{"id":15705005,"url":"https://github.com/adamcooke/sqb","last_synced_at":"2025-05-12T14:55:58.971Z","repository":{"id":56896721,"uuid":"122968204","full_name":"adamcooke/sqb","owner":"adamcooke","description":"👷‍♀️ A very simple but effective SQL query builder","archived":false,"fork":false,"pushed_at":"2020-02-24T12:56:39.000Z","size":113,"stargazers_count":6,"open_issues_count":1,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-16T03:08:45.030Z","etag":null,"topics":["query-builder","ruby","sql"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/adamcooke.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"MIT-LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-02-26T12:40:47.000Z","updated_at":"2024-05-11T09:42:56.000Z","dependencies_parsed_at":"2022-08-21T01:50:40.646Z","dependency_job_id":null,"html_url":"https://github.com/adamcooke/sqb","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/adamcooke%2Fsqb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adamcooke%2Fsqb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adamcooke%2Fsqb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adamcooke%2Fsqb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/adamcooke","download_url":"https://codeload.github.com/adamcooke/sqb/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253759808,"owners_count":21959825,"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":["query-builder","ruby","sql"],"created_at":"2024-10-03T20:14:33.429Z","updated_at":"2025-05-12T14:55:58.624Z","avatar_url":"https://github.com/adamcooke.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SQB (SQL Query Builder)\n\n[![Build Status](https://travis-ci.org/adamcooke/sqb.svg?branch=master)](https://travis-ci.org/adamcooke/sqb) [![Gem Version](https://badge.fury.io/rb/sqb.svg)](https://badge.fury.io/rb/sqb)\n\nThis is a gem that allows you to construct SQL queries from a simple Ruby DSL. There are lots of gems like this around but I haven't yet found one that I really enjoy using that supports things like ORs or various different operators nicely. This isn't a perfect solution but is very handy for quickly generating queries.\n\n## Installation\n\n```ruby\ngem 'sqb'\n```\n\n## Selecting data\n\nTo get started just create yourself a `SQB::Select` object and provide the base table name.\n\n```ruby\nquery = SQB::Select.new(:posts)\n```\n\nWhen you've done all the operations on the query that you wish to do (see below) you can extract the finished SQL query and prepared arguments for passing to a database client.\n\n```ruby\n# Return the SQL query itself\nquery.to_sql\n\n# Return any arguments needed for the query\nquery.prepared_arguments\n\n# For example with the MySQL2 client you might do this...\nstatement = mysql.prepare(query.to_sql)\nstatement.execute(*query.prepared_arguments)\nstatement.close\n```\n\n### Filtering\n\nThe most common thing you'll want to do is filter the data returned which means using `WHERE`. You can do any of the following to filter the data returned.\n\n```ruby\n# The most basic equality operators\nquery.where(:title =\u003e \"Hello world!\")\nquery.where(:title =\u003e {:equal =\u003e \"Hello world!\"})\nquery.where(:title =\u003e {:not_equal =\u003e \"Hello world!\"})\n\n# Greater than or less than\nquery.where(:comments_count =\u003e {:greater_than =\u003e 100})\nquery.where(:comments_count =\u003e {:less_than =\u003e 1})\nquery.where(:comments_count =\u003e {:greater_than_or_equal_to =\u003e 100})\nquery.where(:comments_count =\u003e {:less_than_or_equal_to =\u003e 1})\n\n# Like/Not like\nquery.where(:body =\u003e {:like =\u003e \"Hello world!\"})\nquery.where(:body =\u003e {:not_like =\u003e \"Hello world!\"})\n\n# In/not in an array\nquery.where(:author_id =\u003e [1,2,3,4])\nquery.where(:author_id =\u003e {:in =\u003e [1,2,3,4]})\nquery.where(:author_id =\u003e {:not_in =\u003e [1,2,3,4]})\n\n# Nulls\nquery.where(:markdown =\u003e nil)\nquery.where(:markdown =\u003e {:not_equal =\u003e nil})\n\n# Sub-queries in where queries\nother_query = SQB::Select.new(:comments)\nother_query.where(post_id: SQB.column(:posts =\u003e :id))\nother_query.select(:count, :function =\u003e 'COUNT')\nquery.where(other_query =\u003e {:greater_than =\u003e 10})\n```\n\nBy default all filtering operations will be joined with ANDs. You can use OR if needed.\n\n```ruby\nquery.or do\n  query.where(:author =\u003e \"Sarah Smith\")\n  query.where(:author =\u003e \"John Jones\")\nend\n```\n\n### Selecting columns\n\nBy default, all the columns on your main table will be selected with a `*` however you may not wish to get them all or you may wish to use functions to get other data.\n\n```ruby\nquery.column(:title)\nquery.column(:id, :function =\u003e 'COUNT', :as =\u003e 'count')\n\n# You can do more complex function operations\nquery.column(:amount, :function =\u003e SQB.safe('IFNULL(SUM($$), 0.0))', :as =\u003e 'total')\n\n# Subqueries can be used in columns too\nother_query = SQB::Select.new(:comments)\nother_query.where(post_id: SQB.column(:posts =\u003e :id))\nother_query.select(:count, :function =\u003e 'COUNT')\nquery.column(other_query, :as =\u003e :comments_count)\n\n# If you have already added columns and wish to replace them all with a new one\nquery.column!(:other_column)\n\n# You can choose to select all columns too\nquery.column(SQB::STAR)\n```\n\n### Specifying orders\n\nYou can add fields that you wish to order by as either ascending or decending.\n\n```ruby\nquery.order(:posted_at)\nquery.order(:posted_at, :asc)\nquery.order(:posted_at, :desc)\n\n# If you have already added some orders and wish to replace them with a new field\nquery.order!(:last_comment_posted_at, :desc)\n\n# To remove all ordering\nquery.no_order!\n```\n\n### Limiting the returned records\n\nYou can specify limits and offsets easily\n\n```ruby\nquery.limit(30)\nquery.offset(120)\n```\n\n### Joining with other tables\n\nTo join with other tables you can do so easily with the `join` methods.\n\n```ruby\nquery.join(:comments, :post_id)\nquery.join(:comments, :post_id, :name =\u003e :comments)\n```\n\nBy default, this will join with the table (by default `INNER JOIN`) but won't return any data. You'll likely want to add some conditions and/or some columns to return.\n\n```ruby\nquery.join(:comments, :post_id, :columns =\u003e [:content])\n\n# You can specify the type as either :inner, :left or :right\nquery.join(:users, [:id, :author_id], :name =\u003e :author, :type =\u003e :left)\n\n# This will join users where the user `id` matches the `author_id` in the base table\nquery.join(:users, [:id, :author_id], :name =\u003e :author)\n\n# This will join to a different join rather than the base table\nquery.join(:users, [:id, {user_joins: :user_id}])\n\n# You can add additional join conditions like so. The additional conditions will be\n# added to the `ON` part of the join along with the key join.\nquery.join(:comments, :post_id, :conditions =\u003e {:spam =\u003e true})\n\n# You can also use the existing where and column methods to add joins to these tables\nquery.column({:comments =\u003e :spam})\nquery.where({:comments =\u003e :spam} =\u003e {:not_equal =\u003e true})\n\n# Unless a name is provided with the join, you'll be able to access the join as\n# [table_name]_0 (where 0 is an index for the number of joins for that table\n# starting with 0).\n```\n\n### Grouping\n\nYou can, of course, group your data too\n\n```ruby\nquery.group_by(:author_id)\nquery.column(:author_id)\nquery.column(:count, :function =\u003e 'COUNT', :as =\u003e 'count')\n```\n\n### Distinct\n\nTo only return distinct rows for your dataset:\n\n```ruby\nquery.distinct\n```\n\n## Inserting data\n\nThe INSERT query is one of the less friendly ones but SQB makes light work of it.\n\n```ruby\nquery = SQB::Insert.new(:posts)\nquery.value(:title =\u003e 'Hello world!', :author_id =\u003e 1)\n```\n\n## Updating data\n\nSQB supports crafting UPDATE queries too. You can use the same options for `where` as when selecting data (see above). The `set` method accepts a hash of all values that you wish to update (it can be called multiple times to add additional values).\n\n```ruby\nquery = SQB::Update.new(:posts)\nquery.set(:title =\u003e 'Hello world!')\nquery.where(:id =\u003e 10)\n```\n\n## Deleting data\n\nSQB can write you some lovely DELETE queries too. You can use `where`, `limit` and `order` to limit which records are deleted.\n\n```ruby\nquery = SQB::Delete.new(:posts)\nquery.where(:id =\u003e 10)\nquery.limit(10)\nquery.order(:id =\u003e :desc)\n```\n\n## Other options\n\n### Specifying a database\n\nYou can specify the name of a database that you wish to query. By default, no database name will be included in the query.\n\n```ruby\nquery = SQB::Query.new(:posts, :database_name =\u003e :my_blog)\n```\n\n### Inserting arbitary strings\n\nThere are occasions where you need to break free from constraints. You can do that by passing strings through the `SQB.safe(string)` method. This will avoid any escaping or clever magic by SQB and the string provided will simply be inserted in the query as appropriate.\n\n```ruby\nquery.column(SQB.safe('SUM(CEILING(duration / 60))'))\n# or\nquery.where(SQB.safe('IF(LENGTH(excerpt) \u003e 0, excerpt, description)') =\u003e {:equal =\u003e \"Llamas!\"})\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadamcooke%2Fsqb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadamcooke%2Fsqb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadamcooke%2Fsqb/lists"}