release 1.200001
[dbsrgits/DBIx-Class-Manual-SQLHackers.git] / lib / DBIx / Class / Manual / SQLHackers / SELECT.pod
CommitLineData
6c2a4396 1=head1 NAME
2
3DBIx::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
2f41b1a9 30In 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.
6c2a4396 31
32You 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
2f41b1a9 40=item 2. The B<resultset> method returns a ResultSet representing a query retrieving all columns of the given B<ResultSource> without conditions:
6c2a4396 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
1060e1bd 57The 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.)
6c2a4396 58
59 print $user->username;
60
abc32120 61See the L<DBIx::Class::Row> documentation for more things you can do
6c2a4396 62with 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
70The 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
72If 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
86B<$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
abc32120 94B<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>).
6c2a4396 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
1060e1bd 119To 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.
6c2a4396 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
abc32120 135To run the query, use the B<all> or B<next> methods shown at the beginning of this page.
6c2a4396 136
137=head2 SELECT with different WHERE conditions
138
1060e1bd 139Shown 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.
6c2a4396 140
141 SELECT id, username, dob, realname, password
142 FROM users
143 WHERE username LIKE 'fred%';
144
1060e1bd 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
6c2a4396 156
157 SELECT id, username, dob, realname, password
158 FROM users
159 WHERE dob BETWEEN '1910-01-01' AND '1910-12-31';
160
1060e1bd 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
6c2a4396 172
173 SELECT id, username, dob, realname, password
174 FROM users
175 WHERE dob IN ('1910-02-01', '1910-02-02');
176
1060e1bd 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
6c2a4396 188
189 SELECT id, username, dob, realname, password
190 FROM users
191 WHERE dob >= 1911-01-01;
192
1060e1bd 193=cut
194
195=pod
196
197 my $next_year_dob = $schema->resultset('User')->search(
198 { dob => { '>=', '1911-01-01' } }
199 );
6c2a4396 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
209The 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
1060e1bd 226Note 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.
6c2a4396 227
228To 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
235There'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
6c2a4396 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
1060e1bd 252Note 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>.
6c2a4396 253
254
255=head2 SELECT with aggregates
256
257 SELECT COUNT(*)
258 FROM users;
259
1060e1bd 260Finding out how many users exist can be achieved with a built-in method, B<count>.
6c2a4396 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
1060e1bd 268=item 2. Call the B<count> method on the resultset for the L<ResultSource|DBIx::Class::ResultSource> you wish to fetch data from:
6c2a4396 269
270 my $posts_count = $schema->resultset('Post')->count();
271
272=back
273
274The result is not an object, just a number.
275
276 SELECT SUM(amount)
277 FROM prices;
278
279A 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
1060e1bd 289 my $sum_prices = $schema->resultset('Price')->get_column('amount')->sum();
6c2a4396 290
291=back
292
293The result is just a number.
294
1060e1bd 295The alternative way uses the B<search> method and is easier to build further refinements into.
6c2a4396 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 { },
abc32120 307 { columns => { sum_amount => { SUM => 'amount'} } },
6c2a4396 308 );
309
310=back
311
312The 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
322To 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 { },
abc32120 334 { columns => [ qw/id username posts.id posts.title/ ],
6c2a4396 335 join => 'posts',
336 }
337 );
338
339=back
340
341Here "posts" refers to the name of the L<Relationship|DBIx::Class::Relationship> between the "User" source and the "Post" source.
342
343To 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
abc32120 359To 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.
6c2a4396 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
1060e1bd 367=item 2. Call the B<search> method on the resultset of the L<ResultSource|DBIx::Class::ResultSource> you wish to group data on:
6c2a4396 368
369 my $posts_count_per_user = $schema->resultset('User')->search(
370 { },
abc32120 371 { columns => [ qw/id username/, { post_count => { count => 'posts.id' } } ],
6c2a4396 372 join => 'posts',
373 group_by => [qw/id username/],
374 }
375 );
376
377=back
378
379Here "posts" refers to the name of the L<Relationship|DBIx::Class::Relationship> between the "User" source and the "Post" source.
380
381The 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
387Note: Remember to disambiguate the columns when joining two tables with identical column names.
388
0e8be732 389=begin comment
6c2a4396 390
0e8be732 391Commented out section as ordering by a related source does not work yet. Fix in progress, will comment back in when DBIC is updated.
6c2a4396 392
0e8be732 393 =head2 SELECT with simple ORDER BY
6c2a4396 394
0e8be732 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;
6c2a4396 399
0e8be732 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
6c2a4396 401
0e8be732 402 =over
6c2a4396 403
0e8be732 404 =item 1. Create a Schema object representing the database you are working with:
6c2a4396 405
0e8be732 406 my $schema = MyDatabase::Schema->connect('dbi:SQLite:my.db');
6c2a4396 407
0e8be732 408 =item 2. Call the B<search> method on the resultset of the L<ResultSource|DBIx::Class::ResultSource> you wish to sort data on:
6c2a4396 409
0e8be732 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 );
6c2a4396 417
0e8be732 418 =back
6c2a4396 419
0e8be732 420 Here "posts" refers to the name of the L<Relationship|DBIx::Class::Relationship> between the "User" source and the "Post" source.
6c2a4396 421
0e8be732 422 The results will be ordered by username, then post title, ready for outputting.
6c2a4396 423
0e8be732 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
6c2a4396 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
abc32120 441 GROUP BY users.id, username, dob
6c2a4396 442 HAVING count(posts.id) = 1
443
444To 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 { },
abc32120 456 { 'columns' => [ qw/me.id me.username me.dob/ ],
6c2a4396 457 join => 'posts',
abc32120 458 group_by => [qw/me.id me.username me.dob/],
6c2a4396 459 having => [{ 'posts.id' => 1 }],
460 }
461 );
462
463=back
464
465Here "posts" refers to the name of the L<Relationship|DBIx::Class::Relationship> between the "User" source and the "Post" source.
466
467The results will be filtered by the HAVING clause.
468
469=head2 SELECT with DISTINCT
470
471 SELECT DISTINCT(posts.title)
472 FROM posts
473
abc32120 474To produce DISTINCT clauses, we need to use a hashref argument to the list of items passed to the B<columns> attribute.
6c2a4396 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
abc32120 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:
6c2a4396 483
484 my $distinct_posts = $schema->resultset('Post')->search(
485 { },
abc32120 486 { columns => [{ 'd_title' => { distinct => 'me.title' } }],
6c2a4396 487 }
488 );
489
490=back
491
abc32120 492This 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.
6c2a4396 493
abc32120 494So 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
512The result will be an arrayref of the actual values. If a ResultSet object is needed for further refinement, use B<func_rs> instead.
6c2a4396 513
514=head2 SELECT ... FOR UPDATE
515
516 SELECT users.id, users.username, users.dob
517 FROM users
518 FOR UPDATE
519
1060e1bd 520To 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>.
6c2a4396 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
1060e1bd 539The 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.
6c2a4396 540
abc32120 541=head2 SELECT with LIMIT and OFFSET
6c2a4396 542
543 SELECT users.id, users.username
544 FROM users
545 ORDER BY user.dob DESC
abc32120 546 LIMIT 10 OFFSET 11;
6c2a4396 547
abc32120 548To 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.
6c2a4396 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,
abc32120 563 page => 2,
6c2a4396 564 }
565 );
566
abc32120 567This will return exactly 10 row objects, sorted by descending date of birth of the users, starting at the 11th row of the sorted result.
6c2a4396 568
569=back