sequel 5.83.1 → 5.84.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. checksums.yaml +4 -4
  2. data/lib/sequel/adapters/shared/sqlite.rb +3 -1
  3. data/lib/sequel/database/schema_methods.rb +2 -0
  4. data/lib/sequel/extensions/pg_json_ops.rb +328 -1
  5. data/lib/sequel/sql.rb +8 -5
  6. data/lib/sequel/version.rb +2 -2
  7. metadata +2 -236
  8. data/CHANGELOG +0 -1397
  9. data/README.rdoc +0 -936
  10. data/doc/advanced_associations.rdoc +0 -884
  11. data/doc/association_basics.rdoc +0 -1859
  12. data/doc/bin_sequel.rdoc +0 -146
  13. data/doc/cheat_sheet.rdoc +0 -255
  14. data/doc/code_order.rdoc +0 -104
  15. data/doc/core_extensions.rdoc +0 -405
  16. data/doc/dataset_basics.rdoc +0 -96
  17. data/doc/dataset_filtering.rdoc +0 -222
  18. data/doc/extensions.rdoc +0 -77
  19. data/doc/fork_safety.rdoc +0 -84
  20. data/doc/mass_assignment.rdoc +0 -98
  21. data/doc/migration.rdoc +0 -660
  22. data/doc/model_dataset_method_design.rdoc +0 -129
  23. data/doc/model_hooks.rdoc +0 -254
  24. data/doc/model_plugins.rdoc +0 -270
  25. data/doc/mssql_stored_procedures.rdoc +0 -43
  26. data/doc/object_model.rdoc +0 -563
  27. data/doc/opening_databases.rdoc +0 -439
  28. data/doc/postgresql.rdoc +0 -611
  29. data/doc/prepared_statements.rdoc +0 -144
  30. data/doc/querying.rdoc +0 -1070
  31. data/doc/reflection.rdoc +0 -120
  32. data/doc/release_notes/5.0.0.txt +0 -159
  33. data/doc/release_notes/5.1.0.txt +0 -31
  34. data/doc/release_notes/5.10.0.txt +0 -84
  35. data/doc/release_notes/5.11.0.txt +0 -83
  36. data/doc/release_notes/5.12.0.txt +0 -141
  37. data/doc/release_notes/5.13.0.txt +0 -27
  38. data/doc/release_notes/5.14.0.txt +0 -63
  39. data/doc/release_notes/5.15.0.txt +0 -39
  40. data/doc/release_notes/5.16.0.txt +0 -110
  41. data/doc/release_notes/5.17.0.txt +0 -31
  42. data/doc/release_notes/5.18.0.txt +0 -69
  43. data/doc/release_notes/5.19.0.txt +0 -28
  44. data/doc/release_notes/5.2.0.txt +0 -33
  45. data/doc/release_notes/5.20.0.txt +0 -89
  46. data/doc/release_notes/5.21.0.txt +0 -87
  47. data/doc/release_notes/5.22.0.txt +0 -48
  48. data/doc/release_notes/5.23.0.txt +0 -56
  49. data/doc/release_notes/5.24.0.txt +0 -56
  50. data/doc/release_notes/5.25.0.txt +0 -32
  51. data/doc/release_notes/5.26.0.txt +0 -35
  52. data/doc/release_notes/5.27.0.txt +0 -21
  53. data/doc/release_notes/5.28.0.txt +0 -16
  54. data/doc/release_notes/5.29.0.txt +0 -22
  55. data/doc/release_notes/5.3.0.txt +0 -121
  56. data/doc/release_notes/5.30.0.txt +0 -20
  57. data/doc/release_notes/5.31.0.txt +0 -148
  58. data/doc/release_notes/5.32.0.txt +0 -46
  59. data/doc/release_notes/5.33.0.txt +0 -24
  60. data/doc/release_notes/5.34.0.txt +0 -40
  61. data/doc/release_notes/5.35.0.txt +0 -56
  62. data/doc/release_notes/5.36.0.txt +0 -60
  63. data/doc/release_notes/5.37.0.txt +0 -30
  64. data/doc/release_notes/5.38.0.txt +0 -28
  65. data/doc/release_notes/5.39.0.txt +0 -19
  66. data/doc/release_notes/5.4.0.txt +0 -80
  67. data/doc/release_notes/5.40.0.txt +0 -40
  68. data/doc/release_notes/5.41.0.txt +0 -25
  69. data/doc/release_notes/5.42.0.txt +0 -136
  70. data/doc/release_notes/5.43.0.txt +0 -98
  71. data/doc/release_notes/5.44.0.txt +0 -32
  72. data/doc/release_notes/5.45.0.txt +0 -34
  73. data/doc/release_notes/5.46.0.txt +0 -87
  74. data/doc/release_notes/5.47.0.txt +0 -59
  75. data/doc/release_notes/5.48.0.txt +0 -14
  76. data/doc/release_notes/5.49.0.txt +0 -59
  77. data/doc/release_notes/5.5.0.txt +0 -61
  78. data/doc/release_notes/5.50.0.txt +0 -78
  79. data/doc/release_notes/5.51.0.txt +0 -47
  80. data/doc/release_notes/5.52.0.txt +0 -87
  81. data/doc/release_notes/5.53.0.txt +0 -23
  82. data/doc/release_notes/5.54.0.txt +0 -27
  83. data/doc/release_notes/5.55.0.txt +0 -21
  84. data/doc/release_notes/5.56.0.txt +0 -51
  85. data/doc/release_notes/5.57.0.txt +0 -23
  86. data/doc/release_notes/5.58.0.txt +0 -31
  87. data/doc/release_notes/5.59.0.txt +0 -73
  88. data/doc/release_notes/5.6.0.txt +0 -31
  89. data/doc/release_notes/5.60.0.txt +0 -22
  90. data/doc/release_notes/5.61.0.txt +0 -43
  91. data/doc/release_notes/5.62.0.txt +0 -132
  92. data/doc/release_notes/5.63.0.txt +0 -33
  93. data/doc/release_notes/5.64.0.txt +0 -50
  94. data/doc/release_notes/5.65.0.txt +0 -21
  95. data/doc/release_notes/5.66.0.txt +0 -24
  96. data/doc/release_notes/5.67.0.txt +0 -32
  97. data/doc/release_notes/5.68.0.txt +0 -61
  98. data/doc/release_notes/5.69.0.txt +0 -26
  99. data/doc/release_notes/5.7.0.txt +0 -108
  100. data/doc/release_notes/5.70.0.txt +0 -35
  101. data/doc/release_notes/5.71.0.txt +0 -21
  102. data/doc/release_notes/5.72.0.txt +0 -33
  103. data/doc/release_notes/5.73.0.txt +0 -66
  104. data/doc/release_notes/5.74.0.txt +0 -45
  105. data/doc/release_notes/5.75.0.txt +0 -35
  106. data/doc/release_notes/5.76.0.txt +0 -86
  107. data/doc/release_notes/5.77.0.txt +0 -63
  108. data/doc/release_notes/5.78.0.txt +0 -67
  109. data/doc/release_notes/5.79.0.txt +0 -28
  110. data/doc/release_notes/5.8.0.txt +0 -170
  111. data/doc/release_notes/5.80.0.txt +0 -40
  112. data/doc/release_notes/5.81.0.txt +0 -31
  113. data/doc/release_notes/5.82.0.txt +0 -61
  114. data/doc/release_notes/5.83.0.txt +0 -56
  115. data/doc/release_notes/5.9.0.txt +0 -99
  116. data/doc/schema_modification.rdoc +0 -679
  117. data/doc/security.rdoc +0 -443
  118. data/doc/sharding.rdoc +0 -286
  119. data/doc/sql.rdoc +0 -648
  120. data/doc/testing.rdoc +0 -204
  121. data/doc/thread_safety.rdoc +0 -15
  122. data/doc/transactions.rdoc +0 -250
  123. data/doc/validations.rdoc +0 -558
  124. data/doc/virtual_rows.rdoc +0 -265
data/doc/querying.rdoc DELETED
@@ -1,1070 +0,0 @@
1
- = Querying in Sequel
2
-
3
- This guide is based on http://guides.rubyonrails.org/active_record_querying.html
4
-
5
- == Purpose of this Guide
6
-
7
- Sequel is a flexible and powerful database library
8
- that supports a wide variety of different querying methods. This guide
9
- aims to be a introduction to Sequel's querying support.
10
-
11
- While you can use raw SQL with Sequel, a large part of the
12
- advantage you get from using Sequel is Sequel's ability to abstract
13
- SQL from you and give you a pure-ruby interface. Sequel also ships with
14
- a {core_extensions extension}[rdoc-ref:doc/core_extensions.rdoc],
15
- which adds methods to core ruby types to work with Sequel.
16
-
17
- == Retrieving Objects
18
-
19
- Sequel provides a few separate methods for retrieving objects from the
20
- database. The underlying method is Sequel::Dataset#each, which yields each
21
- row as the Sequel::Database provides it. However, while Dataset#each can and
22
- often is used directly, in many cases there is a more convenient retrieval
23
- method you can use.
24
-
25
- === Sequel::Dataset
26
-
27
- If you are new to Sequel and aren't familiar with Sequel, you should probably
28
- read the {"Dataset Basics" guide}[rdoc-ref:doc/dataset_basics.rdoc],
29
- then come back here.
30
-
31
- === Retrieving a Single Object
32
-
33
- Sequel offers quite a few ways to to retrieve a single object.
34
-
35
- ==== Using a Primary Key [Sequel::Model]
36
-
37
- The <tt>Sequel::Model.[]</tt> is the easiest method to use to find a model instance
38
- by its primary key value:
39
-
40
- # Find artist with primary key (id) 1
41
- artist = Artist[1]
42
- # SELECT * FROM artists WHERE (id = 1)
43
- # => #<Artist @values={:name=>"YJM", :id=>1}>
44
-
45
- If there is no record with the given primary key, nil will be returned. If you want
46
- to raise an exception if no record is found, you can use <tt>Sequel::Model.with_pk!</tt>:
47
-
48
- artist = Artist.with_pk!(1)
49
-
50
- ==== Using +first+
51
-
52
- If you want the first record in the dataset,
53
- <tt>Sequel::Dataset#first</tt> is probably the most obvious method to use:
54
-
55
- artist = Artist.first
56
- # SELECT * FROM artists LIMIT 1
57
- # => #<Artist @values={:name=>"YJM", :id=>1}>
58
-
59
- Any options you pass to +first+ will be used as a filter:
60
-
61
- artist = Artist.first(name: 'YJM')
62
- # SELECT * FROM artists WHERE (name = 'YJM') LIMIT 1
63
- # => #<Artist @values={:name=>"YJM", :id=>1}>
64
-
65
- artist = Artist.first(Sequel.like(:name, 'Y%'))
66
- # SELECT * FROM artists WHERE (name LIKE 'Y%' ESCAPE '\') LIMIT 1
67
- # => #<Artist @values={:name=>"YJM", :id=>1}>
68
-
69
- If there is no matching row, +first+ will return nil. If you want to
70
- raise an exception instead, use <tt>first!</tt>.
71
-
72
- <tt>Sequel::Dataset#[]</tt> is basically an alias for +first+, except it
73
- requires an argument:
74
-
75
- DB[:artists][{name: 'YJM'}]
76
- # SELECT * FROM artists WHERE (name = 'YJM') LIMIT 1
77
- # => {:name=>"YJM", :id=>1}
78
-
79
- Note that while Model.[] allows you to pass a primary key directly,
80
- Dataset#[] does not (unless it is a model dataset).
81
-
82
- ==== Using +last+
83
-
84
- If you want the last record in the dataset,
85
- <tt>Sequel::Dataset#last</tt> is an obvious method to use. +last+ requires the
86
- dataset be ordered, unless the dataset is a model dataset in which case +last+
87
- will do a reverse order by the primary key field:
88
-
89
- artist = Artist.last
90
- # SELECT * FROM artists ORDER BY id DESC LIMIT 1
91
- # => #<Artist @values={:name=>"YJM", :id=>1}>
92
-
93
- Note:
94
-
95
- 1. +last+ is equivalent to running a +reverse.first+ query, in other words it reverses the order of the dataset and then calls +first+. This is why +last+ raises a Sequel::Error when there is no order on a plain dataset - because it will provide the same record as +first+, and most users will find that confusing.
96
- 2. +last+ is not necessarily going to give you the last record in the dataset unless you give the dataset an unambiguous order.
97
- 3. +last+ will ignore +limit+ if chained together in a query because it sets a limit of 1 if no arguments are given.
98
-
99
- ==== Retrieving a Single Column Value
100
-
101
- Sometimes, instead of wanting an entire row, you only want the value of
102
- a specific column. For this <tt>Sequel::Dataset#get</tt> is the method
103
- you want:
104
-
105
- artist_name = Artist.get(:name)
106
- # SELECT name FROM artists LIMIT 1
107
- # => "YJM"
108
-
109
- ==== Retrieving a Multiple Column Values
110
-
111
- If you want the value for multiple columns, you can pass an array to
112
- <tt>Sequel::Dataset#get</tt>:
113
-
114
- artist_id, artist_name = Artist.get([:id, :name])
115
- # SELECT id, name FROM artists LIMIT 1
116
- # => [1, "YJM"]
117
-
118
- === Retrieving Multiple Objects
119
-
120
- ==== As an Array of Hashes or Model Objects
121
-
122
- In many cases, you want an array of all of the rows associated with the
123
- dataset, in which case <tt>Sequel::Dataset#all</tt> is the method you
124
- want to use:
125
-
126
- artists = Artist.all
127
- # SELECT * FROM artists
128
- # => [#<Artist @values={:name=>"YJM", :id=>1}>,
129
- # #<Artist @values={:name=>"AS", :id=>2}>]
130
-
131
- ==== Using an Enumerable Interface
132
-
133
- <tt>Sequel::Dataset</tt> uses an Enumerable Interface, so it provides a
134
- method named each that yields hashes or model objects as they are retrieved
135
- from the database:
136
-
137
- Artist.each{|x| p x.name}
138
- # SELECT * FROM artists
139
- "YJM"
140
- "AS"
141
-
142
- This means that all of the methods in the Enumerable module are available,
143
- such as +map+:
144
-
145
- artist_names = Artist.map{|x| x.name}
146
- # SELECT * FROM artists
147
- # => ["YJM", "AS"]
148
-
149
- ==== As an Array of Column Values
150
-
151
- Sequel also has an extended +map+ method that takes an argument. If you
152
- provide an argument to +map+, it will return an array of values for the
153
- given column. So the previous example can be handled more easily with:
154
-
155
- artist_names = Artist.map(:name)
156
- # SELECT * FROM artists
157
- # => ["YJM", "AS"]
158
-
159
- One difference between these two ways of returning an array of values is
160
- that providing +map+ with an argument is really doing:
161
-
162
- artist_names = Artist.map{|x| x[:name]} # not x.name
163
-
164
- Note that regardless of whether you provide +map+ with an argument, it
165
- does not modify the columns selected. If you only want to select a
166
- single column and return an array of the columns values, you can use
167
- +select_map+:
168
-
169
- artist_names = Artist.select_map(:name)
170
- # SELECT name FROM artists
171
- # => ["YJM", "AS"]
172
-
173
- It's also common to want to order such a map, so Sequel provides a
174
- +select_order_map+ method as well:
175
-
176
- artist_names = Artist.select_order_map(:name)
177
- # SELECT name FROM artists ORDER BY name
178
- # => ["AS", "YJM"]
179
-
180
- In all of these cases, you can provide an array of column symbols and
181
- an array of arrays of values will be returned:
182
-
183
- artist_names = Artist.select_map([:id, :name])
184
- # SELECT id, name FROM artists
185
- # => [[1, "YJM"], [2, "AS"]]
186
-
187
- ==== As a Hash
188
-
189
- Sequel makes it easy to take an SQL query and return it as a ruby hash,
190
- using the +as_hash+ method:
191
-
192
- artist_names = Artist.as_hash(:id, :name)
193
- # SELECT * FROM artists
194
- # => {1=>"YJM", 2=>"AS"}
195
-
196
- As you can see, the +as_hash+ method uses the first symbol as the key
197
- and the second symbol as the value. So if you swap the two arguments the hash
198
- will have its keys and values transposed:
199
-
200
- artist_names = Artist.as_hash(:name, :id)
201
- # SELECT * FROM artists
202
- # => {"YJM"=>1, "AS"=>2}
203
-
204
- Now what if you have multiple values for the same key? By default, +as_hash+
205
- will just have the last matching value. If you care about all matching values,
206
- use +to_hash_groups+, which makes the values of the array an array of matching
207
- values, in the order they were received:
208
-
209
- artist_names = Artist.to_hash_groups(:name, :id)
210
- # SELECT * FROM artists
211
- # => {"YJM"=>[1, 10, ...], "AS"=>[2, 20, ...]}
212
-
213
- If you only provide one argument to +as_hash+, it uses the entire hash
214
- or model object as the value:
215
-
216
- artist_names = DB[:artists].as_hash(:name)
217
- # SELECT * FROM artists
218
- # => {"YJM"=>{:id=>1, :name=>"YJM"}, "AS"=>{:id=>2, :name=>"AS"}}
219
-
220
- and +to_hash_groups+ works similarly:
221
-
222
- artist_names = DB[:artists].to_hash_groups(:name)
223
- # SELECT * FROM artists
224
- # => {"YJM"=>[{:id=>1, :name=>"YJM"}, {:id=>10, :name=>"YJM"}], ...}
225
-
226
- Model datasets have a +as_hash+ method that can be called without any
227
- arguments, in which case it will use the primary key as the key and
228
- the model object as the value. This can be used to easily create an
229
- identity map:
230
-
231
- artist_names = Artist.as_hash
232
- # SELECT * FROM artists
233
- # => {1=>#<Artist @values={:id=>1, :name=>"YGM"}>,
234
- # 2=>#<Artist @values={:id=>2, :name=>"AS"}>}
235
-
236
- There is no equivalent handling to +to_hash_groups+, since there would
237
- only be one matching record, as the primary key must be unique.
238
-
239
- Note that +as_hash+ never modifies the columns selected. However, just
240
- like Sequel has a +select_map+ method to modify the columns selected and
241
- return an array, Sequel also has a +select_hash+ method to modify the
242
- columns selected and return a hash:
243
-
244
- artist_names = Artist.select_hash(:name, :id)
245
- # SELECT name, id FROM artists
246
- # => {"YJM"=>1, "AS"=>2}
247
-
248
- Likewise, +select_hash_groups+ also exists:
249
-
250
- artist_names = Artist.select_hash_groups(:name, :id)
251
- # SELECT name, id FROM artists
252
- # => {"YJM"=>[1, 10, ...], "AS"=>[2, 20, ...]}
253
-
254
- == Modifying datasets
255
-
256
- Note that the retrieval methods discussed above just return
257
- the row(s) included in the existing dataset. In most cases,
258
- you aren't interested in every row in a table, but in a subset
259
- of the rows, based on some criteria. In Sequel, filtering
260
- the dataset is generally done separately than retrieving
261
- the records.
262
-
263
- There are really two types of dataset methods that you will
264
- be using:
265
-
266
- 1. Methods that return row(s), discussed above
267
- 2. Methods that return modified datasets, discussed below
268
-
269
- Sequel datasets are frozen and use a method chaining, functional style API
270
- that returns modified datasets. Let's start with a simple example.
271
-
272
- This is a basic dataset that includes all records in the
273
- table +artists+:
274
-
275
- ds1 = DB[:artists]
276
- # SELECT * FROM artists
277
-
278
- Let's say we are only interested in the artists whose names
279
- start with "A":
280
-
281
- ds2 = ds1.where(Sequel.like(:name, 'A%'))
282
- # SELECT * FROM artists WHERE (name LIKE 'A%' ESCAPE '\')
283
-
284
- Here we see that +where+ returns a dataset that adds a +WHERE+
285
- clause to the query. It's important to note that +where+ does
286
- not modify the receiver:
287
-
288
- ds1
289
- # SELECT * FROM artists
290
- ds2
291
- # SELECT * FROM artists WHERE (name LIKE 'A%' ESCAPE '\')
292
-
293
- In Sequel, dataset methods do not modify the dataset itself, so you can freely use the dataset in multiple
294
- places without worrying that its usage in one place will affect its usage
295
- in another place. This is what is meant by a functional style API.
296
-
297
- Let's say we only want to select the id and name columns, and that
298
- we want to order by name:
299
-
300
- ds3 = ds2.order(:name).select(:id, :name)
301
- # SELECT id, name FROM artists WHERE (name LIKE 'A%' ESCAPE '\') ORDER BY name
302
-
303
- Note how you don't need to assign the returned value of order to a variable,
304
- and then call select on that. Because order just returns a dataset, you can
305
- call select directly on the returned dataset. This is what is meant by a
306
- method chaining API.
307
-
308
- Also note how you can call methods that modify different clauses in any order.
309
- In this case, the WHERE clause was added first, then the ORDER clause, then the
310
- SELECT clause was modified. This makes for a flexible API, where you can modify
311
- any part of the query at any time.
312
-
313
- == Filters
314
-
315
- Filtering is probably the most common dataset modifying action done in Sequel.
316
- Both the +where+ and +filter+ methods filter the dataset by modifying the
317
- dataset's WHERE clause. Both accept a wide variety of input formats, discussed
318
- below.
319
-
320
- === Hashes
321
-
322
- The most common format for providing filters is via a hash. In general, Sequel
323
- treats conditions specified with a hash as equality, inclusion, or identity. What type
324
- of condition is used depends on the values in the hash.
325
-
326
- Unless Sequel has special support for the value's class, it uses a simple
327
- equality statement:
328
-
329
- Artist.where(id: 1)
330
- # SELECT * FROM artists WHERE (id = 1)
331
-
332
- Artist.where(name: 'YJM')
333
- # SELECT * FROM artists WHERE (name = 'YJM')
334
-
335
- For arrays, Sequel uses the IN operator with a value list:
336
-
337
- Artist.where(id: [1, 2])
338
- # SELECT * FROM artists WHERE (id IN (1, 2))
339
-
340
- For datasets, Sequel uses the IN operator with a subselect:
341
-
342
- Artist.where(id: Album.select(:artist_id))
343
- # SELECT * FROM artists WHERE (id IN (
344
- # SELECT artist_id FROM albums))
345
-
346
- For boolean values such as nil, true, and false, Sequel uses the IS operator:
347
-
348
- Artist.where(id: nil)
349
- # SELECT * FROM artists WHERE (id IS NULL)
350
-
351
- For ranges, Sequel uses a pair of inequality statements:
352
-
353
- Artist.where(id: 1..5)
354
- # SELECT * FROM artists WHERE ((id >= 1) AND (id <= 5))
355
-
356
- Artist.where(id: 1...5)
357
- # SELECT * FROM artists WHERE ((id >= 1) AND (id < 5))
358
-
359
- Finally, for regexps, Sequel uses an SQL regular expression. Note that this
360
- is only supported by default on PostgreSQL and MySQL. It can also be supported
361
- on SQLite when using the sqlite adapter with the :setup_regexp_function
362
- Database option.
363
-
364
- Artist.where(name: /JM$/)
365
- # SELECT * FROM artists WHERE (name ~ 'JM$')
366
-
367
- If there are multiple arguments in the hash, the filters are ANDed together:
368
-
369
- Artist.where(id: 1, name: /JM$/)
370
- # SELECT * FROM artists WHERE ((id = 1) AND (name ~ 'JM$'))
371
-
372
- This works the same as if you used two separate +where+ calls:
373
-
374
- Artist.where(id: 1).where(name: /JM$/)
375
- # SELECT * FROM artists WHERE ((id = 1) AND (name ~ 'JM$'))
376
-
377
- === Array of Two Element Arrays
378
-
379
- If you use an array of two element arrays, it is treated as a hash. The only
380
- advantage to using an array of two element arrays is that it allows you to
381
- duplicate keys, so you can do:
382
-
383
- Artist.where([[:name, /JM$/], [:name, /^YJ/]])
384
- # SELECT * FROM artists WHERE ((name ~ 'JM$')) AND ((name ~ '^YJ'))
385
-
386
- === Virtual Row Blocks
387
-
388
- If a block is passed to a filter, it is treated as a virtual row block:
389
-
390
- Artist.where{id > 5}
391
- # SELECT * FROM artists WHERE (id > 5)
392
-
393
- You can learn more about virtual row blocks in the {"Virtual Rows" guide}[rdoc-ref:doc/virtual_rows.rdoc].
394
-
395
- You can provide both regular arguments and a block, in which case the results
396
- will be ANDed together:
397
-
398
- Artist.where(name: 'A'...'M'){id > 5}
399
- # SELECT * FROM artists WHERE ((name >= 'A') AND (name < 'M') AND (id > 5))
400
-
401
- Using virtual row blocks, what you can do with single entry hash or an array with
402
- a single two element array can also be done using the =~ method:
403
-
404
- Artist.where{id =~ 5}
405
- # SELECT * FROM artists WHERE (id = 5)
406
-
407
- === Symbols
408
-
409
- If you have a boolean column in the database, and you want only true
410
- values, you can just provide the column symbol to filter:
411
-
412
- Artist.where(:retired)
413
- # SELECT * FROM artists WHERE retired
414
-
415
- === SQL::Expression
416
-
417
- Sequel has a DSL that allows easily creating SQL expressions. These SQL
418
- expressions are instances of subclasses of Sequel::SQL::Expression. You've
419
- already seen an example earlier:
420
-
421
- Artist.where(Sequel.like(:name, 'Y%'))
422
- # SELECT * FROM artists WHERE name LIKE 'Y%' ESCAPE '\'
423
-
424
- In this case Sequel.like returns a Sequel::SQL::BooleanExpression object,
425
- which is used directly in the filter.
426
-
427
- You can use the DSL to create arbitrarily complex expressions. SQL::Expression
428
- objects can be created via singleton methods on the Sequel module. The most common
429
- method is Sequel.[], which takes any object and wraps it in a SQL::Expression
430
- object. In most cases, the SQL::Expression returned supports the & operator for
431
- +AND+, the | operator for +OR+, and the ~ operator for inversion:
432
-
433
- Artist.where(Sequel.like(:name, 'Y%') & (Sequel[{b: 1}] | Sequel.~(c: 3)))
434
- # SELECT * FROM artists WHERE ((name LIKE 'Y%' ESCAPE '\') AND ((b = 1) OR (c != 3)))
435
-
436
- You can combine these expression operators with the virtual row support:
437
-
438
- Artist.where{(a > 1) & ~((b(c) < 1) | d)}
439
- # SELECT * FROM artists WHERE ((a > 1) AND (b(c) >= 1) AND NOT d)
440
-
441
- Note the use of parentheses when using the & and | operators, as they have lower
442
- precedence than other operators. The following will not work:
443
-
444
- Artist.where{a > 1 & ~(b(c) < 1 | d)}
445
- # Raises a TypeError
446
-
447
- === Strings with Placeholders
448
-
449
- Assuming you want to get your hands dirty and use SQL fragments in filters, Sequel allows you
450
- to do so if you explicitly mark the strings as literal strings using +Sequel.lit+. You can
451
- use placeholders in the string and pass arguments for the placeholders:
452
-
453
- Artist.where(Sequel.lit("name LIKE ?", 'Y%'))
454
- # SELECT * FROM artists WHERE (name LIKE 'Y%')
455
-
456
- This is the most common type of placeholder, where each question mark is substituted
457
- with the next argument:
458
-
459
- Artist.where(Sequel.lit("name LIKE ? AND id = ?", 'Y%', 5))
460
- # SELECT * FROM artists WHERE (name LIKE 'Y%' AND id = 5)
461
-
462
- You can also use named placeholders with a hash, where the named placeholders use
463
- colons before the placeholder names:
464
-
465
- Artist.where(Sequel.lit("name LIKE :name AND id = :id", name: 'Y%', id: 5))
466
- # SELECT * FROM artists WHERE (name LIKE 'Y%' AND id = 5)
467
-
468
- You don't have to provide any placeholders if you don't want to:
469
-
470
- Artist.where(Sequel.lit("id = 2"))
471
- # SELECT * FROM artists WHERE id = 2
472
-
473
- However, if you are using any untrusted input, you should definitely be using placeholders.
474
- In general, unless you are hardcoding values in the strings, you should use placeholders.
475
- You should never pass a string that has been built using interpolation, unless you are
476
- sure of what you are doing.
477
-
478
- Artist.where(Sequel.lit("id = #{params[:id]}")) # Don't do this!
479
- Artist.where(Sequel.lit("id = ?", params[:id])) # Do this instead
480
- Artist.where(id: params[:id].to_i) # Even better
481
-
482
- === Inverting
483
-
484
- You may be wondering how to specify a not equals condition in Sequel, or the NOT IN
485
- operator. Sequel has generic support for inverting conditions, so to write a not
486
- equals condition, you write an equals condition, and invert it:
487
-
488
- Artist.where(id: 5).invert
489
- # SELECT * FROM artists WHERE (id != 5)
490
-
491
- Note that +invert+ inverts the entire filter:
492
-
493
- Artist.where(id: 5).where{name > 'A'}.invert
494
- # SELECT * FROM artists WHERE ((id != 5) OR (name <= 'A'))
495
-
496
- In general, +invert+ is used rarely, since +exclude+ allows you to invert only specific
497
- filters:
498
-
499
- Artist.exclude(id: 5)
500
- # SELECT * FROM artists WHERE (id != 5)
501
-
502
- Artist.where(id: 5).exclude{name > 'A'}
503
- # SELECT * FROM artists WHERE ((id = 5) AND (name <= 'A')
504
-
505
- So to do a NOT IN with an array:
506
-
507
- Artist.exclude(id: [1, 2])
508
- # SELECT * FROM artists WHERE (id NOT IN (1, 2))
509
-
510
- Or to use the NOT LIKE operator:
511
-
512
- Artist.exclude(Sequel.like(:name, '%J%'))
513
- # SELECT * FROM artists WHERE (name NOT LIKE '%J%' ESCAPE '\')
514
-
515
- You can use Sequel.~ to negate expressions:
516
-
517
- Artist.where(Sequel.~(id: 5))
518
- # SELECT * FROM artists WHERE id != 5
519
-
520
- On Sequel expression objects, you can use ~ to negate them:
521
-
522
- Artist.where(~Sequel.like(:name, '%J%'))
523
- # SELECT * FROM artists WHERE (name NOT LIKE '%J%' ESCAPE '\')
524
-
525
- You can use !~ on Sequel expressions to create negated expressions:
526
-
527
- Artist.where{id !~ 5}
528
- # SELECT * FROM artists WHERE (id != 5)
529
-
530
- === Removing
531
-
532
- To remove all existing filters, use +unfiltered+:
533
-
534
- Artist.where(id: 1).unfiltered
535
- # SELECT * FROM artists
536
-
537
- == Ordering
538
-
539
- Sequel offers quite a few methods to manipulate the SQL ORDER BY clause. The
540
- most basic of these is +order+:
541
-
542
- Artist.order(:id)
543
- # SELECT * FROM artists ORDER BY id
544
-
545
- You can specify multiple arguments to order by more than one column:
546
-
547
- Album.order(:artist_id, :id)
548
- # SELECT * FROM album ORDER BY artist_id, id
549
-
550
- Note that unlike +where+, +order+ replaces an existing order, it does not
551
- append to an existing order:
552
-
553
- Artist.order(:id).order(:name)
554
- # SELECT * FROM artists ORDER BY name
555
-
556
- If you want to add a column to the end of the existing order:
557
-
558
- Artist.order(:id).order_append(:name)
559
- # SELECT * FROM artists ORDER BY id, name
560
-
561
- If you want to add a column to the beginning of the existing order:
562
-
563
- Artist.order(:id).order_prepend(:name)
564
- # SELECT * FROM artists ORDER BY name, id
565
-
566
- === Reversing
567
-
568
- Just like you can invert an existing filter, you can reverse an existing
569
- order, using +reverse+ without an order:
570
-
571
- Artist.order(:id).reverse
572
- # SELECT FROM artists ORDER BY id DESC
573
-
574
- Alternatively, you can provide reverse with the order:
575
-
576
- Artist.reverse(:id)
577
- # SELECT FROM artists ORDER BY id DESC
578
-
579
- To specify a single entry be reversed, <tt>Sequel.desc</tt> can be used:
580
-
581
- Artist.order(Sequel.desc(:id))
582
- # SELECT FROM artists ORDER BY id DESC
583
-
584
- This allows you to easily use both ascending and descending orders:
585
-
586
- Artist.order(:name, Sequel.desc(:id))
587
- # SELECT FROM artists ORDER BY name, id DESC
588
-
589
- === Removing
590
-
591
- Just like you can remove filters with +unfiltered+, you can remove
592
- orders with +unordered+:
593
-
594
- Artist.order(:name).unordered
595
- # SELECT * FROM artists
596
-
597
- == Selected Columns
598
-
599
- Sequel offers a few methods to manipulate the columns selected. As
600
- you may be able to guess, the main method used is +select+:
601
-
602
- Artist.select(:id, :name)
603
- # SELECT id, name FROM artists
604
-
605
- You just specify all of the columns that you are selecting as
606
- arguments to the method.
607
-
608
- If you are dealing with model objects, you'll want to include the
609
- primary key if you want to update or destroy the object. You'll
610
- also want to include any keys (primary or foreign) related to
611
- associations you plan to use.
612
-
613
- If a column is not selected, and you attempt to access it, you will
614
- get nil:
615
-
616
- artist = Artist.select(:name).first
617
- # SELECT name FROM artists LIMIT 1
618
-
619
- artist[:id]
620
- # => nil
621
-
622
- Like +order+, +select+ replaces the existing selected columns:
623
-
624
- Artist.select(:id).select(:name)
625
- # SELECT name FROM artists
626
-
627
- To append to the existing selected columns, use +select_append+:
628
-
629
- Artist.select(:id).select_append(:name)
630
- # SELECT id, name FROM artists
631
-
632
- To prepend to the existing selected columns, use +select_prepend+:
633
-
634
- Artist.select(:id).select_prepend(:name)
635
- # SELECT name, id FROM artists
636
-
637
- To remove specifically selected columns, and default back to all
638
- columns, use +select_all+:
639
-
640
- Artist.select(:id).select_all
641
- # SELECT * FROM artists
642
-
643
- To select all columns from a given table, provide an argument to
644
- +select_all+:
645
-
646
- Artist.select_all(:artists)
647
- # SELECT artists.* FROM artists
648
-
649
- === Distinct
650
-
651
- To treat duplicate rows as a single row when retrieving the records,
652
- use +distinct+:
653
-
654
- Artist.distinct.select(:name)
655
- # SELECT DISTINCT name FROM artists
656
-
657
- Note that DISTINCT is a separate SQL clause, it's not a function
658
- that you pass to select.
659
-
660
- == Limit and Offset
661
-
662
- You can limit the dataset to a given number of rows using +limit+:
663
-
664
- Artist.limit(5)
665
- # SELECT * FROM artists LIMIT 5
666
-
667
- You can provide a second argument to +limit+ to specify an offset:
668
-
669
- Artist.limit(5, 10)
670
- # SELECT * FROM artists LIMIT 5 OFFSET 10
671
-
672
- You can also call the +offset+ method separately:
673
-
674
- Artist.limit(5).offset(10)
675
- # SELECT * FROM artists LIMIT 5 OFFSET 10
676
-
677
- Either of these would return the 11th through 15th records in the original
678
- dataset.
679
-
680
- To remove a limit and offset from a dataset, use +unlimited+:
681
-
682
- Artist.limit(5, 10).unlimited
683
- # SELECT * FROM artists
684
-
685
- == Grouping
686
-
687
- The SQL GROUP BY clause is used to combine multiple rows based on
688
- the values of a given group of columns.
689
-
690
- To modify the GROUP BY clause of the SQL statement, you use +group+:
691
-
692
- Album.group(:artist_id)
693
- # SELECT * FROM albums GROUP BY artist_id
694
-
695
- You can remove an existing grouping using +ungrouped+:
696
-
697
- Album.group(:artist_id).ungrouped
698
- # SELECT * FROM albums
699
-
700
- If you want to add a column to the end of the existing grouping columns:
701
-
702
- Album.group(:artist_id).group_append(:name)
703
- # SELECT * FROM albums GROUP BY artist_id, name
704
-
705
- A common use of grouping is to count based on the number of grouped rows,
706
- and Sequel provides a +group_and_count+ method to make this easier:
707
-
708
- Album.group_and_count(:artist_id)
709
- # SELECT artist_id, count(*) AS count FROM albums GROUP BY artist_id
710
-
711
- This will return the number of albums for each artist_id.
712
-
713
- If you want to select and group on the same columns, you can use +select_group+:
714
-
715
- Album.select_group(:artist_id)
716
- # SELECT artist_id FROM albums GROUP BY artist_id
717
-
718
- Usually you would add a +select_append+ call after that, to add some sort of
719
- aggregation:
720
-
721
- Album.select_group(:artist_id).select_append{sum(num_tracks).as(tracks)}
722
- # SELECT artist_id, sum(num_tracks) AS tracks FROM albums GROUP BY artist_id
723
-
724
- == Having
725
-
726
- The SQL HAVING clause is similar to the WHERE clause, except that
727
- filters the results after the grouping has been applied, instead of
728
- before. One possible use is if you only wanted to return artists
729
- who had at least 10 albums:
730
-
731
- Album.group_and_count(:artist_id).having{count.function.* >= 10}
732
- # SELECT artist_id, count(*) AS count FROM albums
733
- # GROUP BY artist_id HAVING (count(*) >= 10)
734
-
735
- Both the WHERE clause and the HAVING clause are removed by +unfiltered+:
736
-
737
- Album.group_and_count(:artist_id).having{count.function.* >= 10}.
738
- where(:name.like('A%')).unfiltered
739
- # SELECT artist_id, count(*) AS count FROM albums GROUP BY artist_id
740
-
741
- == Joins
742
-
743
- Sequel has support for many different SQL join types.
744
- The underlying method used is +join_table+:
745
-
746
- Album.join_table(:inner, :artists, id: :artist_id)
747
- # SELECT * FROM albums
748
- # INNER JOIN artists ON (artists.id = albums.artist_id)
749
-
750
- In most cases, you won't call +join_table+ directly, as Sequel provides
751
- shortcuts for all common (and most uncommon) join types. For example
752
- +join+ does an inner join:
753
-
754
- Album.join(:artists, id: :artist_id)
755
- # SELECT * FROM albums
756
- # INNER JOIN artists ON (artists.id = albums.artist_id)
757
-
758
- And +left_join+ does a LEFT JOIN:
759
-
760
- Album.left_join(:artists, id: :artist_id)
761
- # SELECT * FROM albums
762
- # LEFT JOIN artists ON (artists.id = albums.artist_id)
763
-
764
- === Table/Dataset to Join
765
-
766
- For all of these specialized join methods, the first argument is
767
- generally the name of the table to which you are joining. However, you
768
- can also provide a dataset, in which case a subselect is used:
769
-
770
- Album.join(Artist.where{name < 'A'}, id: :artist_id)
771
- # SELECT * FROM albums
772
- # INNER JOIN (SELECT * FROM artists WHERE (name < 'A')) AS t1
773
- # ON (t1.id = albums.artist_id)
774
-
775
- === Join Conditions
776
-
777
- The second argument to the specialized join methods is the conditions
778
- to use when joining, which is similar to a filter expression, with
779
- a few minor exceptions.
780
-
781
- ==== Implicit Qualification
782
-
783
- A hash used as the join conditions operates similarly to a filter,
784
- except that unqualified symbol keys are automatically qualified
785
- with the table from the first argument, and unqualified symbol values
786
- are automatically qualified with the last table joined (or the first
787
- table in the dataset if there hasn't been a previous join):
788
-
789
- Album.join(:artists, id: :artist_id)
790
- # SELECT * FROM albums
791
- # INNER JOIN artists ON (artists.id = albums.artist_id)
792
-
793
- Note how the +id+ symbol is automatically qualified with +artists+,
794
- while the +artist_id+ symbol is automatically qualified with +albums+.
795
-
796
- Because Sequel uses the last joined table for implicit qualifications
797
- of values, you can do things like:
798
-
799
- Album.join(:artists, id: :artist_id).
800
- join(:members, artist_id: :id)
801
- # SELECT * FROM albums
802
- # INNER JOIN artists ON (artists.id = albums.artist_id)
803
- # INNER JOIN members ON (members.artist_id = artists.id)
804
-
805
- Note that when joining to the +members+ table, +artist_id+ is qualified
806
- with +members+ and +id+ is qualified with +artists+.
807
-
808
- While a good default, implicit qualification is not always correct:
809
-
810
- Album.join(:artists, id: :artist_id).
811
- join(:tracks, album_id: :id)
812
- # SELECT * FROM albums
813
- # INNER JOIN artists ON (artists.id = albums.artist_id)
814
- # INNER JOIN tracks ON (tracks.album_id = artists.id)
815
-
816
- Note here how +id+ is qualified with +artists+ instead of +albums+. This
817
- is wrong as the foreign key <tt>tracks.album_id</tt> refers to <tt>albums.id</tt>, not
818
- <tt>artists.id</tt>. To fix this, you need to explicitly qualify when joining:
819
-
820
- Album.join(:artists, id: :artist_id).
821
- join(:tracks, album_id: Sequel[:albums][:id])
822
- # SELECT * FROM albums
823
- # INNER JOIN artists ON (artists.id = albums.artist_id)
824
- # INNER JOIN tracks ON (tracks.album_id = albums.id)
825
-
826
- Just like in filters, an array of two element arrays is treated the same
827
- as a hash, but allows for duplicate keys:
828
-
829
- Album.join(:artists, [[:id, :artist_id], [:id, 1..5]])
830
- # SELECT * FROM albums INNER JOIN artists
831
- # ON ((artists.id = albums.artist_id)
832
- # AND (artists.id >= 1) AND (artists.id <= 5))
833
-
834
- And just like in the hash case, unqualified symbol elements in the
835
- array are implicitly qualified.
836
-
837
- By default, Sequel only qualifies unqualified symbols in the conditions. However,
838
- You can provide an options hash with a <tt>qualify: :deep</tt> option to do a deep
839
- qualification, which can qualify subexpressions. For example, let's say you are doing
840
- a JOIN using case insensitive string comparison:
841
-
842
- Album.join(:artists, {Sequel.function(:lower, :name) =>
843
- Sequel.function(:lower, :artist_name)},
844
- qualify: :deep)
845
- # SELECT * FROM albums INNER JOIN artists
846
- # ON (lower(artists.name) = lower(albums.artist_name))
847
-
848
- Note how the arguments to lower were qualified correctly in both cases.
849
-
850
- ==== USING Joins
851
-
852
- The most common type of join conditions is a JOIN ON, as displayed
853
- above. However, the SQL standard allows for join conditions to be
854
- specified with JOIN USING, assuming the column name is the same in
855
- both tables.
856
-
857
- For example, if instead of having a primary
858
- column named +id+ in all of your tables, you use +artist_id+ in your
859
- +artists+ table and +album_id+ in your +albums+ table, you could do:
860
-
861
- Album.join(:artists, [:artist_id])
862
- # SELECT * FROM albums INNER JOIN artists USING (artist_id)
863
-
864
- See here how you specify the USING columns as an array of symbols.
865
-
866
- ==== NATURAL Joins
867
-
868
- NATURAL joins take it one step further than USING joins, by assuming
869
- that all columns with the same names in both tables should be
870
- used for joining:
871
-
872
- Album.natural_join(:artists)
873
- # SELECT * FROM albums NATURAL JOIN artists
874
-
875
- In this case, you don't even need to specify any conditions.
876
-
877
- ==== Join Blocks
878
-
879
- You can provide a block to any of the join methods that accept
880
- conditions. This block should accept 3 arguments: the table alias
881
- for the table currently being joined, the table alias for the last
882
- table joined (or first table), and an array of previous
883
- <tt>Sequel::SQL::JoinClause</tt>s.
884
-
885
- This allows you to qualify columns similar to how the implicit
886
- qualification works, without worrying about the specific aliases
887
- being used. For example, let's say you wanted to join the albums
888
- and artists tables, but only want albums where the artist's name
889
- comes before the album's name.
890
-
891
- Album.join(:artists, id: :artist_id) do |j, lj, js|
892
- Sequel[j][:name] < Sequel[lj][:name]
893
- end
894
- # SELECT * FROM albums INNER JOIN artists
895
- # ON ((artists.id = albums.artist_id)
896
- # AND (artists.name < albums.name))
897
-
898
- Because greater than can't be expressed with a hash in Sequel, you
899
- need to use a block and qualify the tables manually.
900
-
901
- == From
902
-
903
- In general, the FROM table is the first clause populated when creating
904
- a dataset. For a standard Sequel::Model, the dataset already has the
905
- FROM clause populated, and the most common way to create datasets is
906
- with the <tt>Database#[]</tt> method, which populates the FROM clause.
907
-
908
- However, you can modify the tables you are selecting FROM using +from+:
909
-
910
- Album.from(:albums, :old_albums)
911
- # SELECT * FROM albums, old_albums
912
-
913
- Be careful with this, as multiple tables in the FROM clause use a cross
914
- join by default, so the number of rows will be number of albums times the
915
- number of old albums.
916
-
917
- Using multiple FROM tables and setting conditions in the WHERE clause is
918
- an old-school way of joining tables:
919
-
920
- DB.from(:albums, :artists).where{{artists[:id]=>albums[:artist_id]}}
921
- # SELECT * FROM albums, artists WHERE (artists.id = albums.artist_id)
922
-
923
- === Using the current dataset in a subselect
924
-
925
- In some cases, you may want to wrap the current dataset in a subselect.
926
- Here's an example using +from_self+:
927
-
928
- Album.order(:artist_id).limit(100).from_self.group(:artist_id)
929
- # SELECT * FROM (SELECT * FROM albums ORDER BY artist_id LIMIT 100)
930
- # AS t1 GROUP BY artist_id
931
-
932
- This is different than without +from_self+:
933
-
934
- Album.order(:artist_id).limit(100).group(:artist_id)
935
- # SELECT * FROM albums GROUP BY artist_id ORDER BY name LIMIT 100
936
-
937
- Without +from_self+, you are doing the grouping, and limiting the number
938
- of grouped records returned to 100. So assuming you have albums by more
939
- than 100 artists, you'll end up with 100 results.
940
-
941
- With +from_self+, you are limiting the number of records before grouping.
942
- So if the artist with the lowest id had 100 albums, you'd get 1 result,
943
- not 100.
944
-
945
- == Locking for Update
946
-
947
- Sequel allows you to easily add a FOR UPDATE clause to your queries so
948
- that the records returned can't be modified by another query until the
949
- current transaction commits. You just use the +for_update+ dataset
950
- method when returning the rows:
951
-
952
- DB.transaction do
953
- album = Album.for_update.first(id: 1)
954
- # SELECT * FROM albums WHERE (id = 1) FOR UPDATE
955
- album.num_tracks += 1
956
- album.save
957
- end
958
-
959
- This will ensure that no other connection modifies the row between when you select
960
- it and when the transaction ends.
961
-
962
- === Optimistic Locking
963
-
964
- One of the model plugins that ships with Sequel is an optimistic locking plugin, which provides
965
- a database independent way to detect and raise an error if two different connections
966
- modify the same row. It's useful for things like web forms where you cannot keep a
967
- transaction open while the user is looking at the form, because of the web's
968
- stateless nature.
969
-
970
- == Custom SQL
971
-
972
- Sequel makes it easy to use custom SQL for the query by providing it to the <tt>Database#[]</tt>
973
- method as a string:
974
-
975
- DB["SELECT * FROM artists"]
976
- # SELECT * FROM artists
977
-
978
- You can also use the +with_sql+ dataset method to return a dataset that uses that
979
- exact SQL:
980
-
981
- DB[:albums].with_sql("SELECT * FROM artists")
982
- # SELECT * FROM artists
983
-
984
- With either of these methods, you can use placeholders:
985
-
986
- DB["SELECT * FROM artists WHERE id = ?", 5]
987
- # SELECT * FROM artists WHERE id = 5
988
-
989
- DB[:albums].with_sql("SELECT * FROM artists WHERE id = :id", id: 5)
990
- # SELECT * FROM artists WHERE id = 5
991
-
992
- Note that if you specify the dataset using custom SQL, you can still call the dataset
993
- modification methods, but in many cases they will appear to have no affect:
994
-
995
- DB["SELECT * FROM artists"].select(:name).order(:id)
996
- # SELECT * FROM artists
997
-
998
- You can use the implicit_subquery extension to automatically wrap queries that use
999
- custom SQL in subqueries if a method is called that would modify the SQL:
1000
-
1001
- DB.extension :implicit_subquery
1002
- DB["SELECT * FROM artists"].select(:name).order(:id)
1003
- # SELECT name FROM (SELECT * FROM artists) AS t1 ORDER BY id"
1004
-
1005
- If you must drop down to using custom SQL, it's recommended that you only do so for
1006
- specific parts of a query. For example, if the reason you are using custom SQL is
1007
- to use a custom operator in the database in the SELECT clause:
1008
-
1009
- DB["SELECT name, (foo !@# ?) AS baz FROM artists", 'bar']
1010
-
1011
- it's better to use Sequel's DSL, and use a literal string for the custom operator:
1012
-
1013
- DB[:artists].select(:name, Sequel.lit("(foo !@# ?)", 'bar').as(:baz))
1014
-
1015
- That way Sequel's method chaining still works, and it increases Sequel's ability to
1016
- introspect the code.
1017
-
1018
- == Checking for Records
1019
-
1020
- If you just want to know whether the current dataset would return any rows, use <tt>empty?</tt>:
1021
-
1022
- Album.empty?
1023
- # SELECT 1 FROM albums LIMIT 1
1024
- # => false
1025
-
1026
- Album.where(id: 0).empty?
1027
- # SELECT 1 FROM albums WHERE (id = 0) LIMIT 1
1028
- # => true
1029
-
1030
- Album.where(Sequel.like(:name, 'R%')).empty?
1031
- # SELECT 1 FROM albums WHERE (name LIKE 'R%' ESCAPE '\') LIMIT 1
1032
- # => false
1033
-
1034
- == Aggregate Calculations
1035
-
1036
- The SQL standard defines a few helpful methods to get aggreate information about
1037
- datasets, such as +count+, +sum+, +avg+, +min+, and +max+. There are dataset methods
1038
- for each of these aggregate functions.
1039
-
1040
- +count+ just returns the number of records in the dataset.
1041
-
1042
- Album.count
1043
- # SELECT count(*) AS count FROM albums LIMIT 1
1044
- # => 2
1045
-
1046
- If you pass an expression to count, it will return the number of records where
1047
- that expression in not NULL:
1048
-
1049
- Album.count(:artist_id)
1050
- # SELECT count(artist_id) AS count FROM albums LIMIT 1
1051
- # => 1
1052
-
1053
- The other methods take a column argument and call the aggregate function with
1054
- the argument:
1055
-
1056
- Album.sum(:id)
1057
- # SELECT sum(id) AS sum FROM albums LIMIT 1
1058
- # => 3
1059
-
1060
- Album.avg(:id)
1061
- # SELECT avg(id) AS avg FROM albums LIMIT 1
1062
- # => 1.5
1063
-
1064
- Album.min(:id)
1065
- # SELECT min(id) AS min FROM albums LIMIT 1
1066
- # => 1
1067
-
1068
- Album.max(:id)
1069
- # SELECT max(id) AS max FROM albums LIMIT 1
1070
- # => 2