1SQL::Abstract(3) User Contributed Perl Documentation SQL::Abstract(3)
2
3
4
6 SQL::Abstract - Generate SQL from Perl data structures
7
9 use SQL::Abstract;
10
11 my $sql = SQL::Abstract->new;
12
13 my($stmt, @bind) = $sql->select($table, \@fields, \%where, \@order);
14
15 my($stmt, @bind) = $sql->insert($table, \%fieldvals ⎪⎪ \@values);
16
17 my($stmt, @bind) = $sql->update($table, \%fieldvals, \%where);
18
19 my($stmt, @bind) = $sql->delete($table, \%where);
20
21 # Then, use these in your DBI statements
22 my $sth = $dbh->prepare($stmt);
23 $sth->execute(@bind);
24
25 # Just generate the WHERE clause
26 my($stmt, @bind) = $sql->where(\%where, \@order);
27
28 # Return values in the same order, for hashed queries
29 # See PERFORMANCE section for more details
30 my @bind = $sql->values(\%fieldvals);
31
33 This module was inspired by the excellent DBIx::Abstract. However, in
34 using that module I found that what I really wanted to do was generate
35 SQL, but still retain complete control over my statement handles and
36 use the DBI interface. So, I set out to create an abstract SQL genera‐
37 tion module.
38
39 While based on the concepts used by DBIx::Abstract, there are several
40 important differences, especially when it comes to WHERE clauses. I
41 have modified the concepts used to make the SQL easier to generate from
42 Perl data structures and, IMO, more intuitive. The underlying idea is
43 for this module to do what you mean, based on the data structures you
44 provide it. The big advantage is that you don't have to modify your
45 code every time your data changes, as this module figures it out.
46
47 To begin with, an SQL INSERT is as easy as just specifying a hash of
48 "key=value" pairs:
49
50 my %data = (
51 name => 'Jimbo Bobson',
52 phone => '123-456-7890',
53 address => '42 Sister Lane',
54 city => 'St. Louis',
55 state => 'Louisiana',
56 );
57
58 The SQL can then be generated with this:
59
60 my($stmt, @bind) = $sql->insert('people', \%data);
61
62 Which would give you something like this:
63
64 $stmt = "INSERT INTO people
65 (address, city, name, phone, state)
66 VALUES (?, ?, ?, ?, ?)";
67 @bind = ('42 Sister Lane', 'St. Louis', 'Jimbo Bobson',
68 '123-456-7890', 'Louisiana');
69
70 These are then used directly in your DBI code:
71
72 my $sth = $dbh->prepare($stmt);
73 $sth->execute(@bind);
74
75 In addition, you can apply SQL functions to elements of your %data by
76 specifying an arrayref for the given hash value. For example, if you
77 need to execute the Oracle "to_date" function on a value, you can say
78 something like this:
79
80 my %data = (
81 name => 'Bill',
82 date_entered => ["to_date(?,'MM/DD/YYYY')", "03/02/2003"],
83 );
84
85 The first value in the array is the actual SQL. Any other values are
86 optional and would be included in the bind values array. This gives
87 you:
88
89 my($stmt, @bind) = $sql->insert('people', \%data);
90
91 $stmt = "INSERT INTO people (name, date_entered)
92 VALUES (?, to_date(?,'MM/DD/YYYY'))";
93 @bind = ('Bill', '03/02/2003');
94
95 An UPDATE is just as easy, all you change is the name of the function:
96
97 my($stmt, @bind) = $sql->update('people', \%data);
98
99 Notice that your %data isn't touched; the module will generate the
100 appropriately quirky SQL for you automatically. Usually you'll want to
101 specify a WHERE clause for your UPDATE, though, which is where handling
102 %where hashes comes in handy...
103
104 This module can generate pretty complicated WHERE statements easily.
105 For example, simple "key=value" pairs are taken to mean equality, and
106 if you want to see if a field is within a set of values, you can use an
107 arrayref. Let's say we wanted to SELECT some data based on this crite‐
108 ria:
109
110 my %where = (
111 requestor => 'inna',
112 worker => ['nwiger', 'rcwe', 'sfz'],
113 status => { '!=', 'completed' }
114 );
115
116 my($stmt, @bind) = $sql->select('tickets', '*', \%where);
117
118 The above would give you something like this:
119
120 $stmt = "SELECT * FROM tickets WHERE
121 ( requestor = ? ) AND ( status != ? )
122 AND ( worker = ? OR worker = ? OR worker = ? )";
123 @bind = ('inna', 'completed', 'nwiger', 'rcwe', 'sfz');
124
125 Which you could then use in DBI code like so:
126
127 my $sth = $dbh->prepare($stmt);
128 $sth->execute(@bind);
129
130 Easy, eh?
131
133 The functions are simple. There's one for each major SQL operation, and
134 a constructor you use first. The arguments are specified in a similar
135 order to each function (table, then fields, then a where clause) to try
136 and simplify things.
137
138 new(option => 'value')
139
140 The "new()" function takes a list of options and values, and returns a
141 new SQL::Abstract object which can then be used to generate SQL through
142 the methods below. The options accepted are:
143
144 case
145 If set to 'lower', then SQL will be generated in all lowercase. By
146 default SQL is generated in "textbook" case meaning something like:
147
148 SELECT a_field FROM a_table WHERE some_field LIKE '%someval%'
149
150 cmp This determines what the default comparison operator is. By default
151 it is "=", meaning that a hash like this:
152
153 %where = (name => 'nwiger', email => 'nate@wiger.org');
154
155 Will generate SQL like this:
156
157 WHERE name = 'nwiger' AND email = 'nate@wiger.org'
158
159 However, you may want loose comparisons by default, so if you set
160 "cmp" to "like" you would get SQL such as:
161
162 WHERE name like 'nwiger' AND email like 'nate@wiger.org'
163
164 You can also override the comparsion on an individual basis - see
165 the huge section on "WHERE CLAUSES" at the bottom.
166
167 logic
168 This determines the default logical operator for multiple WHERE
169 statements in arrays. By default it is "or", meaning that a WHERE
170 array of the form:
171
172 @where = (
173 event_date => {'>=', '2/13/99'},
174 event_date => {'<=', '4/24/03'},
175 );
176
177 Will generate SQL like this:
178
179 WHERE event_date >= '2/13/99' OR event_date <= '4/24/03'
180
181 This is probably not what you want given this query, though (look
182 at the dates). To change the "OR" to an "AND", simply specify:
183
184 my $sql = SQL::Abstract->new(logic => 'and');
185
186 Which will change the above "WHERE" to:
187
188 WHERE event_date >= '2/13/99' AND event_date <= '4/24/03'
189
190 convert
191 This will automatically convert comparisons using the specified SQL
192 function for both column and value. This is mostly used with an
193 argument of "upper" or "lower", so that the SQL will have the
194 effect of case-insensitive "searches". For example, this:
195
196 $sql = SQL::Abstract->new(convert => 'upper');
197 %where = (keywords => 'MaKe iT CAse inSeNSItive');
198
199 Will turn out the following SQL:
200
201 WHERE upper(keywords) like upper('MaKe iT CAse inSeNSItive')
202
203 The conversion can be "upper()", "lower()", or any other SQL func‐
204 tion that can be applied symmetrically to fields (actually
205 SQL::Abstract does not validate this option; it will just pass
206 through what you specify verbatim).
207
208 bindtype
209 This is a kludge because many databases suck. For example, you
210 can't just bind values using DBI's "execute()" for Oracle "CLOB" or
211 "BLOB" fields. Instead, you have to use "bind_param()":
212
213 $sth->bind_param(1, 'reg data');
214 $sth->bind_param(2, $lots, {ora_type => ORA_CLOB});
215
216 The problem is, SQL::Abstract will normally just return a @bind
217 array, which loses track of which field each slot refers to. Fear
218 not.
219
220 If you specify "bindtype" in new, you can determine how @bind is
221 returned. Currently, you can specify either "normal" (default) or
222 "columns". If you specify "columns", you will get an array that
223 looks like this:
224
225 my $sql = SQL::Abstract->new(bindtype => 'columns');
226 my($stmt, @bind) = $sql->insert(...);
227
228 @bind = (
229 [ 'column1', 'value1' ],
230 [ 'column2', 'value2' ],
231 [ 'column3', 'value3' ],
232 );
233
234 You can then iterate through this manually, using DBI's
235 "bind_param()".
236
237 $sth->prepare($stmt);
238 my $i = 1;
239 for (@bind) {
240 my($col, $data) = @$_;
241 if ($col eq 'details' ⎪⎪ $col eq 'comments') {
242 $sth->bind_param($i, $data, {ora_type => ORA_CLOB});
243 } elsif ($col eq 'image') {
244 $sth->bind_param($i, $data, {ora_type => ORA_BLOB});
245 } else {
246 $sth->bind_param($i, $data);
247 }
248 $i++;
249 }
250 $sth->execute; # execute without @bind now
251
252 Now, why would you still use SQL::Abstract if you have to do this
253 crap? Basically, the advantage is still that you don't have to
254 care which fields are or are not included. You could wrap that
255 above "for" loop in a simple sub called "bind_fields()" or some‐
256 thing and reuse it repeatedly. You still get a layer of abstraction
257 over manual SQL specification.
258
259 quote_char
260 This is the character that a table or column name will be quoted
261 with. By default this is an empty string, but you could set it to
262 the character "`", to generate SQL like this:
263
264 SELECT `a_field` FROM `a_table` WHERE `some_field` LIKE '%someval%'
265
266 This is useful if you have tables or columns that are reserved
267 words in your database's SQL dialect.
268
269 name_sep
270 This is the character that separates a table and column name. It
271 is necessary to specify this when the "quote_char" option is
272 selected, so that tables and column names can be individually
273 quoted like this:
274
275 SELECT `table`.`one_field` FROM `table` WHERE `table`.`other_field` = 1
276
277 insert($table, \@values ⎪⎪ \%fieldvals)
278
279 This is the simplest function. You simply give it a table name and
280 either an arrayref of values or hashref of field/value pairs. It
281 returns an SQL INSERT statement and a list of bind values.
282
283 update($table, \%fieldvals, \%where)
284
285 This takes a table, hashref of field/value pairs, and an optional
286 hashref WHERE clause. It returns an SQL UPDATE function and a list of
287 bind values.
288
289 select($table, \@fields, \%where, \@order)
290
291 This takes a table, arrayref of fields (or '*'), optional hashref WHERE
292 clause, and optional arrayref order by, and returns the corresponding
293 SQL SELECT statement and list of bind values.
294
295 delete($table, \%where)
296
297 This takes a table name and optional hashref WHERE clause. It returns
298 an SQL DELETE statement and list of bind values.
299
300 where(\%where, \@order)
301
302 This is used to generate just the WHERE clause. For example, if you
303 have an arbitrary data structure and know what the rest of your SQL is
304 going to look like, but want an easy way to produce a WHERE clause, use
305 this. It returns an SQL WHERE clause and list of bind values.
306
307 values(\%data)
308
309 This just returns the values from the hash %data, in the same order
310 that would be returned from any of the other above queries. Using this
311 allows you to markedly speed up your queries if you are affecting lots
312 of rows. See below under the "PERFORMANCE" section.
313
314 generate($any, 'number', $of, \@data, $struct, \%types)
315
316 Warning: This is an experimental method and subject to change.
317
318 This returns arbitrarily generated SQL. It's a really basic shortcut.
319 It will return two different things, depending on return context:
320
321 my($stmt, @bind) = $sql->generate('create table', \$table, \@fields);
322 my $stmt_and_val = $sql->generate('create table', \$table, \@fields);
323
324 These would return the following:
325
326 # First calling form
327 $stmt = "CREATE TABLE test (?, ?)";
328 @bind = (field1, field2);
329
330 # Second calling form
331 $stmt_and_val = "CREATE TABLE test (field1, field2)";
332
333 Depending on what you're trying to do, it's up to you to choose the
334 correct format. In this example, the second form is what you would
335 want.
336
337 By the same token:
338
339 $sql->generate('alter session', { nls_date_format => 'MM/YY' });
340
341 Might give you:
342
343 ALTER SESSION SET nls_date_format = 'MM/YY'
344
345 You get the idea. Strings get their case twiddled, but everything else
346 remains verbatim.
347
349 This module uses a variation on the idea from DBIx::Abstract. It is
350 NOT, repeat not 100% compatible. The main logic of this module is that
351 things in arrays are OR'ed, and things in hashes are AND'ed.
352
353 The easiest way to explain is to show lots of examples. After each
354 %where hash shown, it is assumed you used:
355
356 my($stmt, @bind) = $sql->where(\%where);
357
358 However, note that the %where hash can be used directly in any of the
359 other functions as well, as described above.
360
361 So, let's get started. To begin, a simple hash:
362
363 my %where = (
364 user => 'nwiger',
365 status => 'completed'
366 );
367
368 Is converted to SQL "key = val" statements:
369
370 $stmt = "WHERE user = ? AND status = ?";
371 @bind = ('nwiger', 'completed');
372
373 One common thing I end up doing is having a list of values that a field
374 can be in. To do this, simply specify a list inside of an arrayref:
375
376 my %where = (
377 user => 'nwiger',
378 status => ['assigned', 'in-progress', 'pending'];
379 );
380
381 This simple code will create the following:
382
383 $stmt = "WHERE user = ? AND ( status = ? OR status = ? OR status = ? )";
384 @bind = ('nwiger', 'assigned', 'in-progress', 'pending');
385
386 If you want to specify a different type of operator for your compari‐
387 son, you can use a hashref for a given column:
388
389 my %where = (
390 user => 'nwiger',
391 status => { '!=', 'completed' }
392 );
393
394 Which would generate:
395
396 $stmt = "WHERE user = ? AND status != ?";
397 @bind = ('nwiger', 'completed');
398
399 To test against multiple values, just enclose the values in an
400 arrayref:
401
402 status => { '!=', ['assigned', 'in-progress', 'pending'] };
403
404 Which would give you:
405
406 "WHERE status != ? OR status != ? OR status != ?"
407
408 But, this is probably not what you want in this case (look at it). So
409 the hashref can also contain multiple pairs, in which case it is
410 expanded into an "AND" of its elements:
411
412 my %where = (
413 user => 'nwiger',
414 status => { '!=', 'completed', -not_like => 'pending%' }
415 );
416
417 # Or more dynamically, like from a form
418 $where{user} = 'nwiger';
419 $where{status}{'!='} = 'completed';
420 $where{status}{'-not_like'} = 'pending%';
421
422 # Both generate this
423 $stmt = "WHERE user = ? AND status != ? AND status NOT LIKE ?";
424 @bind = ('nwiger', 'completed', 'pending%');
425
426 To get an OR instead, you can combine it with the arrayref idea:
427
428 my %where => (
429 user => 'nwiger',
430 priority => [ {'=', 2}, {'!=', 1} ]
431 );
432
433 Which would generate:
434
435 $stmt = "WHERE user = ? AND priority = ? OR priority != ?";
436 @bind = ('nwiger', '2', '1');
437
438 However, there is a subtle trap if you want to say something like this
439 (notice the "AND"):
440
441 WHERE priority != ? AND priority != ?
442
443 Because, in Perl you can't do this:
444
445 priority => { '!=', 2, '!=', 1 }
446
447 As the second "!=" key will obliterate the first. The solution is to
448 use the special "-modifier" form inside an arrayref:
449
450 priority => [ -and => {'!=', 2}, {'!=', 1} ]
451
452 Normally, these would be joined by "OR", but the modifier tells it to
453 use "AND" instead. (Hint: You can use this in conjunction with the
454 "logic" option to "new()" in order to change the way your queries work
455 by default.) Important: Note that the "-modifier" goes INSIDE the
456 arrayref, as an extra first element. This will NOT do what you think it
457 might:
458
459 priority => -and => [{'!=', 2}, {'!=', 1}] # WRONG!
460
461 Here is a quick list of equivalencies, since there is some overlap:
462
463 # Same
464 status => {'!=', 'completed', 'not like', 'pending%' }
465 status => [ -and => {'!=', 'completed'}, {'not like', 'pending%'}]
466
467 # Same
468 status => {'=', ['assigned', 'in-progress']}
469 status => [ -or => {'=', 'assigned'}, {'=', 'in-progress'}]
470 status => [ {'=', 'assigned'}, {'=', 'in-progress'} ]
471
472 In addition to "-and" and "-or", there is also a special "-nest" opera‐
473 tor which adds an additional set of parens, to create a subquery. For
474 example, to get something like this:
475
476 $stmt = WHERE user = ? AND ( workhrs > ? OR geo = ? )
477 @bind = ('nwiger', '20', 'ASIA');
478
479 You would do:
480
481 my %where = (
482 user => 'nwiger',
483 -nest => [ workhrs => {'>', 20}, geo => 'ASIA' ],
484 );
485
486 You can also use the hashref format to compare a list of fields using
487 the "IN" comparison operator, by specifying the list as an arrayref:
488
489 my %where = (
490 status => 'completed',
491 reportid => { -in => [567, 2335, 2] }
492 );
493
494 Which would generate:
495
496 $stmt = "WHERE status = ? AND reportid IN (?,?,?)";
497 @bind = ('completed', '567', '2335', '2');
498
499 You can use this same format to use other grouping functions, such as
500 "BETWEEN", "SOME", and so forth. For example:
501
502 my %where = (
503 user => 'nwiger',
504 completion_date => {
505 -not_between => ['2002-10-01', '2003-02-06']
506 }
507 );
508
509 Would give you:
510
511 WHERE user = ? AND completion_date NOT BETWEEN ( ? AND ? )
512
513 So far, we've seen how multiple conditions are joined with a top-level
514 "AND". We can change this by putting the different conditions we want
515 in hashes and then putting those hashes in an array. For example:
516
517 my @where = (
518 {
519 user => 'nwiger',
520 status => { -like => ['pending%', 'dispatched'] },
521 },
522 {
523 user => 'robot',
524 status => 'unassigned',
525 }
526 );
527
528 This data structure would create the following:
529
530 $stmt = "WHERE ( user = ? AND ( status LIKE ? OR status LIKE ? ) )
531 OR ( user = ? AND status = ? ) )";
532 @bind = ('nwiger', 'pending', 'dispatched', 'robot', 'unassigned');
533
534 This can be combined with the "-nest" operator to properly group SQL
535 statements:
536
537 my @where = (
538 -and => [
539 user => 'nwiger',
540 -nest => [
541 -and => [workhrs => {'>', 20}, geo => 'ASIA' ],
542 -and => [workhrs => {'<', 50}, geo => 'EURO' ]
543 ],
544 ],
545 );
546
547 That would yield:
548
549 WHERE ( user = ? AND
550 ( ( workhrs > ? AND geo = ? )
551 OR ( workhrs < ? AND geo = ? ) ) )
552
553 Finally, sometimes only literal SQL will do. If you want to include
554 literal SQL verbatim, you can specify it as a scalar reference, namely:
555
556 my $inn = 'is Not Null';
557 my %where = (
558 priority => { '<', 2 },
559 requestor => \$inn
560 );
561
562 This would create:
563
564 $stmt = "WHERE priority < ? AND requestor is Not Null";
565 @bind = ('2');
566
567 Note that in this example, you only get one bind parameter back, since
568 the verbatim SQL is passed as part of the statement.
569
570 Of course, just to prove a point, the above can also be accomplished
571 with this:
572
573 my %where = (
574 priority => { '<', 2 },
575 requestor => { '!=', undef },
576 );
577
578 TMTOWTDI.
579
580 These pages could go on for a while, since the nesting of the data
581 structures this module can handle are pretty much unlimited (the module
582 implements the "WHERE" expansion as a recursive function internally).
583 Your best bet is to "play around" with the module a little to see how
584 the data structures behave, and choose the best format for your data
585 based on that.
586
587 And of course, all the values above will probably be replaced with
588 variables gotten from forms or the command line. After all, if you knew
589 everything ahead of time, you wouldn't have to worry about dynamically-
590 generating SQL and could just hardwire it into your script.
591
593 Thanks to some benchmarking by Mark Stosberg, it turns out that this
594 module is many orders of magnitude faster than using "DBIx::Abstract".
595 I must admit this wasn't an intentional design issue, but it's a
596 byproduct of the fact that you get to control your "DBI" handles your‐
597 self.
598
599 To maximize performance, use a code snippet like the following:
600
601 # prepare a statement handle using the first row
602 # and then reuse it for the rest of the rows
603 my($sth, $stmt);
604 for my $href (@array_of_hashrefs) {
605 $stmt ⎪⎪= $sql->insert('table', $href);
606 $sth ⎪⎪= $dbh->prepare($stmt);
607 $sth->execute($sql->values($href));
608 }
609
610 The reason this works is because the keys in your $href are sorted
611 internally by SQL::Abstract. Thus, as long as your data retains the
612 same structure, you only have to generate the SQL the first time
613 around. On subsequent queries, simply use the "values" function pro‐
614 vided by this module to return your values in the correct order.
615
617 If you use my "CGI::FormBuilder" module at all, you'll hopefully really
618 like this part (I do, at least). Building up a complex query can be as
619 simple as the following:
620
621 #!/usr/bin/perl
622
623 use CGI::FormBuilder;
624 use SQL::Abstract;
625
626 my $form = CGI::FormBuilder->new(...);
627 my $sql = SQL::Abstract->new;
628
629 if ($form->submitted) {
630 my $field = $form->field;
631 my $id = delete $field->{id};
632 my($stmt, @bind) = $sql->update('table', $field, {id => $id});
633 }
634
635 Of course, you would still have to connect using "DBI" to run the
636 query, but the point is that if you make your form look like your ta‐
637 ble, the actual query script can be extremely simplistic.
638
639 If you're REALLY lazy (I am), check out "HTML::QuickTable" for a fast
640 interface to returning and formatting data. I frequently use these
641 three modules together to write complex database query apps in under 50
642 lines.
643
645 There is not (yet) any explicit support for SQL compound logic state‐
646 ments like "AND NOT". Instead, just do the de Morgan's law transforma‐
647 tions yourself. For example, this:
648
649 "lname LIKE '%son%' AND NOT ( age < 10 OR age > 20 )"
650
651 Becomes:
652
653 "lname LIKE '%son%' AND ( age >= 10 AND age <= 20 )"
654
655 With the corresponding %where hash:
656
657 %where = (
658 lname => {like => '%son%'},
659 age => [-and => {'>=', 10}, {'<=', 20}],
660 );
661
662 Again, remember that the "-and" goes inside the arrayref.
663
665 There are a number of individuals that have really helped out with this
666 module. Unfortunately, most of them submitted bugs via CPAN so I have
667 no idea who they are! But the people I do know are:
668
669 Mark Stosberg (benchmarking)
670 Chas Owens (initial "IN" operator support)
671 Philip Collins (per-field SQL functions)
672 Eric Kolve (hashref "AND" support)
673 Mike Fragassi (enhancements to "BETWEEN" and "LIKE")
674 Dan Kubb (support for "quote_char" and "name_sep")
675 Matt Trout (DBIx::Class support)
676
677 Thanks!
678
680 If found, please DO NOT submit anything via "rt.cpan.org" - that just
681 causes me a ton of work. Email me a patch (or script demonstrating the
682 problem) to the below address, and include the VERSION you're using.
683
685 DBIx::Abstract, DBI, CGI::FormBuilder, HTML::QuickTable
686
688 Copyright (c) 2001-2006 Nathan Wiger <nwiger@cpan.org>. All Rights
689 Reserved.
690
691 For support, your best bet is to try the "DBIx::Class" users mailing
692 list. While not an official support venue, "DBIx::Class" makes heavy
693 use of "SQL::Abstract", and as such list members there are very famil‐
694 iar with how to create queries.
695
696 This module is free software; you may copy this under the terms of the
697 GNU General Public License, or the Artistic License, copies of which
698 should have accompanied your Perl kit.
699
700
701
702perl v5.8.8 2006-11-30 SQL::Abstract(3)