eb74ce8d6c87a5326846d115bfbdbb83381c31fb
[dbsrgits/DBIx-Class-Manual-SQLHackers.git] / lib / DBIx / Class / Manual / SQLHackers / SELECT.pod
1 =head1 NAME
2
3 DBIx::Class::Manual::SQLHackers::SELECT - DBIx::Class for SQL Hackers - SELECT
4
5 =over
6
7 =item L<Introduction|DBIx::Class::Manual::SQLHackers::Introduction>
8
9 =item L<CREATE|DBIx::Class::Manual::SQLHackers::CREATE>
10
11 =item L<INSERT|DBIx::Class::Manual::SQLHackers::INSERT>
12
13 =item SELECT
14
15 =item L<UPDATE|DBIx::Class::Manual::SQLHackers::UPDATE>
16
17 =item L<DELETE|DBIx::Class::Manual::SQLHackers::DELETE>
18
19 =item L<BEGIN, COMMIT|DBIx::Class::Manual::SQLHackers::Transactions>
20
21 =back
22
23 =head1 SELECTing data
24
25 =head2 Fetching rows from a query
26
27     SELECT id, username, dob, realname, password
28     FROM users;
29
30 In DBIx::Class queries (or more specifically query plans) are represented by ResultSet objects. These are created by calling B<search> on existing resultsets, while passing new search conditions or attributes. A query is not run against the database until data is explicitly requested. 
31
32 You can either fetch all the data at once, or iterate over the results:
33
34 =over 
35
36 =item 1. Create a Schema object representing the database you are working with:
37
38         my $schema = MyDatabase::Schema->connect('dbi:SQLite:my.db');
39
40 =item 2. The B<resultset> method returns a ResultSet representing a query retrieving all columns of the given B<ResultSource> without conditions:
41
42         my $user_resultset = $schema->resultset('User');
43
44 =item 3. Fetch all users as Row objects using the B<all> method:
45
46         my @users = $user_resultset->all();
47
48 =item 4. OR, fetch each user as a Row object using B<next>:
49
50         while( my $user = $user_resultset->next()) {
51         }
52
53 =back
54
55 =head2 Fetching column values from a Row object
56
57 The Row object represents the results from a single data source in the query. The column values can be retrieved by using the accessor methods named after the column names. (By default that is; accessors can be changed in the L<Result Class|DBIx::Class::ResulSource> if needed.)
58
59     print $user->username;
60
61 See the L<DBIx::Class::Row> documentation for more things you can do
62 with Row objects.
63     
64 =head2 Simple SELECT, one row via the primary key
65
66     SELECT id, username, dob, realname, password
67     FROM users
68     WHERE id = 1;
69
70 The B<find> method on a ResultSet is a shortcut to create a query based on the inputs, run the query, and return a single row as a Row object result. 
71
72 If passed a condition which matches multiple rows, a warning is given.
73
74 =over 
75
76 =item 1. Create a Schema object representing the database you are working with:
77
78         my $schema = MyDatabase::Schema->connect('dbi:SQLite:my.db');
79
80 =item 2. Call the B<find> method on the resultset for the L<ResultSource|DBIx::Class::ResultSource> you wish to fetch data from:
81
82         my $fred_user = $schema->resultset('User')->find({ id => 1 });
83
84 =back
85
86 B<$fred_user> is a now Row object.
87
88 =head2 Simple SELECT, one row via a unique key
89
90     SELECT id, username, dob, realname, password
91     FROM users
92     WHERE username = 'fredbloggs';
93
94 B<find> also works well on unique constraints, for example the username of our user. Unique constraints can be defined on Result classes using B<add_unique_constraint> (See L<CREATE|DBIx::Class::Manual::SQLHackers::CREATE>).
95
96 =over 
97
98 =item 1. Create a Schema object representing the database you are working with:
99
100         my $schema = MyDatabase::Schema->connect('dbi:SQLite:my.db');
101
102 =item 2. Call the B<find> method on the resultset for the L<ResultSource|DBIx::Class::ResultSource> you wish to fetch data from:
103
104         my $fred_user = $schema->resultset('User')->find(
105           { username => 'fredbloggs' },
106           { key => 'uniq_username' }
107         );
108
109 =back
110
111 "uniq_username" is the name of a constraint defined on the User L<ResultSource|DBIx::Class::ResultSource> which specifies that the username column is unique across the table. The second argument to B<find> is a set of attributes, of which the "key" attribute defines which constraint to do a lookup on.
112
113 =head2 Simple SELECT, with WHERE condition
114
115     SELECT id, username, dob, realname, password
116     FROM users
117     WHERE dob = '1910-02-01';
118
119 To select all users born on the date '1910-02-01', we can use the B<search> method to prepare a query. Search returns a new resultset with the search conditions stored in it; it does not run the query on the database.
120
121 =over
122
123 =item 1. Create a Schema object representing the database you are working with:
124
125         my $schema = MyDatabase::Schema->connect('dbi:SQLite:my.db');
126
127 =item 2. Call the B<search> method on the resultset for the L<ResultSource|DBIx::Class::ResultSource> you wish to fetch data from:
128
129         my $dob_search = $schema->resultset('User')->search(
130           { dob => '1910-02-01' }
131         );
132
133 =back
134
135 To run the query, use the B<all> or B<next> methods shown at the beginning of this page.
136
137 =head2 SELECT with different WHERE conditions
138
139 Shown below are some common SQL WHERE conditions. The syntax for these is parsed by a module called L<SQL::Abstract>, which DBIx::Class uses. They can all be passed to the B<search> method as conditions.
140
141     SELECT id, username, dob, realname, password
142     FROM users
143     WHERE username LIKE 'fred%';
144
145 =cut
146
147 =pod
148
149         my $name_search = $schema->resultset('User')->search(
150           { username => { '-like' => 'fred%' } }
151         );
152
153 =cut
154
155 =pod
156
157     SELECT id, username, dob, realname, password
158     FROM users
159     WHERE dob BETWEEN '1910-01-01' AND '1910-12-31';
160
161 =cut
162
163 =pod
164
165         my $year_dob_search = $schema->resultset('User')->search(
166           { dob => { '-between' => ['1910-01-01', '1910-12-31'] } }
167         );
168
169 =cut
170
171 =pod
172
173     SELECT id, username, dob, realname, password
174     FROM users
175     WHERE dob IN ('1910-02-01', '1910-02-02');
176
177 =cut
178
179 =pod
180
181         my $feb_dob_search = $schema->resultset('User')->search(
182           { dob => { '-in' => ['1910-02-01', '1910-02-02'] } }
183         );
184
185 =cut
186
187 =pod
188
189     SELECT id, username, dob, realname, password
190     FROM users
191     WHERE dob >= 1911-01-01;
192     
193 =cut
194
195 =pod
196
197         my $next_year_dob = $schema->resultset('User')->search(
198           { dob => { '>=', '1911-01-01' } }
199         );
200     
201
202 =head2 SELECT with WHERE condition on JOINed table
203
204     SELECT posts.id, created_date, title, post
205     FROM posts
206     JOIN users user ON user.id = posts.user_id
207     WHERE user.username = 'fredbloggs';
208
209 The second argument to B<search> is a hashref of attributes to apply to the query. One of them is B<join>, which is used to connect to other tables using the relationships defined in the Result classes.
210
211 =over
212
213 =item 1. Create a Schema object representing the database you are working with:
214
215         my $schema = MyDatabase::Schema->connect('dbi:SQLite:my.db');
216
217 =item 2. Call the B<search> method on the resultset for the L<ResultSource|DBIx::Class::ResultSource> you wish to fetch data from:
218
219         my $freds_posts = $schema->resultset('Post')->search(
220           { 'user.username' => 'fredbloggs' },
221           { join => 'user' }
222         );
223
224 =back
225
226 Note that the string "user", used twice here, refers to the B<name> of the L<Relationship|DBIx::Class::Relationship> between the "Post" source and the "User" source. All dealings with related tables are referred to by relationship names, not table names.
227
228 To run the query, use the B<all> or B<next> methods show at the beginning of this page.
229
230 =head2 SELECT with fewer columns
231
232     SELECT id, title
233     FROM posts
234
235 There's usually little reason to do this sort of query, as fetching all the data in a row doesn't cost any more time than fetching some of it. Unless of course your source is a View with calculations, or has huge blobs, or.. Okay, you might well want to do this occasionally.
236
237 =over
238
239 =item 1. Create a Schema object representing the database you are working with:
240
241         my $schema = MyDatabase::Schema->connect('dbi:SQLite:my.db');
242
243 =item 2. Call the B<search> method on the resultset for the L<ResultSource|DBIx::Class::ResultSource> you wish to fetch data from:
244
245         my $post_titles = $schema->resultset('Post')->search(
246           { },
247           { columns => [qw/id title/] }
248         );
249
250 =back
251
252 Note that accessors for other columns not fetched will return B<undef>, which is also the perl equivalent of the SQL C<NULL> value. To disambiguate between an C<undef> meaning "this column is set null" and "we never retrieved the value of this column" use L<DBIx::Class::Row::has_column_loaded|DBIx::Class::Row/has_column_loaded>.
253     
254
255 =head2 SELECT with aggregates
256
257     SELECT COUNT(*)
258     FROM users;
259
260 Finding out how many users exist can be achieved with a built-in method, B<count>.
261
262 =over
263
264 =item 1. Create a Schema object representing the database you are working with:
265
266         my $schema = MyDatabase::Schema->connect('dbi:SQLite:my.db');
267
268 =item 2. Call the B<count> method on the resultset for the L<ResultSource|DBIx::Class::ResultSource> you wish to fetch data from:
269
270         my $posts_count = $schema->resultset('Post')->count();
271
272 =back
273
274 The result is not an object, just a number.
275
276     SELECT SUM(amount)
277     FROM prices;
278
279 A rather pointless exercise in summing an entire "amount" column from an imaginary "prices" table. This can be done in several ways, first, the built-in L<DBIx::Class::ResultSet::Column> method, by calling B<get_column>.
280
281 =over
282
283 =item 1. Create a Schema object representing the database you are working with:
284
285         my $schema = MyDatabase::Schema->connect('dbi:SQLite:my.db');
286
287 =item 2. Call the B<get_column> method on the resultset for the L<ResultSource|DBIx::Class::ResultSource> you wish to fetch data from, then the B<sum> method:
288
289         my $sum_prices = $schema->resultset('Price')->get_column('amount')->sum();
290
291 =back
292
293 The result is just a number.
294
295 The alternative way uses the B<search> method and is easier to build further refinements into.
296
297 =over
298
299 =item 1. Create a Schema object representing the database you are working with:
300
301         my $schema = MyDatabase::Schema->connect('dbi:SQLite:my.db');
302
303 =item 2. Call the B<search> method on the resultset for the L<ResultSource|DBIx::Class::ResultSource> you wish to fetch data from:
304
305         my $sum_prices_rs = $schema->resultset('Price')->search(
306           { },
307           { columns => { sum_amount => { SUM => 'amount'} } },
308         );
309
310 =back
311
312 The result is a resultset. To fetch the one-row result, call B<single> or B<all>. The resulting Row object will not contain an accessor for the virtual "sum_amount" column, we'll need to fetch it using the Row method B<get_column>.
313
314     print $sum_prices_rs->single->get_column('sum_amount');
315
316 =head2 SELECT from JOINed tables
317
318     SELECT users.id, username, posts.id, posts.title
319     FROM users
320     JOIN posts posts ON posts.used_id = users.id
321     
322 To select data from other tables, use the B<join> attribute to name the table relationships to create a JOIN clause to.
323
324 =over
325
326 =item 1. Create a Schema object representing the database you are working with:
327
328         my $schema = MyDatabase::Schema->connect('dbi:SQLite:my.db');
329
330 =item 2. Call the B<search> method on the resultset of the L<ResultSource|DBIx::Class::ResultSource> you wish to group data on:
331
332         my $posts_count_per_user = $schema->resultset('User')->search(
333           { },
334           { columns => [ qw/id username posts.id posts.title/ ],
335             join => 'posts',
336           }
337         );
338
339 =back
340
341 Here "posts" refers to the name of the L<Relationship|DBIx::Class::Relationship> between the "User" source and the "Post" source.
342
343 To retrieve the extra data, call the usual relationship accessor:
344
345     while( my $row = $sorted_users->next) {
346       print "user/post: ", $row->username;
347       print $_->title for $row->posts;
348       print "\n";
349     }
350
351
352 =head2 SELECT with GROUP BY
353
354     SELECT users.id, username, COUNT(posts.id)
355     FROM users
356     JOIN posts posts ON posts.used_id = users.id
357     GROUP BY users.id, username;
358
359 To group your results, use the B<group_by> attribute on a B<search> method. We also use the B<columns>  attribute to select and name a subset of columns.
360
361 =over
362
363 =item 1. Create a Schema object representing the database you are working with:
364
365         my $schema = MyDatabase::Schema->connect('dbi:SQLite:my.db');
366
367 =item 2. Call the B<search> method on the resultset of the L<ResultSource|DBIx::Class::ResultSource> you wish to group data on:
368
369         my $posts_count_per_user = $schema->resultset('User')->search(
370           { },
371           { columns => [ qw/id username/, { post_count => { count => 'posts.id' } } ],
372             join => 'posts',
373             group_by => [qw/id username/],
374           }
375         );
376
377 =back
378
379 Here "posts" refers to the name of the L<Relationship|DBIx::Class::Relationship> between the "User" source and the "Post" source.
380
381 The results will contain two columns with the usual accessors, "id" and "username", and one with no accessor, as it is a virtual column.
382
383     while( my $row = $posts_count_per_user->next) {
384       print "user: ", $row->username, " posts: ", $row->get_column('post_count');
385     }
386
387 Note: Remember to disambiguate the columns when joining two tables with identical column names.
388
389 =begin comment
390
391 Commented out section as ordering by a related source does not work yet. Fix in progress, will comment back in when DBIC is updated.
392
393     =head2 SELECT with simple ORDER BY
394
395         SELECT users.id, username, dob, realname, password, posts.title
396         FROM users
397         JOIN posts posts ON posts.used_id = users.id
398         ORDER BY username, posts.title;
399
400     To sort the results, use the B<order_by> attributes on a B<search> method. Content can of course be ordered by columns in the current table, or in a joined table
401
402     =over
403
404     =item 1. Create a Schema object representing the database you are working with:
405
406             my $schema = MyDatabase::Schema->connect('dbi:SQLite:my.db');
407
408     =item 2. Call the B<search> method on the resultset of the L<ResultSource|DBIx::Class::ResultSource> you wish to sort data on:
409
410             my $sorted_users = $schema->resultset('User')->search(
411               { },
412               { '+columns' => [ qw/posts.id posts.title/ ],
413                 join => 'posts',
414                 order_by => [qw/username posts.title/],
415               }
416             );
417
418     =back
419
420     Here "posts" refers to the name of the L<Relationship|DBIx::Class::Relationship> between the "User" source and the "Post" source.
421
422     The results will be ordered by username, then post title, ready for outputting.
423
424     Note how we have added the title of each post, this prevents us having to fire off a second query to fetch the post data to output it. The B<+columns> attribute specifies an extended set of columns to fetch, in addition to the columns of the main query table.
425
426     To retrieve the extra data, call the usual relationship accessor:
427
428         while( my $row = $sorted_users->next) {
429           print "user/post: ", $row->username;
430           print $_->title for $row->posts;
431           print "\n";
432         }
433
434 =end comment
435
436 =head2 SELECT with HAVING
437
438     SELECT users.id, username, dob
439     FROM users
440     JOIN posts posts ON posts.used_id = users.id
441     GROUP BY users.id, username, dob
442     HAVING count(posts.id) = 1
443
444 To add a B<having> clause to your query, use the corresponding B<having> attribute.
445
446 =over
447
448 =item 1. Create a Schema object representing the database you are working with:
449
450         my $schema = MyDatabase::Schema->connect('dbi:SQLite:my.db');
451
452 =item 2. Call the B<search> method on the resultset of the L<ResultSource|DBIx::Class::ResultSource> you wish to filter data on:
453
454         my $filtered_users = $schema->resultset('User')->search(
455           { },
456           { 'columns' => [ qw/me.id me.username me.dob/ ],
457             join => 'posts',
458             group_by => [qw/me.id me.username me.dob/],
459             having   => [{ 'posts.id' => 1 }],
460           }
461         );
462
463 =back
464
465 Here "posts" refers to the name of the L<Relationship|DBIx::Class::Relationship> between the "User" source and the "Post" source.
466
467 The results will be filtered by the HAVING clause.
468
469 =head2 SELECT with DISTINCT
470
471     SELECT DISTINCT(posts.title)
472     FROM posts
473
474 To produce DISTINCT clauses, we need to use a hashref argument to the list of items passed to the B<columns> attribute.
475
476 =over
477
478 =item 1. Create a Schema object representing the database you are working with:
479
480         my $schema = MyDatabase::Schema->connect('dbi:SQLite:my.db');
481
482 =item 2. Call the B<search> method on the resultset of the L<ResultSource|DBIx::Class::ResultSource> you wish to find distinct rows on:
483
484         my $distinct_posts = $schema->resultset('Post')->search(
485           { },
486           { columns => [{ 'd_title' => { distinct => 'me.title' } }],
487           }
488         );
489
490 =back
491
492 This can also be achieved by using the ResultSet method B<get_column>. The method returns a ResultSetColumn object based on the given column name argument, which can call SQL aggregate functions based upon the column of that data.
493
494 So we can also do this, for single column DISTINCT clauses:
495
496 =over
497
498 =item 1. Create a Schema object representing the database you are working with:
499
500         my $schema = MyDatabase::Schema->connect('dbi:SQLite:my.db');
501
502 =item 2. Call the B<get_column> method on the resultset of the L<ResultSource|DBIx::Class::ResultSource> you wish to find distinct rows on:
503
504         my $rs_column = $schema->resultset('Post')->get_column('title');
505
506 =item 3. Call the B<func> method on the resultset column object and pass it the name of the function to apply:
507
508         my $titles = $rs_column->func('distinct');
509
510 =back
511
512 The result will be an arrayref of the actual values. If a ResultSet object is needed for further refinement, use B<func_rs> instead.
513
514 =head2 SELECT ... FOR UPDATE
515
516     SELECT users.id, users.username, users.dob
517     FROM users
518     FOR UPDATE
519
520 To fetch data and lock it for updating from other transactions, use the B<for> attribute and pass it the value B<update>. This should be done inside a L<Transaction|DBIx::Class::Manual::SQLHackers::Transactions>.
521
522 =over
523
524 =item 1. Create a Schema object representing the database you are working with:
525
526         my $schema = MyDatabase::Schema->connect('dbi:SQLite:my.db');
527
528 =item 2. Call the B<search> method on the resultset of the L<ResultSource|DBIx::Class::ResultSource> you wish to lock data on:
529
530         my $locked_posts = $schema->resultset('User')->search(
531           { },
532           { columns => [qw/me.id me.username me.dob/],
533             for     => 'update'
534           }
535         );
536
537 =back
538
539 The resultset and rows will be returned as normal, and can be used to update the rows without worrying about other processes modifying the table behind your back.
540
541 =head2 SELECT with LIMIT and OFFSET
542
543     SELECT users.id, users.username
544     FROM users
545     ORDER BY user.dob DESC
546     LIMIT 10 OFFSET 11;
547
548 To reduce the set of rows fetched, use the B<rows> and B<page> attributes. The value of B<page> will default to 1, which means no OFFSET will be applied.
549
550 =over
551
552 =item 1. Create a Schema object representing the database you are working with:
553
554         my $schema = MyDatabase::Schema->connect('dbi:SQLite:my.db');
555
556 =item 2. Call the B<search> method on the resultset of the L<ResultSource|DBIx::Class::ResultSource> you wish to limit data on:
557
558         my $limited_posts = $schema->resultset('User')->search(
559           { },
560           { columns  => [qw/me.id me.username/],
561             order_by => { '-desc' => ['user.dob'] },
562             rows     => 10,
563             page     => 2,
564           }
565         );
566
567 This will return exactly 10 row objects, sorted by descending date of birth of the users, starting at the 11th row of the sorted result.
568
569 =back