{"id":18077599,"url":"https://github.com/fukamachi/sxql","last_synced_at":"2025-04-05T20:17:09.229Z","repository":{"id":48035113,"uuid":"13746770","full_name":"fukamachi/sxql","owner":"fukamachi","description":"An SQL generator for Common Lisp.","archived":false,"fork":false,"pushed_at":"2024-10-23T01:32:07.000Z","size":325,"stargazers_count":369,"open_issues_count":24,"forks_count":32,"subscribers_count":20,"default_branch":"master","last_synced_at":"2025-02-18T21:00:41.752Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Common Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fukamachi.png","metadata":{"files":{"readme":"README.markdown","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2013-10-21T15:39:52.000Z","updated_at":"2025-02-17T07:31:14.000Z","dependencies_parsed_at":"2024-07-09T19:29:51.694Z","dependency_job_id":null,"html_url":"https://github.com/fukamachi/sxql","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fukamachi%2Fsxql","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fukamachi%2Fsxql/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fukamachi%2Fsxql/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fukamachi%2Fsxql/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fukamachi","download_url":"https://codeload.github.com/fukamachi/sxql/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247393569,"owners_count":20931813,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-31T11:46:06.701Z","updated_at":"2025-04-05T20:17:09.197Z","avatar_url":"https://github.com/fukamachi.png","language":"Common Lisp","readme":"# SxQL - An SQL generator.\n\n[![Build Status](https://travis-ci.org/fukamachi/sxql.svg?branch=master)](https://travis-ci.org/fukamachi/sxql)\n\n## Usage\n\n```common-lisp\n(select (:id :name :sex)\n  (from (:as :person :p))\n  (where (:and (:\u003e= :age 18)\n               (:\u003c :age 65)))\n  (order-by (:desc :age)))\n;=\u003e #\u003cSXQL-STATEMENT: SELECT id, name, sex FROM person AS p WHERE ((age \u003e= 18) AND (age \u003c 65)) ORDER BY age DESC\u003e\n\n(yield *)\n\n;=\u003e \"SELECT id, name, sex FROM person AS p WHERE ((age \u003e= ?) AND (age \u003c ?)) ORDER BY age DESC\"\n;   (18 65)\n\n(sql-compile **)\n;=\u003e #\u003cSXQL-COMPILED: SELECT id, name, sex FROM person AS p WHERE ((age \u003e= ?) AND (age \u003c ?)) ORDER BY age DESC [18, 65]\u003e\n\n(union-queries * (select (:id :name :sex) (from '(:as animal a))))\n;=\u003e #\u003cSXQL-OP: (SELECT id, name, sex FROM (person AS p) WHERE ((age \u003e= ?) AND (age \u003c ?)) ORDER BY age DESC) UNION (SELECT id, name, sex FROM (animal AS a))\u003e\n\n(yield *)\n;=\u003e \"(SELECT id, name, sex FROM (person AS p) WHERE ((age \u003e= ?) AND (age \u003c ?)) ORDER BY age DESC) UNION (SELECT id, name, sex FROM (animal AS a))\"\n;   (18 65)\n```\n\n## SQL Statements\n\n### select (field \u0026body clauses)\n\nCreates a SELECT query. It takes a field (or a list of fields) and SQL Clauses.\n\n```common-lisp\n(select ((:+ 1 1)))\n;=\u003e #\u003cSXQL-STATEMENT: SELECT (1 + 1)\u003e\n\n(select :name\n  (from :person)\n  (where (:\u003e :age 20)))\n;=\u003e #\u003cSXQL-STATEMENT: SELECT name FROM person WHERE (age \u003e 20)\u003e\n\n(select (:id :name)\n  (from (:as :person :p))\n  (left-join :person_config :on (:= :person.config_id :person_config.id))\n  (where (:and (:\u003e :age 20)\n               (:\u003c= :age 65)))\n  (order-by :age)\n  (limit 5))\n;=\u003e #\u003cSXQL-STATEMENT: SELECT id, name FROM (person AS p) LEFT JOIN person_config ON (person.config_id = person_config.id) WHERE ((age \u003e 20) AND (age \u003c= 65)) ORDER BY age LIMIT 5\u003e\n\n(select (:sex (:count :*)) (from :person) (group-by :sex))\n;=\u003e #\u003cSXQL-STATEMENT: SELECT sex, COUNT(*) FROM person GROUP BY sex\u003e\n\n(select (:sex (:as (:count :*) :num)) \n  (from :person)\n  (group-by :sex)\n  (order-by (:desc :num)))\n;=\u003e #\u003cSXQL-STATEMENT: SELECT sex, COUNT(*) AS num FROM person GROUP BY sex ORDER BY num DESC\u003e\n```\n\n### insert-into (table \u0026body clauses)\n\n```common-lisp\n(insert-into :person\n  (set= :sex \"male\"\n        :age 25\n        :name \"Eitaro Fukamachi\"))\n;=\u003e #\u003cSXQL-STATEMENT: INSERT INTO person SET sex = 'male', age = 25, name = 'Eitaro Fukamachi'\u003e\n\n(insert-into :person\n  (:sex :age :name)\n  (list \"male\" 25 \"Eitaro Fukamachi\"))\n;=\u003e #\u003cSXQL-STATEMENT: INSERT INTO person SET sex = 'male', age = 25, name = 'Eitaro Fukamachi'\u003e\n\n(insert-into :person\n  (:sex :age :name)\n  (list (list \"male\" 25 \"Eitaro Fukamachi\")\n        (list \"female\" 16 \"Miku Hatsune\")))\n;=\u003e #\u003cSXQL-STATEMENT: INSERT INTO person (sex, age, name) VALUES ('male', 25, 'Eitaro Fukamachi'), ('female', 16, 'Miku Hatsune')\u003e\n\n(insert-into :users\n  (set= :name \"Jack\"\n        :jinbei-size \"small\")\n  (returning :id))\n;=\u003e #\u003cSXQL-STATEMENT: INSERT INTO `users` (`name`, `jinbei-size`) VALUES ('Jack', 'small') RETURNING `id`\u003e\n\n(insert-into :person\n  (:id :name)\n  (select (:id :name)\n    (from :person_tmp)))\n;=\u003e #\u003cSXQL-STATEMENT: INSERT INTO person (id, name) SELECT id, name FROM person_tmp\u003e\n```\n\n### update (table \u0026body clauses)\n\n```common-lisp\n(update :person\n  (set= :age 26)\n  (where (:like :name \"Eitaro %\")))\n;=\u003e #\u003cSXQL-STATEMENT: UPDATE person SET age = 26 WHERE (name LIKE 'Eitaro %')\u003e\n```\n\n### delete-from (table \u0026body clauses)\n\n```common-lisp\n(delete-from :person\n  (where (:= :name \"Eitaro Fukamachi\")))\n;=\u003e #\u003cSXQL-STATEMENT: DELETE FROM person WHERE (name = 'Eitaro Fukamachi')\u003e\n```\n\n### union-queies (\u0026rest statements)\n\n```common-lisp\n(union-queries\n (select (:name :birthday) (from :fulltime))\n (select (:name :birthday) (from :parttime)))\n;=\u003e #\u003cSXQL-OP: (SELECT name, birthday FROM fulltime) UNION (SELECT name, birthday FROM parttime)\u003e\n```\n\n### union-all-queries (\u0026rest statements)\n\n```common-lisp\n(union-all-queries\n (select (:name :birthday) (from :fulltime))\n (select (:name :birthday) (from :parttime)))\n;=\u003e #\u003cSXQL-OP: (SELECT name, birthday FROM fulltime) UNION ALL (SELECT name, birthday FROM parttime)\u003e\n```\n\n### create-table (table column-definitions \u0026body options)\n\n```common-lisp\n(create-table :enemy\n    ((name :type 'string\n           :primary-key t)\n     (age :type 'integer\n          :not-null t)\n     (address :type 'text\n              :not-null nil)\n     (fatal_weakness :type 'text\n                     :not-null t\n                     :default \"None\")\n     (identifying_color :type '(:char 20)\n                        :unique t)))\n;=\u003e #\u003cSXQL-STATEMENT: CREATE TABLE enemy (name STRING PRIMARY KEY, age INTEGER NOT NULL, address TEXT, fatal_weakness TEXT NOT NULL DEFAULT 'None', identifying_color CHAR(20) UNIQUE)\u003e\n\n(yield *)\n;=\u003e \"CREATE TABLE enemy (name STRING PRIMARY KEY, age INTEGER NOT NULL, address TEXT, fatal_weakness TEXT NOT NULL DEFAULT ?, identifying_color CHAR(20) UNIQUE)\"\n;   (\"None\")\n\n(create-table (:enemy :if-not-exists t)\n    ((name :type 'string\n           :primary-key t)\n     (age :type 'integer\n          :not-null t)\n     (address :type 'text\n              :not-null nil)\n     (fatal_weakness :type 'text\n                     :not-null t\n                     :default \"None\")\n     (identifying_color :type '(:char 20)\n                        :unique t)))\n;=\u003e #\u003cSXQL-STATEMENT: CREATE TABLE IF NOT EXISTS enemy (name STRING PRIMARY KEY, age INTEGER NOT NULL, address TEXT, fatal_weakness TEXT NOT NULL DEFAULT 'None', identifying_color CHAR(20) UNIQUE)\u003e\n```\n\n### drop-table (table \u0026key if-exists)\n\n```common-lisp\n(drop-table :enemy)\n;=\u003e #\u003cSXQL-STATEMENT: DROP TABLE enemy\u003e\n\n(drop-table :enemy :if-exists t)\n;=\u003e #\u003cSXQL-STATEMENT: DROP TABLE IF EXISTS enemy\u003e\n```\n\n### alter-table (table \u0026body clauses)\n\n```common-lisp\n(alter-table :tweet\n  (add-column :id :type 'bigint :primary-key t :auto-increment t :first t)\n  (add-column :updated_at :type 'timestamp))\n;=\u003e #\u003cSXQL-STATEMENT: ALTER TABLE tweet ADD COLUMN id BIGINT AUTO_INCREMENT PRIMARY KEY FIRST, ADD COLUMN updated_at TIMESTAMP\u003e\n```\n\n### create-index (index-name \u0026key unique using on)\n\n```common-lisp\n(create-index \"index_name\"\n              :unique t\n              :using :btee\n              :on '(:table :column1 :column2))\n;=\u003e #\u003cSXQL-STATEMENT: CREATE UNIQUE INDEX index_name USING BTEE ON table (column1, column2)\u003e\n```\n\n### drop-index (index-name \u0026key if-exists on)\n\n```common-lisp\n(drop-index \"index_name\" :if-exists t :on :person)\n;=\u003e #\u003cSXQL-STATEMENT: DROP INDEX IF EXISTS index_name ON person\u003e\n```\n\n## SQL Clauses\n\n### fields\n\n```common-lisp\n(fields :id)\n;=\u003e #\u003cSXQL-CLAUSE: id\u003e\n\n(fields (:count :id))\n;=\u003e #\u003cSXQL-CLAUSE: COUNT(id)\u003e\n\n(fields :id (:sum :amount))\n;=\u003e #\u003cSXQL-CLAUSE: id, SUM(amount)\u003e\n```\n\n### from\n\n```common-lisp\n(from :person)\n;=\u003e #\u003cSXQL-CLAUSE: FROM person\u003e\n\n(from :person :person_config)\n;=\u003e #\u003cSXQL-CLAUSE: FROM person, person_config\u003e\n\n(from (select :* (from :person) (where (:= :is_active 1))))\n;=\u003e #\u003cSXQL-CLAUSE: FROM (SELECT * FROM person WHERE (is_active = 1))\u003e\n```\n\n### where\n\n```common-lisp\n(where (:and (:\u003e :age 20) (:\u003c= :age 65)))\n;=\u003e #\u003cSXQL-CLAUSE: WHERE ((age \u003e 20) AND (age \u003c= 65))\u003e\n\n(yield *)\n;=\u003e \"WHERE ((age \u003e ?) AND (age \u003c= ?))\"\n;   (20 65)\n```\n\n### order-by\n\n```common-lisp\n(order-by :age)\n;=\u003e #\u003cSXQL-CLAUSE: ORDER BY age\u003e\n\n(order-by :age (:desc :id))\n;=\u003e #\u003cSXQL-CLAUSE: ORDER BY age, id DESC\u003e\n;   NIL\n```\n\n### group-by\n\n```common-lisp\n(group-by :sex)\n;=\u003e #\u003cSXQL-CLAUSE: GROUP BY sex\u003e\n```\n\n### having\n\n```common-lisp\n(having (:\u003e= (:sum :hoge) 88))\n;=\u003e #\u003cSXQL-CLAUSE: HAVING (SUM(`hoge`) \u003e= 88)\u003e\n```\n\n### returning\n\n```common-lisp\n(returning :id)\n;=\u003e #\u003cSXQL-CLAUSE: RETURNING `id`\u003e\n```\n\n### limit\n\n```common-lisp\n(limit 10)\n;=\u003e #\u003cSXQL-CLAUSE: LIMIT 10\u003e\n\n(limit 0 10)\n;=\u003e #\u003cSXQL-CLAUSE: LIMIT 0, 10\u003e\n\n(yield *)\n;=\u003e \"LIMIT 0, 10\"\n;   NIL\n```\n\n### offset\n\n```common-lisp\n(offset 0)\n;=\u003e #\u003cSXQL-CLAUSE: OFFSET 0\u003e\n\n(yield *)\n;=\u003e \"OFFSET 0\"\n;   NIL\n```\n\n### inner-join, left-join, right-join, full-join\n\n```common-lisp\n(inner-join :person_config :on (:= :person.config_id :person_config.id))\n;=\u003e #\u003cSXQL-CLAUSE: INNER JOIN person_config ON (person.config_id = person_config.id)\u003e\n\n(left-join :person_config :on (:= :person.config_id :person_config.id))\n;=\u003e #\u003cSXQL-CLAUSE: LEFT JOIN person_config ON (person.config_id = person_config.id)\u003e\n\n(left-join :person_config :using :config_id)\n;=\u003e #\u003cSXQL-CLAUSE: LEFT JOIN person_config USING config_id\u003e\n```\n\n### primary-key\n\n```common-lisp\n(primary-key :id)\n;=\u003e #\u003cSXQL-CLAUSE: PRIMARY KEY (id)\u003e\n\n(primary-key '(:id))\n;=\u003e #\u003cSXQL-CLAUSE: PRIMARY KEY (id)\u003e\n\n(primary-key \"id_index\" '(:id))\n;=\u003e #\u003cSXQL-CLAUSE: PRIMARY KEY 'id_index' (id)\u003e\n```\n\n### unique-key\n\n```common-lisp\n(unique-key '(:name :country))\n;=\u003e #\u003cSXQL-CLAUSE: UNIQUE (name, country)\u003e\n\n(unique-key \"name_and_country_index\" '(:name :country))\n;=\u003e #\u003cSXQL-CLAUSE: UNIQUE 'name_and_country_index' (name, country)\u003e\n```\n\n### index-key\n\n```common-lisp\n(index-key (:name :country))\n;=\u003e #\u003cSXQL-CLAUSE: KEY (name, country)\u003e\n\n(index-key \"name_and_country_index\" '(:name :country))\n;=\u003e #\u003cSXQL-CLAUSE: KEY 'name_and_country_index' (name, country)\u003e\n```\n\n### foreign-key\n\n```common-lisp\n(foreign-key '(:project_id) :references '(:project :id))\n;=\u003e #\u003cSXQL-CLAUSE: FOREIGN KEY (project_id) REFERENCES project (id)\u003e\n\n(foreign-key '(:user_id) :references '(:user :id) :on-delete :cascade)\n;=\u003e #\u003cSXQL-CLAUSE: FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE\u003e\n```\n\n### add-column\n\n```common-lisp\n(add-column :updated_at :type 'integer :default 0 :not-null t :after :created_at)\n;=\u003e #\u003cSXQL-CLAUSE: ADD COLUMN updated_at INTEGER NOT NULL DEFAULT 0 AFTER created_at\u003e\n```\n\n### modify-column\n\n```common-lisp\n(modify-column :updated_at :type 'datetime :not-null t)\n;=\u003e #\u003cSXQL-CLAUSE: MODIFY COLUMN updated_at DATETIME NOT NULL\u003e\n```\n\n### alter-column\n\n```common-lisp\n(alter-column :user :type '(:varchar 64))\n;=\u003e #\u003cSXQL-CLAUSE: ALTER COLUMN user TYPE VARCHAR(64)\u003e\n\n(alter-column :id :set-default 1)\n;=\u003e #\u003cSXQL-CLAUSE: ALTER COLUMN id SET DEFAULT 1\u003e\n\n(alter-column :id :drop-default t)\n;=\u003e #\u003cSXQL-CLAUSE: ALTER COLUMN id DROP DEFAULT\u003e\n\n(alter-column :profile :not-null t)\n;=\u003e #\u003cSXQL-CLAUSE: ALTER COLUMN profile SET NOT NULL\u003e\n```\n\n### change-column\n\n```common-lisp\n(change-column :updated_at :updated_on)\n;=\u003e #\u003cSXQL-CLAUSE: CHANGE COLUMN updated_at updated_on\u003e\n```\n\n### drop-column\n\n```common-lisp\n(drop-column :updated_on)\n;=\u003e #\u003cSXQL-CLAUSE: DROP COLUMN updated_on\u003e\n```\n\n### add-primary-key\n\n```common-lisp\n(add-primary-key :id :name)\n;=\u003e #\u003cSXQL-CLAUSE: ADD PRIMARY KEY (id, name)\u003e\n```\n\n### drop-primary-key\n\n```common-lisp\n(drop-primary-key)\n;=\u003e #\u003cSXQL-CLAUSE: DROP PRIMARY KEY\u003e\n```\n\n### rename-to\n\n```common-lisp\n(rename-to :users)\n;=\u003e #\u003cSXQL-CLAUSE: RENAME TO `users`\u003e\n\n(alter-table :user\n  (rename-to :users))\n;=\u003e #\u003cSXQL-STATEMENT: ALTER TABLE `user` RENAME TO `users`\u003e\n```\n\n### on-duplicate-key-update\n\nSupport MySQL's `INSERT ... ON DUPLICATE KEY UPDATE` syntax.\n\n```common-lisp\n(on-duplicate-key-update :age (:+ :age 1))\n;=\u003e #\u003cSXQL-CLAUSE: ON DUPLICATE KEY UPDATE `age` = (`age` + 1)\u003e\n\n(insert-into :person\n  (set= :sex \"male\"\n        :age 25\n        :name \"Eitaro Fukamachi\")\n  (on-duplicate-key-update :age (:+ :age 1)))\n;=\u003e #\u003cSXQL-STATEMENT: INSERT INTO `person` (`sex`, `age`, `name`) VALUES ('male', 25, 'Eitaro Fukamachi') ON DUPLICATE KEY UPDATE `age` = (`age` + 1)\u003e\n```\n\n### on-coflict-do-nothing\n\nSupport PostgreSQL's `INSERT ... ON CONFLICT DO NOTHING` syntax.\n\n```common-lisp\n(on-conflict-do-nothing)\n;=\u003e #\u003cSXQL-CLAUSE: ON CONFLICT DO NOTHING\u003e\n\n(on-conflict-do-nothing :index_name)\n;=\u003e #\u003cSXQL-CLAUSE: ON CONFLICT ON CONSTRAINT index_name DO NOTHING\u003e\n\n(on-conflict-do-nothing '(:column1 :column2 :column3))\n;=\u003e #\u003cSXQL-CLAUSE: ON CONFLICT (column1, column2, column3) DO NOTHING\u003e\n```\n\n### on-coflict-do-update\n\nSupport PostgreSQL's `INSERT ... ON CONFLICT ... DO UPDATE` syntax.\n\n```common-lisp\n(on-conflict-do-update :index_name (set= :x 1 :y 2))\n;=\u003e #\u003cSXQL-CLAUSE: ON CONFLICT ON CONSTRAINT index_name DO UPDATE SET x = 1, y = 2\u003e\n\n(on-conflict-do-update '(:column1 :column2 :column3) (set= :x 1 :y 2))\n;=\u003e #\u003cSXQL-CLAUSE: ON CONFLICT (column1, column2, column3) DO UPDATE SET x = 1, y = 2\u003e\n\n(insert-into :person\n  (set= :sex \"male\"\n        :age 25\n        :name \"Eitaro Fukamachi\")\n  (on-conflict-do-update '(:name)\n                         (set= :age (:+ :age 1))\n                         (where (:\u003c :age 99))))\n;=\u003e #\u003cSXQL-STATEMENT: INSERT INTO person (sex, age, name) VALUES ('male', 25, 'Eitaro Fukamachi') ON CONFLICT (name) DO UPDATE SET age = (age + 1) WHERE (age \u003c 99)\u003e\n```\n\n## SQL Operators\n\n* :not\n* :is-null, :not-null\n* :asc, :desc\n* :distinct\n* :=, :!=\n* :\u003c, :\u003e, :\u003c= :\u003e=\n* :a\u003c, :a\u003e\n* :as\n* :in, :not-in\n* :like\n* :and, :or\n* :+, :-, :* :/ :%\n* :raw\n* :is-distinct-from, :is-not-distinct-from (Postgres)\n\n## Set a quote character\n\n`*quote-character*` is the character that a table or column name will be quoted with. The default value is NIL (not quote).\n\n```common-lisp\n(yield (select :* (from 'table)))\n;=\u003e \"SELECT * FROM table\"\n;   NIL\n\n;; for MySQL\n(let ((*quote-character* #\\`))\n  (yield (select :* (from 'table))))\n;=\u003e \"SELECT * FROM `table`\"\n;   NIL\n\n;; for PostgreSQL\n(let ((*quote-character* #\\\"))\n  (yield (select :* (from 'table))))\n;=\u003e \"SELECT * FROM \"table\"\"\n;   NIL\n```\n\n## Author\n\n* Eitaro Fukamachi (e.arrows@gmail.com)\n\n## Copyright\n\nCopyright (c) 2013-2014 Eitaro Fukamachi (e.arrows@gmail.com)\n\n# License\n\nLicensed under the BSD 3-Clause License.\n","funding_links":[],"categories":["Expert Systems"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffukamachi%2Fsxql","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffukamachi%2Fsxql","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffukamachi%2Fsxql/lists"}