I like that SQL Mode in Emacs comes with an interactive mode that I could execute a query in a buffer to a client buffer similar to how I could execute R code using ESS. However, I don’t think SQL mode is that great at formatting SQL code (eg, indenting). I guess I could live with manual indenting and selecting in multiple lines (preceded by a comma).
I typically write code in lower cases, but I think the SQL convention is to use upper cases for keywords like SELECT
, FROM
, WHERE
, etc. This can be done using Abbrev Mode in Emacs. Add the following to your init file:
;; stop asking whether to save newly added abbrev when quitting emacs (setq save-abbrevs nil) ;; turn on abbrev mode globally (setq-default abbrev-mode t)
Now, open a SQL file (/tmp/test.sql
). Type SELECT
, then C-x a l
and type select
. This saves the abbreviation for the current major mode (SQL mode). Now, when you type select
then <space>
, the keyword will be capitalized. Continue doing the same for other keywords. Now, use the write-abbrev-file
command to save the abbreviations to ~/.emacs.d/abbrev_defs
so it can be saved and usable in future Emacs sessions.
To define many keywords all at once, edit the abbrev_defs
directly. For example, I used this list of SQL keywords and relied on Emacs macros to add them to my abbrev_defs
file. My abbreviation table for SQL mode is as follows:
(define-abbrev-table 'sql-mode-abbrev-table (mapcar #'(lambda (v) (list v (upcase v) nil 1)) '("absolute" "action" "add" "after" "all" "allocate" "alter" "and" "any" "are" "array" "as" "asc" "asensitive" "assertion" "asymmetric" "at" "atomic" "authorization" "avg" "before" "begin" "between" "bigint" "binary" "bit" "bitlength" "blob" "boolean" "both" "breadth" "by" "call" "called" "cascade" "cascaded" "case" "cast" "catalog" "char" "char_length" "character" "character_length" "check" "clob" "close" "coalesce" "collate" "collation" "column" "commit" "condition" "connect" "connection" "constraint" "constraints" "constructor" "contains" "continue" "convert" "corresponding" "count" "create" "cross" "cube" "current" "current_date" "current_default_transform_group" "current_path" "current_role" "current_time" "current_timestamp" "current_transform_group_for_type" "current_user" "cursor" "cycle" "data" "date" "day" "deallocate" "dec" "decimal" "declare" "default" "deferrable" "deferred" "delete" "depth" "deref" "desc" "describe" "descriptor" "deterministic" "diagnostics" "disconnect" "distinct" "do" "domain" "double" "drop" "dynamic" "each" "element" "else" "elseif" "end" "equals" "escape" "except" "exception" "exec" "execute" "exists" "exit" "external" "extract" "false" "fetch" "filter" "first" "float" "for" "foreign" "found" "free" "from" "full" "function" "general" "get" "global" "go" "goto" "grant" "group" "grouping" "handler" "having" "hold" "hour" "identity" "if" "immediate" "in" "indicator" "initially" "inner" "inout" "input" "insensitive" "insert" "int" "integer" "intersect" "interval" "into" "is" "isolation" "iterate" "join" "key" "language" "large" "last" "lateral" "leading" "leave" "left" "level" "like" "local" "localtime" "localtimestamp" "locator" "loop" "lower" "map" "match" "map" "member" "merge" "method" "min" "minute" "modifies" "module" "month" "multiset" "names" "national" "natural" "nchar" "nclob" "new" "next" "no" "none" "not" "null" "nullif" "numeric" "object" "octet_length" "of" "old" "on" "only" "open" "option" "or" "order" "ordinality" "out" "outer" "output" "over" "overlaps" "pad" "parameter" "partial" "partition" "path" "position" "precision" "prepare" "preserve" "primary" "prior" "privileges" "procedure" "public" "range" "read" "reads" "real" "recursive" "ref" "references" "referencing" "relative" "release" "repeat" "resignal" "restrict" "result" "return" "returns" "revoke" "right" "role" "rollback" "rollup" "routine" "row" "rows" "savepoint" "schema" "scope" "scroll" "search" "second" "section" "select" "sensitive" "session" "session_user" "set" "sets" "signal" "similar" "size" "smallint" "some" "space" "specific" "specifictype" "sql" "sqlcode" "sqlerror" "sqlexception" "sqlstate" "sqlwarning" "start" "state" "static" "submultiset" "substring" "sum" "symmetric" "system" "system_user" "table" "tablesample" "temporary" "then" "time" "timestamp" "timezone_hour" "timezone_minute" "to" "trailing" "transaction" "translate" "translation" "treat" "trigger" "trim" "true" "under" "undo" "union" "unique" "unknown" "unnest" "until" "update" "upper" "usage" "user" "using" "value" "values" "varchar" "varying" "view" "when" "whenever" "where" "while" "window" "with" "within" "without" "work" "write" "year" "zone") ))
There is a lot of redundancy in that code. It would make much more sense to write it as:
(define-abbrev-table ‘sql-mode-abbrev-table (mapcar #'(lambda (v) (list v (upcase v) nil 1)) ‘(“absolute” “action” “add” “after” “etc…”)))
As you can see, I don’t know lisp well :). Thanks for the tip.
How to switch off the uppercasing inside comments?
This page (http://www.emacswiki.org/emacs/AbbrevMode) talks about how to disable it in comments. Let me know if you figure out how to do this easily. Thanks.
Hey, I know this is an old post but you might be interested in this minor mode: https://github.com/Trevoke/sqlup-mode.el
It does automatic upcasing of SQL keywords like the abbrev mode method you describe, but it automatically avoids affecting comments and doesn’t doesn’t upcase keywords within words (i.e. no user_NAME).