I found out about a feature in SQL Server 2005 I didn’t know about (having come from a SQL Server 2000 shop). Cross Apply! It’s for when you want to feed the value of a table row into a function and join on the results. This is different than a cross join, because you cannot pass a table column value into a function when you do a cross join.
I whipped up a simple example. Let’s say we want the states that state with a certain letter (this is a trivial example because we could do this with a simple query as well).
1 2 3 4 5 6 7 8 9 10 11 12 13 | select * from letters cross apply dbo.get_StateByFirstLetter ( letters.letter ) where letters.letter between 'L' and 'M' -- equivalent to select * from dbo.get_StateByFirstLetter ( 'L' ) UNION select * from dbo.get_StateByFirstLetter ( 'M' ) -- equivalent to (which makes the above trivial) select * from [states] where left (state_name, 1) between 'L' and 'M' |
Full script to setup everything (pardon the sloppiness)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | -- setup the states table CREATE TABLE [states] ( state_name varchar (25), state_abbr char (2) ) INSERT INTO states VALUES ( 'Alaska' , 'AK' ); INSERT INTO states VALUES ( 'Alabama' , 'AL' ); INSERT INTO states VALUES ( 'American Samoa' , 'AS' ); INSERT INTO states VALUES ( 'Arizona' , 'AZ' ); INSERT INTO states VALUES ( 'Arkansas' , 'AR' ); INSERT INTO states VALUES ( 'California' , 'CA' ); INSERT INTO states VALUES ( 'Colorado' , 'CO' ); INSERT INTO states VALUES ( 'Connecticut' , 'CT' ); INSERT INTO states VALUES ( 'Delaware' , 'DE' ); INSERT INTO states VALUES ( 'District of Columbia' , 'DC' ); INSERT INTO states VALUES ( 'Florida' , 'FL' ); INSERT INTO states VALUES ( 'Georgia' , 'GA' ); INSERT INTO states VALUES ( 'Guam' , 'GU' ); INSERT INTO states VALUES ( 'Hawaii' , 'HI' ); INSERT INTO states VALUES ( 'Idaho' , 'ID' ); INSERT INTO states VALUES ( 'Illinois' , 'IL' ); INSERT INTO states VALUES ( 'Indiana' , 'IN' ); INSERT INTO states VALUES ( 'Iowa' , 'IA' ); INSERT INTO states VALUES ( 'Kansas' , 'KS' ); INSERT INTO states VALUES ( 'Kentucky' , 'KY' ); INSERT INTO states VALUES ( 'Louisiana' , 'LA' ); INSERT INTO states VALUES ( 'Maine' , 'ME' ); INSERT INTO states VALUES ( 'Marshall Islands' , 'MH' ); INSERT INTO states VALUES ( 'Maryland' , 'MD' ); INSERT INTO states VALUES ( 'Massachusetts' , 'MA' ); INSERT INTO states VALUES ( 'Michigan' , 'MI' ); INSERT INTO states VALUES ( 'Minnesota' , 'MN' ); INSERT INTO states VALUES ( 'Mississippi' , 'MS' ); INSERT INTO states VALUES ( 'Missouri' , 'MO' ); INSERT INTO states VALUES ( 'Montana' , 'MT' ); INSERT INTO states VALUES ( 'Nebraska' , 'NE' ); INSERT INTO states VALUES ( 'Nevada' , 'NV' ); INSERT INTO states VALUES ( 'New Hampshire' , 'NH' ); INSERT INTO states VALUES ( 'New Jersey' , 'NJ' ); INSERT INTO states VALUES ( 'New Mexico' , 'NM' ); INSERT INTO states VALUES ( 'New York' , 'NY' ); INSERT INTO states VALUES ( 'North Carolina' , 'NC' ); INSERT INTO states VALUES ( 'North Dakota' , 'ND' ); INSERT INTO states VALUES ( 'Ohio' , 'OH' ); INSERT INTO states VALUES ( 'Oklahoma' , 'OK' ); INSERT INTO states VALUES ( 'Oregon' , 'OR' ); INSERT INTO states VALUES ( 'Palau' , 'PW' ); INSERT INTO states VALUES ( 'Pennsylvania' , 'PA' ); INSERT INTO states VALUES ( 'Puerto Rico' , 'PR' ); INSERT INTO states VALUES ( 'Rhode Island' , 'RI' ); INSERT INTO states VALUES ( 'South Carolina' , 'SC' ); INSERT INTO states VALUES ( 'South Dakota' , 'SD' ); INSERT INTO states VALUES ( 'Tennessee' , 'TN' ); INSERT INTO states VALUES ( 'Texas' , 'TX' ); INSERT INTO states VALUES ( 'Utah' , 'UT' ); INSERT INTO states VALUES ( 'Vermont' , 'VT' ); INSERT INTO states VALUES ( 'Virgin Islands' , 'VI' ); INSERT INTO states VALUES ( 'Virginia' , 'VA' ); INSERT INTO states VALUES ( 'Washington' , 'WA' ); INSERT INTO states VALUES ( 'West Virginia' , 'WV' ); INSERT INTO states VALUES ( 'Wisconsin' , 'WI' ); INSERT INTO states VALUES ( 'Wyoming' , 'WY' ); GO -- create the function which we are applying create function dbo.get_StateByFirstLetter(@firstLetter char (1)) RETURNS @rtn TABLE ( state_name varchar (25), state_abbr char (2) ) AS bEGIN insert into @rtn select state_name, state_abbr from states where left (state_name,1) = @firstLetter return END GO -- generate letters table create table letters ( letter char (1) PRIMARY KEY ) with gen_letters as ( select 65 as ascii_val UNION ALL SELECT ascii_val + 1 from gen_letters where ascii_val + 1 <= 90 ) insert into letters select char (ascii_val) from gen_letters -- get results by cross applying select * from letters cross apply dbo.get_StateByFirstLetter ( letters.letter ) where letters.letter between 'L' and 'M' -- equivalent to select * from dbo.get_StateByFirstLetter ( 'L' ) UNION select * from dbo.get_StateByFirstLetter ( 'M' ) |
And for good measure, using the WITH clause to generate a table of letters:
1 2 3 4 5 6 7 | with gen_letters as ( select 65 as ascii_val UNION ALL SELECT ascii_val + 1 from gen_letters where ascii_val + 1 <= 90 ) insert into letters select char (ascii_val) from gen_letters |
Blog: Sql Cross Apply /programming/sql-cross-apply/
This comment was originally posted on Twitter