Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Indenting SQL in another major mode in Emacs

Oftentimes I'm writing some script to do some stuff, often involving SQL, in a different major mode. Maybe it looks like this:

sql = """
SELECT * FROM table WHERE row_awesomeness > 1000
"""

I'd like to be able to indent the SQL propertly, so it looks something like:

sql = """
SELECT *
  FROM table
 WHERE row_awesomeness > 1000
"""

I'm not picky about the SQL indentation algorithm used, but I can't get anything to work at all. I'm not a huge fan of sql-indent.el, but I can't even get that to work using it in a new buffer (the function sql-indent-buffer doesn't change anything from my first description, and I definitely want the SELECT, FROM and WHERE clauses to be on separate lines which I think is pretty standard).

Ideally, I would highlight the region that contains the SQL and do something like M-x sql-indent-region RET - no need for something that indents upon a newline.

like image 978
Hut8 Avatar asked Nov 02 '22 11:11

Hut8


1 Answers

This is one way of doing it (lightly tested, using the indenting function you mentioned -- I don't work with SQL but you should be able to plug in any function in its place as long as it operates on the whole buffer):

(defun my-sql-indent-region (beg end)
  "Indent the SQL statement in the region."
  (interactive "*r")
  (save-excursion
    (save-restriction
      (narrow-to-region beg end)
      ;; http://www.emacswiki.org/emacs/download/sql-indent.el
      (sql-indent-buffer))))

If I mark the following sql query (from "SELECT" through "f2.PLAYERID"), embedded in an elisp string, and do M-x my-sql-indent-region RET:

(defvar my-sql-query "
SELECT p1.PLAYERID, 
f1.PLAYERNAME, 
  p2.PLAYERID, 
f2.PLAYERNAME 
FROM PLAYER f1, 
                   PLAYER f2, 
    PLAYS p1 
    FULL OUTER JOIN PLAYS p2 
        ON p1.PLAYERID < p2.PLAYERID 
    AND p1.TEAMID = p2.TEAMID 
GROUP BY p1.PLAYERID, 
    f1.PLAYERID, 
   p2.PLAYERID, 
    f2.PLAYERID 
HAVING Count(p1.PLAYERID) = Count(*) 
  AND Count(p2.PLAYERID) = Count(*) 
    AND p1.PLAYERID = f1.PLAYERID 
AND p2.PLAYERID = f2.PLAYERID;
")

I end up with:

(defvar my-sql-query "
SELECT p1.PLAYERID, 
    f1.PLAYERNAME, 
    p2.PLAYERID, 
    f2.PLAYERNAME 
FROM PLAYER f1, 
    PLAYER f2, 
    PLAYS p1 
    FULL OUTER JOIN PLAYS p2 
    ON p1.PLAYERID < p2.PLAYERID 
    AND p1.TEAMID = p2.TEAMID 
GROUP BY p1.PLAYERID, 
    f1.PLAYERID, 
    p2.PLAYERID, 
    f2.PLAYERID 
HAVING Count(p1.PLAYERID) = Count(*) 
    AND Count(p2.PLAYERID) = Count(*) 
    AND p1.PLAYERID = f1.PLAYERID 
    AND p2.PLAYERID = f2.PLAYERID;
")
like image 72
tankrim Avatar answered Nov 28 '22 14:11

tankrim