using …

Pure C#

‘CTE’ Kategorisi için Arşiv

SQL Server 2005 Common Table

Yazan: esersahin 05/09/2009

http://www.simple-talk.com/sql/sql-server-2005/sql-server-2005-common-table-expressions/

In my opinion, Common Table Expressions (CTEs) are one of the most exciting features to be introduced with SQL Server 2005. A CTE is a “temporary result set” that exists only within the scope of a single SQL statement. It allows access to functionality within that single SQL statement that was previously only available through use of functions, temp tables, cursors, and so on.

CTE basics

The concept behind a CTE is simplicity itself. Consider the following statement:

with MyCTE(x)
as
(select x='hello')
select x from MyCTE

This defines a CTE called MyCTE. In brackets after the as keyword is the query that defines the CTE. The subsequent query references our CTE, in this case simply returning the string “hello”.

Like a derived table, a CTE lasts only for the duration of a query but, in contrast to a derived table, a CTE can be referenced multiple times in the same query. So, we now we have a way of calculating percentages and performing arithmetic using aggregates without repeating queries or using a temp table:

with MyCTE(x)
as
(
select top 10 x = id from sysobjects
)
select x, maxx = (select max(x) from MyCTE), pct =
                    100.0 * x / (select sum(x) from MyCTE)
from MyCTE

This returns (on my system):

x           maxx         pct
4           2137058649   2.515723270440
5           2137058649   3.144654088050
7           2137058649   4.402515723270
8           2137058649   5.031446540880
13          2137058649   8.176100628930
15          2137058649   9.433962264150
25          2137058649   15.723270440251
26          2137058649   16.352201257861
27          2137058649   16.981132075471
29          2137058649   18.238993710691

Note that although this has only referenced sysobjects once in the CTE, the query plan will confirm that sysobjects is actually scanned 3 times – each aggregate in the result set causes an additional scan. As a result, it would still be more efficient to accumulate the values in a temporary table or table variable if you are accessing large tables.

CTE and recursion

More interesting, in my opinion, is the use of recursion with CTEs. The table defined in the CTE can be referenced in the CTE itself to give a recursive expression, using union all:

with MyCTE(x)
as
(
select x = convert(varchar(8000),'hello')
union all
select x + 'a' from MyCTE where len(x) < 100
)
select x from MyCTE
order by x

The query:

select x = convert(varchar(8000),’hello’)

is called the anchor member. This is executed in the first pass and will populate the CTE with the result, in this case hello. This initial CTE is repeatedly executed until the complete result set is returned. The next entry:

select x + ‘a’ from MyCTE where len(x) < 100

is a recursive member as it references the CTE, MyCTE. The recursive member is executed with the anchor member output to give helloa. The next pass takes helloa as input and returns helloaa, and so on so that we arrive at a CTE populated with rows as follows:

hello
helloa
helloaa
helloaaa
helloaaaa
…

The recursion will terminate when the recursive member produces no rows – in this case recursion stops when the length of x equals 99 – or when the recursion limit is reached (more about that later). The CTE is then output by the following statement:

select x from MyCTE
order by x

There are a few interesting issues associated with even this simple CTE usage. Note that the anchor member populates the CTE with a varchar(8000). Had the convert not been included then you would expect the datatype of x to be defined by that of the anchor member (varchar(5)) and to give an error when trying to insert the longer recursive entries. This does indeed happen – but you would expect varchar(1000) to be fine. Not so. This still produces the error that the datatypes don’t match. In fact, you should always cast the recursive member output to be the same as the anchor member:

with MyCTE(x)
as
(
select x = convert(varchar(1000),'hello')
union all
select convert(varchar(1000),x + 'a') from MyCTE
   where len(x) < 100
)
select x from MyCTE
order by x

But why, then, did the code work with varchar(8000)? This looks like a bug. As far as I can tell varchar(8000) and nvarchar(4000) seem to be the only values that work. Varchar(max) and varchar(7999) give an error as do all the other values that I have tried.

Multiple anchor members

Any entry that does not reference the CTE will be considered an anchor member so we can also include multiple anchor members using a union all:

with MyCTE(x)
as
(
select x = convert(varchar(1000),'hello')
union all
select x = convert(varchar(1000),'goodbye')
union all
select convert(varchar(1000),x + 'a') from MyCTE
   where len(x) < 10
)
select x from MyCTE
order by len(x), x

This adds two rows from the anchor members and hence the recursive member acts on two rows for each pass to produce the output:

hello
helloa
goodbye
helloaa
goodbyea
helloaaa
goodbyeaa
helloaaaa
goodbyeaaa
helloaaaaa

The first recursive pass produces the output “helloa” and “goodbyea”. The second produces “helloaa” and “goodbyeaa”. The third produces “helloaaa” and “goodbyeaaa”. For subsequent passes the string containing “goodbye” is too long for the check len(x)<10 but recursion continues as long as some output is produced – so we get more entries from hello than goodbye.

Multiple recursive members

We can also include multiple recursive members to produce extra rows at each pass:

with MyCTE(x)
as
(
select x = convert(varchar(1000),'hello')
union all
select convert(varchar(1000),x + 'a') from MyCTE where len(x) < 10
union all
select convert(varchar(1000),x + 'b') from MyCTE where len(x) < 10
)
select x from MyCTE
order by len(x), x

This produces the result:

hello
helloa
hellob
helloaa
helloab
helloba
hellobb
helloaaa
helloaab
helloaba
helloabb
hellobaa
hellobab
hellobba
hellobbb
helloaaaa
….
63 rows of output.

In order to understand this output, you need to remember that the input to each pass is the output from the previous pass. On the first recursive pass the input is the row from the anchor member. This produces two rows – one from each recursive member. On the next pass the input is the two rows output from the previous pass. Each recursive member outputs two rows producing four in total. In other words, the number of rows output doubles with each pass.

We can modify the output by limiting the rows on which the recursive members act. For example:

with MyCTE(x)
as
(
select x = convert(varchar(1000),'hello')
union all
select convert(varchar(1000),x + 'a') from MyCTE
   where len(x) < 10 and (len(x) = 5 or x like '%a')
union all
select convert(varchar(1000),x + 'b') from MyCTE
   where len(x) < 10 and (len(x) = 5 or x like '%b')
)
select x from MyCTE
order by len(x), x

giving:

hello
helloa
hellob
helloaa
hellobb
helloaaa
hellobbb
helloaaaa
hellobbbb
helloaaaaa
hellobbbbb

Another method is to flag the recursive members:

with MyCTE(i, x)
as
(
select i = 0, x = convert(varchar(1000),'hello')
union all
select i = 1, convert(varchar(1000),x + 'a') from MyCTE
   where len(x) < 10 and i in (0,1)
union all
select i = 2, convert(varchar(1000),x + 'b') from MyCTE
   where len(x) < 10 and i in (0,2)
)
select x from MyCTE
order by len(x), x

This gives the same result as above. It forces each recursive member to act only on the anchor member output and on any output that it itself has produced. This is at the expense of including the redundant data column “i” in the CTE but it does make the code a lot more readable. Using a similar technique we can output a value to indicate which pass produces each row:

with MyCTE(r1, r2, i, x)
as
(
select r1 = 1, r2 = 1, i = 0, x = convert(varchar(1000),'hello')
union all
select r1 = r1 + 1, r2 = r2, i = 1, convert(varchar(1000),x + 'a') from MyCTE
   where len(x) < 10 and i in (0,1)
union all
select r1 = r1, r2 = r2 + 1, i = 2, convert(varchar(1000),x + 'b') from MyCTE
   where len(x) < 10 and i in (0,2)
)
select r1, r2, x from MyCTE
order by len(x), x

This returns the following, r1 giving the pass number for the first recursive member and r2 for the second:

r1          r2          x
1           1           hello
2           1           helloa
1           2           hellob
3           1           helloaa
1           3           hellobb
4           1           helloaaa
1           4           hellobbb
5           1           helloaaaa
1           5           hellobbbb
6           1           helloaaaaa
1           6           hellobbbbb

This is very useful for debugging and also for detecting how a CTE is processed and for controlling the number of passes for each recursive member. For instance:

with MyCTE(r1, r2, i, x)
as
(
select r1 = 1, r2 = 1, i = 0, x = convert(varchar(1000),'hello')
union all
select r1 = r1 + 1, r2 = r2, i = 1, convert(varchar(1000),x + 'a') from MyCTE
   where i in (0,1) and R1 < 3
union all
select r1 = r1, r2 = r2 + 1, i = 2, convert(varchar(1000),x + 'b') from MyCTE
   where i in (0,2) and R2 < 6
)
select r1, r2, x from MyCTE
order by len(x), x

Here I have terminated the first recursive member after two iterations and the second after five, giving:

1           1           hello
2           1           helloa
1           2           hellob
3           1           helloaa
1           3           hellobb
1           4           hellobbb
1           5           hellobbbb
1           6           hellobbbbb

Note that recursion continues until a pass produces no output – although the first recursive member terminates early recursion continues until both recursive members produce no output.

Recursion limit

In order to demonstrate the recursion limit, we start by producing a series of numbers in a CTE:

with MyCTE(i)
as
(
select i = 1
union all
select i = i + 1 from MyCTE where i < 100
)
select i
from MyCTE
order by i

This happily produces the numbers 1 to 100 (a tally table). However, try increasing the recursion limit as follows:

with MyCTE(i)
as
(
select i = 1
union all
select i = i + 1 from MyCTE where i < 1000
)
select i
from MyCTE
order by i

You will receive the following error:

The statement terminated. The maximum recursion 100 has been exhausted before statement completion

It sounds like there is a limit of 100 for recursion but luckily this is just the default limit. For development this is very useful; to save time and space consider setting it lower for first attempts.

The maximum number of recursions can be set via the maxrecursion option, up to a maximum of 32767 (wouldn’t it be nice, though, if the error message suggested that the recursion limit should be increased?):

with MyCTE(i)
as
(
select i = 1
union all
select i = i + 1 from MyCTE where i < 1000
)
select i
from MyCTE
order by i
option (maxrecursion 1000)

Uses for Common Table Expressions

Finally, let’s review some of the more interesting applications of CTEs.

Traversing a hierarchy

This is covered well in BOL and now gives SQL Server something to compete with the Oracle connect by operator.

Date Ranges

A common requirement is to aggregate entries per day (or month or year). This is easy using a group by, if there are entries for every day:

declare @Sales table (TrDate datetime, Amount money)
insert @Sales select '20060501', 200
insert @Sales select '20060501', 400
insert @Sales select '20060502', 1200

select [day] = TrDate, sum(amount) total_sales
from @sales
group by TrDate
order by TrDate

giving:

day                       total_sales
2006-05-01 00:00:00.000   600.00
2006-05-02 00:00:00.000   1200.00

However, if there are some days with no transactions the result set, rather than report zero, does not give an entry for that day. To get round this we need to left join to a tally table which includes the days on which we wish to report. With a CTE this becomes simple. For example, for a year:

declare @Sales table (TrDate datetime, Amount money)
insert @Sales select '20060501', 200
insert @Sales select '20060501', 400
insert @Sales select '20060502', 1200

;with MyCTE(d)
as
(
select d = convert(datetime,'20060101')
union all
select d = d + 1 from MyCTE where d < '20061231'
)
select [day] = d.d, sum(coalesce(s.amount,0))
from MyCTE d
left join @sales s
on s.TrDate = d.d
group by d.d
order by d.d
option (maxrecursion 1000)

Note the “;” before the CTE definition – that’s just a syntax requirement if the CTE declaration is not the first statement in a batch.

Parsing CSV values

It is common to pass a CSV string in to a stored procedure as a means of passing in an array of values. Often this is turned into a table via a function. Using a CTE we can now contain this code within the stored procedure:

declare @s varchar(1000)
select @s = 'a,b,cd,ef,zzz,hello'

;with csvtbl(i,j)
as
(
select i=1, j=charindex(',',@s+',')
union all
select i=j+1, j=charindex(',',@s+',',j+1) from csvtbl
   where charindex(',',@s+',',j+1) <> 0
)
select substring(@s,i,j-i)
from csvtbl

The output is as follows:

a
b
cd
ef
zzz
hello

How does this work? The anchor member, select i=1, j=charindex(‘,’,@s+’,'), returns 1 and the location of the first comma. The recursive member gives the location of the first character after the comma and the location of the next comma (we append a comma to the string to get the last entry). The result set is then obtained by using these values in a substring.

In the previous example the CTE output was the start and end locations of each of the strings. We can instead produce the strings themselves; the CTE code becomes a little more complicated but the following query is simplified:

declare @s varchar(1000)
select @s = 'a,b,cd,ef,zzz,hello'

;with csvtbl(i,j, s)
as
(
select i=1, s=charindex(',',@s+','),
   substring(@s, 1, charindex(',',@s+',')-1)
union all
select i=j+1, j=charindex(',',@s+',',j+1),
   substring(@s, j+1, charindex(',',@s+',',j+1)-(j+1))
from csvtbl where charindex(',',@s+',',j+1) <> 0
)
select s from csvtbl

Beyond 32767

What happens if you want a list of numbers that extends beyond 32767? Although the recursion limit is 32767 it is possible to create extra entries. For example, the following CTE returns all the numbers from 0 to 64000. The result set produced is used to check the results. The maximum and count verify that all of the numbers are present, assuming that the result is a sequence:

with n(rc,i)
as
(
select rc = 1, i = 0
union all
select rc = 1, i = i + 1 from n where rc = 1 and i < 32000
union all
select rc = 2, i = i + 32001 from n where rc = 1 and i < 32000
)
select count_i = count(*), max_i = max(i)
from n
option (maxrecursion 32000)

To take this a step further we can accumulate values by manipulating the CTE:

with n (j)
as 
( 
select j = 0
union all
select j = j + 1 from n where j < 32000
)
select max_i = max (na.i), count_i = count(*)
from ( select i = j + k
   from n
   cross join
   ( select k = j * 32001
      from n
      where j < 32
   ) n2
) na
option (maxrecursion 32000)

giving:

max_i       count_i
----------- -------
1024031     1024032

In other words, this returns all the numbers from 0 to 1024031. How does this work? The derived table, n2, consists of all the numbers from 0 to 32 multiplied by 32001, i.e.

0
32001
64002
96003
….

This is cross-joined with the result of the CTE, n, which consists of all the numbers from 0 to 32000, and the result is the sum of the values from n and n2. Hence we get:

from n 0- 32000 with 0 from n2 to give 0 – 32000
from n 0- 32000 with 32001 from n2 to give 32001 – 64001
from n 0- 32000 with 64002 from n2 to give 64002 – 96002
from n 0- 32000 with 96003 from n2 to give 64003 – 96003
…..

to give the values 0 – 1,024,031. If more values are required then just increase the size of n2 by increasing the maximum value from 32.

Yazı kategorisi: CTE | » yorum bırak;

SQL Server / T-SQL Tutorial

Yazan: esersahin 20/03/2009

http://www.java2s.com/Tutorial/SQLServer/CatalogSQLServer.htm

1. Query
1. 1. Query Select( 18 ) 1. 17. ANY( 6 )
1. 2. where( 10 ) 1. 18. Some( 2 )
1. 3. Order by( 16 ) 1. 19. AND( 2 )
1. 4. GROUP BY( 8 ) 1. 20. OR( 4 )
1. 5. Having( 7 ) 1. 21. Not( 6 )
1. 6. Null( 2 ) 1. 22. AS( 2 )
1. 7. IS NOT NULL( 1 ) 1. 23. Case( 19 )
1. 8. IS NULL( 3 ) 1. 24. arithmetic operator( 1 )
1. 9. Between( 8 ) 1. 25. Math Calculation( 4 )
1. 10. Exists( 6 ) 1. 26. Logical operator( 11 )
1. 11. In( 7 ) 1. 27. Comparison operators( 7 )
1. 12. DISTINCT( 7 ) 1. 28. Query Hints( 2 )
1. 13. LIKE( 16 ) 1. 29. Select Into( 6 )
1. 14. Column Alias( 5 ) 1. 30. TABLESAMPLE( 1 )
1. 15. Top( 10 ) 1. 31. ROWGUIDCOL( 1 )
1. 16. ALL( 8 ) 1. 32. rowversion( 1 )
2. Insert Delete Update
2. 1. Insert( 12 ) 2. 4. Delete( 9 )
2. 2. Insert into select( 5 ) 2. 5. Update( 16 )
2. 3. BULK INSERT( 1 ) 2. 6. Output( 1 )
3. Table
3. 1. Create Table( 6 ) 3. 5. DROP TABLE( 2 )
3. 2. ALTER TABLE( 16 ) 3. 6. Table alias( 5 )
3. 3. Column( 7 ) 3. 7. Temporary Table( 9 )
3. 4. Computed Columns( 1 ) 3. 8. TRUNCATE table( 2 )
4. Table Join
4. 1. Table Join( 14 ) 4. 7. Self join( 3 )
4. 2. Cross Join( 4 ) 4. 8. MERGE( 1 )
4. 3. Inner join( 8 ) 4. 9. One to many( 2 )
4. 4. Left Join( 1 ) 4. 10. many to many( 2 )
4. 5. LEFT OUTER JOIN( 5 ) 4. 11. APPLY( 1 )
4. 6. RIGHT OUTER JOIN( 2 )
5. Data Types
5. 1. bigint( 1 ) 5. 16. nchar( 1 )
5. 2. bit( 4 ) 5. 17. nVarChar( 2 )
5. 3. bitwise operators( 13 ) 5. 18. OPENROWSET( 2 )
5. 4. Char( 4 ) 5. 19. READTEXT( 1 )
5. 5. collate( 2 ) 5. 20. smalldatetime( 2 )
5. 6. Create Type( 5 ) 5. 21. Smallint( 1 )
5. 7. Data type( 1 ) 5. 22. SQL_VARIANT( 6 )
5. 8. Date Type( 1 ) 5. 23. text( 2 )
5. 9. datetime( 18 ) 5. 24. TEXTPTR( 1 )
5. 10. decimal( 4 ) 5. 25. timestamp( 2 )
5. 11. Float( 1 ) 5. 26. VARBINARY( 4 )
5. 12. FULLTEXT( 8 ) 5. 27. VARCHAR( 13 )
5. 13. integer( 9 ) 5. 28. WRITETEXT( 1 )
5. 14. Large Text( 3 ) 5. 29. Unicode( 1 )
5. 15. money( 1 )
6. Set Operations
6. 1. EXCEPT( 2 ) 6. 3. Union( 6 )
6. 2. INTERSECT( 2 )
7. Constraints
7. 1. Constraints( 5 ) 7. 7. Create Default( 2 )
7. 2. Primary Key( 7 ) 7. 8. Create Rule( 2 )
7. 3. Foreign Key( 9 ) 7. 9. NewID( 1 )
7. 4. REFERENCES( 5 ) 7. 10. Unique( 7 )
7. 5. Check( 13 ) 7. 11. uniqueidentifier( 1 )
7. 6. Default( 8 ) 7. 12. Constriant violation( 4 )
8. Subquery
8. 1. Subquery( 16 ) 8. 3. Inline view( 10 )
8. 2. Correlated subquery( 4 )
9. Aggregate Functions
9. 1. Aggregate function( 5 ) 9. 5. Min( 6 )
9. 2. AVG( 6 ) 9. 6. RANK( 3 )
9. 3. Count( 8 ) 9. 7. SUM( 6 )
9. 4. Max( 6 )
10. Date Functions
10. 1. CURRENT_TIMESTAMP( 4 ) 10. 8. DATEPART( 25 )
10. 2. Date calculation( 1 ) 10. 9. Day( 3 )
10. 3. DATEADD( 16 ) 10. 10. GETDATE( 7 )
10. 4. DATEDIFF( 16 ) 10. 11. GETUTCDATE( 1 )
10. 5. DATEFIRST( 3 ) 10. 12. ISDATE( 4 )
10. 6. DATEFORMAT( 1 ) 10. 13. MONTH( 2 )
10. 7. DATENAME( 15 ) 10. 14. Year( 2 )
11. Math Functions
11. 1. ABS( 2 ) 11. 13. LOG10( 1 )
11. 2. ACOS( 1 ) 11. 14. PI( 1 )
11. 3. ASIN( 1 ) 11. 15. Power( 2 )
11. 4. ATAN( 1 ) 11. 16. RADIANS( 1 )
11. 5. CEILING( 4 ) 11. 17. RAND( 4 )
11. 6. COS( 1 ) 11. 18. ROUND( 9 )
11. 7. COT( 1 ) 11. 19. SIGN( 1 )
11. 8. DEGREES( 1 ) 11. 20. Sin( 2 )
11. 9. EXP( 1 ) 11. 21. SQRT( 3 )
11. 10. FLOOR( 7 ) 11. 22. SQUARE( 2 )
11. 11. ISNUMERIC( 5 ) 11. 23. TAN( 1 )
11. 12. LOG( 1 )
12. String Functions
12. 1. ASCII( 3 ) 12. 13. REPLACE( 1 )
12. 2. Char function( 4 ) 12. 14. REPLICATE( 5 )
12. 3. CHARINDEX( 6 ) 12. 15. REVERSE( 2 )
12. 4. DIFFERENCE( 7 ) 12. 16. Right( 4 )
12. 5. FORMATMESSAGE( 1 ) 12. 17. RTRIM( 6 )
12. 6. LEFT( 7 ) 12. 18. SOUNDEX( 4 )
12. 7. LEN( 4 ) 12. 19. SPACE( 2 )
12. 8. LOWER( 4 ) 12. 20. STR( 6 )
12. 9. LTRIM( 4 ) 12. 21. STUFF( 3 )
12. 10. nchar function( 3 ) 12. 22. SUBSTRING( 8 )
12. 11. PATINDEX( 5 ) 12. 23. UNICODE function( 2 )
12. 12. QUOTENAME( 2 ) 12. 24. UPPER( 4 )
13. Data Convert Functions
13. 1. CAST( 7 ) 13. 4. DROP DATABASE( 2 )
13. 2. COALESCE( 5 ) 13. 5. ISNULL( 7 )
13. 3. CONVERT( 26 ) 13. 6. NULLIF( 1 )
14. Analytical Functions
14. 1. COMPUTE( 5 ) 14. 8. ROLLUP( 8 )
14. 2. CUBE( 7 ) 14. 9. ROW_NUMBER( 2 )
14. 3. DENSE_RANK( 1 ) 14. 10. STDEV( 3 )
14. 4. GROUPING( 4 ) 14. 11. STDEVP( 2 )
14. 5. NTILE( 1 ) 14. 12. VAR( 2 )
14. 6. PARTITION( 3 ) 14. 13. VARP( 1 )
14. 7. PIVOT( 1 )
15. Sequence Indentity
15. 1. Identity( 22 ) 15. 5. IDENT_INCR( 2 )
15. 2. IDENTITYCOL( 2 ) 15. 6. IDENT_SEED( 2 )
15. 3. IDENTITY_INSERT( 2 ) 15. 7. SCOPE_IDENTITY( 3 )
15. 4. IDENT_CURRENT( 2 )
16. View
16. 1. View( 8 ) 16. 5. DROP VIEW( 3 )
16. 2. Create View( 10 ) 16. 6. Filter view( 5 )
16. 3. Query view( 1 ) 16. 7. Updatable View( 6 )
16. 4. ALTER VIEW( 2 )
17. Index
17. 1. CREATE INDEX( 18 ) 17. 2. DROP INDEX( 2 )
18. Cursor
18. 1. Cursor( 3 ) 18. 5. FETCH_STATUS( 1 )
18. 2. Declare Cursor( 12 ) 18. 6. Close cursor( 1 )
18. 3. Open Cursor( 1 ) 18. 7. DEALLOCATE cursor( 2 )
18. 4. Fetch cursor( 3 ) 18. 8. cursor_status( 1 )
19. Database
19. 1. Create Database( 9 ) 19. 4. BACKUP( 3 )
19. 2. Use( 1 ) 19. 5. RESTORE DATABASE( 2 )
19. 3. Alter Database( 8 )
20. Transact SQL
20. 1. Declare( 7 ) 20. 14. Delete Statement( 5 )
20. 2. Variable( 15 ) 20. 15. Insert Statement( 5 )
20. 3. Variable Select( 8 ) 20. 16. Select statement( 4 )
20. 4. Set( 7 ) 20. 17. Update Statement( 2 )
20. 5. Table Variable( 5 ) 20. 18. Dynamic SQL( 8 )
20. 6. Print( 5 ) 20. 19. EXEC( 12 )
20. 7. IF( 14 ) 20. 20. Error Handler( 1 )
20. 8. while( 10 ) 20. 21. RAISERROR( 9 )
20. 9. Goto( 3 ) 20. 22. Return( 7 )
20. 10. Break( 1 ) 20. 23. Try catch( 7 )
20. 11. Comments( 2 ) 20. 24. WAITFOR( 4 )
20. 12. Continue( 1 ) 20. 25. With( 4 )
20. 13. Code Block( 2 )
21. Procedure Function
21. 1. Create function( 6 ) 21. 9. Procedure call( 2 )
21. 2. function( 19 ) 21. 10. Alter procedure( 4 )
21. 3. Recursive function( 5 ) 21. 11. Utility Procedure( 5 )
21. 4. Alter function( 1 ) 21. 12. Drop procedure( 2 )
21. 5. Drop function( 2 ) 21. 13. Parameter( 20 )
21. 6. Utility function( 6 ) 21. 14. Output parameter( 3 )
21. 7. Create Procedure( 6 ) 21. 15. Returning value( 4 )
21. 8. Procedure( 10 )
22. Trigger
22. 1. Trigger( 14 ) 22. 10. Trigger order( 2 )
22. 2. Alter Trigger( 4 ) 22. 11. Drop trigger( 2 )
22. 3. Trigger for after( 4 ) 22. 12. COLUMNS_UPDATED( 1 )
22. 4. Trigger for Delete( 4 ) 22. 13. Update function( 3 )
22. 5. Trigger for insert( 1 ) 22. 14. Deleted table( 2 )
22. 6. Trigger for update( 4 ) 22. 15. Inserted table( 5 )
22. 7. Trigger on database( 2 ) 22. 16. RECURSIVE_TRIGGERS( 1 )
22. 8. Trigger on server( 1 ) 22. 17. Utility trigger( 4 )
22. 9. Trigger on view( 3 )
23. Transaction
23. 1. TRANSACTION( 14 ) 23. 4. Save points( 2 )
23. 2. TRANSACTION ISOLATION LEVEL( 3 ) 23. 5. TRANCOUNT( 2 )
23. 3. COMMIT( 1 )
24. XML
24. 1. XML( 7 ) 24. 4. XML query( 5 )
24. 2. For XML( 4 ) 24. 5. XML Schema( 1 )
24. 3. XML Index( 1 )
25. System Functions
25. 1. APP_NAME( 1 ) 25. 31. sp_depends( 1 )
25. 2. COL_LENGTH( 2 ) 25. 32. sp_describe_cursor( 1 )
25. 3. COL_NAME( 1 ) 25. 33. sp_dropdevice( 1 )
25. 4. context_info( 1 ) 25. 34. sp_DropLogin( 1 )
25. 5. DATABASEPROPERTY( 1 ) 25. 35. sp_dropmessage( 1 )
25. 6. DATABASEPROPERTYEX( 1 ) 25. 36. sp_DropRoleMember( 3 )
25. 7. DATALENGTH( 4 ) 25. 37. sp_DropSrvRoleMember( 2 )
25. 8. db_name( 2 ) 25. 38. sp_droptype( 1 )
25. 9. DecryptByPassphrase( 1 ) 25. 39. sp_GrantDbAccess( 2 )
25. 10. EncryptByPassPhrase( 1 ) 25. 40. sp_GrantLogin( 1 )
25. 11. fn_builtin_permissions( 1 ) 25. 41. sp_help( 3 )
25. 12. fn_helpcollations( 1 ) 25. 42. sp_helpconstraint( 2 )
25. 13. fn_varbintohexstr( 1 ) 25. 43. sp_helpdb( 2 )
25. 14. fn_varbintohexsubstring( 1 ) 25. 44. sp_helpindex( 1 )
25. 15. fn_virtualfilestats( 1 ) 25. 45. sp_HelpRole( 2 )
25. 16. sp_addlinkedserver( 1 ) 25. 46. sp_helptext( 4 )
25. 17. sp_addlogin( 2 ) 25. 47. sp_helpuser( 1 )
25. 18. sp_addmessage( 3 ) 25. 48. sp_makestartup( 1 )
25. 19. sp_AddRole( 2 ) 25. 49. sp_monitor( 1 )
25. 20. sp_addrolemember( 5 ) 25. 50. sp_procoption( 1 )
25. 21. sp_AddSrvRoleMember( 2 ) 25. 51. sp_recompile( 2 )
25. 22. sp_addtype( 3 ) 25. 52. sp_refreshview( 1 )
25. 23. sp_altermessage( 1 ) 25. 53. sp_rename( 2 )
25. 24. sp_bindefault( 2 ) 25. 54. sp_RevokeDbAccess( 2 )
25. 25. sp_bindrule( 1 ) 25. 55. sp_serveroption( 1 )
25. 26. sp_change_users_login( 1 ) 25. 56. sp_spaceused( 2 )
25. 27. sp_configure( 4 ) 25. 57. sp_unbindefault( 1 )
25. 28. sp_create_removable( 1 ) 25. 58. sp_unmakestartup( 1 )
25. 29. sp_dboption( 9 ) 25. 59. SYSTEM_USER( 3 )
25. 30. sp_DenyLogin( 1 )
26. System Settings
26. 1. ANSI_NULLS( 1 ) 26. 24. PACK_RECEIVED( 1 )
26. 2. CONNECTIONS( 1 ) 26. 25. PACK_SENT( 1 )
26. 3. CPU_BUSY( 1 ) 26. 26. QUOTED_IDENTIFIER( 1 )
26. 4. DBCC( 10 ) 26. 27. rowcount( 7 )
26. 5. DB_ID( 1 ) 26. 28. ROWCOUNT_BIG( 1 )
26. 6. ERROR( 11 ) 26. 29. SERVERNAME( 1 )
26. 7. ERROR_NUMBER( 1 ) 26. 30. SERVERPROPERTY( 2 )
26. 8. ERROR_SEVERITY( 1 ) 26. 31. SERVICENAME( 1 )
26. 9. FORCEPLAN( 1 ) 26. 32. SESSIONPROPERTY( 7 )
26. 10. HashBytes( 1 ) 26. 33. SESSION_USER( 1 )
26. 11. HOST_ID( 1 ) 26. 34. SHOWPLAN_TEXT( 2 )
26. 12. HOST_NAME( 1 ) 26. 35. SPID( 1 )
26. 13. IDLE( 1 ) 26. 36. SUSER_ID( 1 )
26. 14. Information_schema( 10 ) 26. 37. SUSER_NAME( 1 )
26. 15. IO_BUSY( 1 ) 26. 38. TIMETICKS( 1 )
26. 16. LANGID( 1 ) 26. 39. TOTAL_ERRORS( 1 )
26. 17. LOCK_TIMEOUT( 2 ) 26. 40. TOTAL_READ( 1 )
26. 18. NESTLEVEL( 1 ) 26. 41. TOTAL_WRITE( 1 )
26. 19. NOCOUNT( 1 ) 26. 42. VERSION( 2 )
26. 20. OBJECTPROPERTY( 4 ) 26. 43. XACT_ABORT( 3 )
26. 21. OBJECT_ID( 5 ) 26. 44. xp_cmdshell( 2 )
26. 22. OBJECT_NAME( 1 ) 26. 45. xp_msver( 2 )
26. 23. PACKET_ERRORS( 1 ) 26. 46. xp_sendmail( 1 )
27. System Tables Views
27. 1. sys.columns( 1 ) 27. 19. sys.triggers( 3 )
27. 2. sys.databases( 3 ) 27. 20. sys.types( 1 )
27. 3. sys.database_principals( 2 ) 27. 21. sys.views( 3 )
27. 4. sys.fn_varbintohexstr( 1 ) 27. 22. sys.xml_schema_collections( 1 )
27. 5. sys.fulltext_catalogs( 1 ) 27. 23. sys.xml_schema_namespaces( 1 )
27. 6. sys.fulltext_indexes( 1 ) 27. 24. syscolumns( 2 )
27. 7. sys.fulltext_index_columns( 1 ) 27. 25. syscomments( 3 )
27. 8. sys.indexes( 1 ) 27. 26. sysconstraints( 2 )
27. 9. sys.messages( 1 ) 27. 27. sysdatabases( 2 )
27. 10. sys.objects( 4 ) 27. 28. sysdepends( 2 )
27. 11. sys.schemas( 3 ) 27. 29. sysfiles( 1 )
27. 12. sys.server_principals( 1 ) 27. 30. sysindexes( 3 )
27. 13. sys.server_sql_modules( 1 ) 27. 31. syslogins( 1 )
27. 14. sys.server_triggers( 1 ) 27. 32. sysmessages( 1 )
27. 15. sys.sql_dependencies( 1 ) 27. 33. sysobjects( 5 )
27. 16. sys.sql_modules( 2 ) 27. 34. systypes ( 1 )
27. 17. sys.syscacheobjects( 1 ) 27. 35. SYSUSERS( 2 )
27. 18. sys.syslogins( 1 )
28. User Role
28. 1. CREATE CERTIFICATE( 2 ) 28. 8. REVOKE( 6 )
28. 2. CREATE SCHEMA( 1 ) 28. 9. Role( 11 )
28. 3. CURRENT_USER( 1 ) 28. 10. schema( 3 )
28. 4. ALTER AUTHORIZATION( 1 ) 28. 11. USER( 8 )
28. 5. DENY( 2 ) 28. 12. USER_ID( 1 )
28. 6. GRANT( 14 ) 28. 13. USER_NAME( 1 )
28. 7. LOGIN( 13 )
29. CLR
29. 1. ASSEMBLY( 4 ) 29. 2. CLR( 6 )

Yazı kategorisi: CTE, Cast, Common Table Expressions, Cross-Tabs, Functions, Instead Of, Pivot Tables, ROW_NUMBER, Raiserror, SQL, SQLCLR, Sql Server, Sql Server Error, Sql Server Join, Stored Procedure, Transact-SQL, Trigger, UNION, UNION ALL, Update with Join | » yorum bırak;

SQL Server / T-SQL

Yazan: esersahin 20/03/2009

http://www.java2s.com/Code/SQLServer/CatalogSQLServer.htm

Select Query Subquery Insert Delete Update Data Set
Select Query
ALL( 1 ) AND( 1 ) ANY( 1 ) AS( 3 ) Between AND( 5 ) Bitwise Operator( 1 )
Case( 9 ) Column Alias( 4 ) Compare Date( 2 ) Data Type( 1 ) Date Calculation( 1 ) Date Compare( 1 )
DESC( 1 ) DISTINCT( 3 ) EXISTS( 5 ) Group BY( 9 ) HAVING( 6 ) IN( 6 )
IS NULL( 2 ) ISNULL( 6 ) LIKE( 10 ) Logical Operator( 7 ) Math Operator( 2 ) MAXRECURSION( 1 )
NOT( 4 ) NULL( 3 ) Operator Precedence( 2 ) OR( 2 ) Order Columns( 5 ) Order( 11 )
Query Batch( 1 ) Query Columns( 6 ) Quotation Mark( 1 ) Select Into( 3 ) Select( 13 ) String Compare( 1 )
Top percent( 4 ) Top With Ties( 1 ) Top( 7 ) Where( 9 ) With( 2 )
Subquery
Correlated subquery( 6 ) Nested Subquery( 2 ) RTRIM( 4 ) Subqueries ALL( 1 ) Subqueries ANY( 2 ) Subqueries Exists( 4 )
Subqueries IN( 5 ) Subqueries( 4 ) Subquery Aggregate Functions( 2 ) Subquery From( 1 )
Insert Delete Update
Batch Insert( 2 ) BULK INSERT( 1 ) Delete( 6 ) Insert Image( 1 ) Insert Select( 4 ) Insert( 5 )
Update( 15 )
Data Set
EXCEPT( 1 ) INTERSECT( 1 ) UNION ALL( 1 ) Union( 3 )
Store Procedure Function Transact SQL Trigger
Store Procedure Function
Create Function( 5 ) Create Procedure( 13 ) Default Parameter( 3 ) Drop Procedure( 1 ) EXEC( 6 ) EXECUTE( 2 )
Function Call( 2 ) Function Parameters( 1 ) Function Return( 7 ) Procedure Call( 3 ) Procedure Parameters( 2 ) Recursive function( 1 )
Scalar Functions( 1 )
Transact SQL
Assign Value( 4 ) ATAN( 1 ) Break( 2 ) COALESCE( 1 ) Code Block( 2 ) Continue( 2 )
Declare Variables( 5 ) Delete Data( 1 ) Dynamic SQL( 4 ) Error( 4 ) GOTO( 1 ) Handle Error( 1 )
If( 7 ) Insert Data( 6 ) LOG( 2 ) Object Property( 1 ) Print( 1 ) Query Data( 2 )
RAISERROR( 2 ) Return( 2 ) RowCount( 3 ) schemas( 1 ) Select Data( 1 ) Select Variables( 2 )
Set Variables( 4 ) Statement( 1 ) Table Variable( 5 ) Update Data( 5 ) Variable Scope( 2 ) Variables( 1 )
Version( 1 ) WAITFOR( 2 ) While( 5 )
Trigger
Alter Trigger( 1 ) Create Trigger( 3 ) Disable Trigger( 1 ) Enable Disable Trigger( 1 ) inserted table( 1 ) INSTEAD OF Trigger( 3 )
Trigger after( 2 ) Trigger for Insert( 1 ) Trigger for update( 4 ) Trigger Value( 2 ) UPDATE function( 1 )
Table Table Joins View Index Database
Table
Add Column( 3 ) Alter Table( 2 ) Column Data Type( 1 ) Column Index( 1 ) Computed Column( 2 ) Copy Data( 1 )
Create Table( 1 ) Derived Columns( 1 ) Drop Column( 2 ) Drop Table( 3 ) Rename Column( 1 ) Rename Table( 1 )
Sub query( 2 ) Table Alias( 1 ) Table Copy( 1 ) Table Existence( 1 ) Table Properties( 1 ) Temporary Table( 3 )
TRUNCATE TABLE( 2 )
Table Joins
ANSI Join Syntax( 3 ) Cross Join( 3 ) INNER JOIN( 4 ) Left Join( 2 ) LEFT OUTER JOIN( 1 ) RIGHT JOIN( 1 )
RIGHT OUTER JOIN( 2 ) Self Join( 1 ) SQL Server Join Syntax( 2 ) Table Join( 10 )
View
Alter View( 2 ) Create View( 13 ) Drop View( 2 ) ENCRYPTION( 1 ) Filter view( 2 ) Inline view( 2 )
Nested View( 1 ) Query View( 1 ) SCHEMABINDING( 1 ) Updatable View( 2 ) View Existance( 1 )
Index
CLUSTERED INDEX( 2 ) Create Index( 6 ) Drop Index( 1 ) DROP_EXISTING( 1 )
Database
Create Database( 3 ) Database Info( 1 ) Database Option( 7 ) databases( 2 ) DROP DATABASE( 2 ) USE( 1 )
Transaction Cursor Constraints Sequence
Transaction
Commit Transaction( 3 ) Transaction Roll back( 4 ) XACT_ABORT( 1 )
Cursor
Declare CURSOR( 3 ) Fetch Data( 2 ) Fetch_Status( 1 ) Open cursor( 2 )
Constraints
Add Primary Key( 2 ) CASCADE( 1 ) Check Options( 6 ) Check value range( 3 ) Column Constraints( 5 ) Constraints Basics( 2 )
CREATE RULE( 1 ) Default Value( 3 ) Disable constraint( 1 ) Foreign Key( 4 ) Maintain Constaints( 1 ) Nullable( 3 )
Primary key( 3 ) Unique( 3 ) UniqueIdentifier( 1 )
Sequence
IDENTITY( 12 ) IDENTITYCOL( 1 ) IDENT_CURRENT( 2 ) NEWID( 1 ) Procedure Call( 3 ) Procedure Existance( 1 )
Procedure Permission( 1 ) Procedure with Parameters( 13 ) Procedure( 1 )
Data Type XML Date Timezone
Data Type
Bit( 2 ) Cast( 21 ) char( 1 ) Convert( 8 ) Data Type Convert( 1 ) datetime( 1 )
decimal( 7 ) float( 1 ) int( 3 ) Money( 1 ) nchar Data Type( 1 ) Number Format( 2 )
text( 1 ) varchar( 3 )
XML
XML column( 2 )
Date Timezone
CURRENT_TIMESTAMP( 1 ) Date Data Type( 2 ) Date Format( 12 ) DATEADD( 18 ) DATEDIFF( 19 ) DATENAME( 14 )
DATEPART( 13 ) Datetime( 3 ) Day( 4 ) GetDate( 4 ) GETUTCDATE( 2 ) Int( 1 )
ISDATE( 6 ) Month( 4 ) Year( 4 )
Aggregate Functions Analytical Functions Math Functions String Functions
Aggregate Functions
Aggregate Function Basics( 2 ) AVG( 4 ) Count( 6 ) COUNT_BIG( 2 ) MAX( 3 ) MIN( 2 )
SUM( 2 )
Analytical Functions
COMPUTE( 5 ) Cube( 2 ) DENSE RANK( 2 ) NTile( 1 ) Over( 1 ) RANK( 2 )
Row Number( 3 ) STDEV( 4 ) VAR( 3 ) VARP( 2 ) WITH ROLLUP( 2 )
Math Functions
ABS( 2 ) ACOS( 2 ) ASIN( 1 ) CEILING( 3 ) COS( 2 ) COT( 1 )
DEGREES( 2 ) EXP( 1 ) FLOOR( 3 ) ISNUMERIC( 3 ) Log10( 2 ) mod( 1 )
PI( 1 ) Power( 2 ) RADIANS( 1 ) RAND( 1 ) ROUND( 9 ) SIGN( 1 )
SIN( 1 ) SQRT( 1 ) SQUARE( 1 ) TAN( 1 )
String Functions
ASCII( 2 ) CHAR( 3 ) CHARINDEX( 5 ) COLLATE( 1 ) DATALENGTH( 3 ) Difference( 4 )
Escape( 1 ) LEFT( 4 ) LEN( 4 ) Lower( 2 ) LTRIM( 2 ) NCHAR( 2 )
PATINDEX( 2 ) QUOTENAME( 1 ) Regular Expressions( 5 ) REPLACE( 3 ) REPLICATE( 4 ) REVERSE( 2 )
RIGHT( 4 ) SOUNDEX( 2 ) Space( 2 ) STR( 6 ) STUFF( 2 ) Substring( 4 )
UNICODE( 1 ) UPPER( 3 )
System
System
columns( 2 ) DATABASEPROPERTYEX( 1 ) DB_ID( 1 ) Error_Message( 1 ) HOST_NAME( 1 ) INFORMATION_SCHEMA( 3 )
LOCK_TIMEOUT( 1 ) LOGIN( 1 ) OBJECT_ID( 1 ) QUOTED_IDENTIFIER( 2 ) Row Count( 2 ) ROWCOUNT( 1 )
SHOWPLAN_TEXT( 2 ) sp_addmessage( 2 ) sp_altermessage( 1 ) sp_dboption( 1 ) sp_dropmessage( 1 ) sp_helpconstraint( 1 )
sp_helpindex( 1 ) sp_helptext( 1 ) sp_unbindefault( 1 ) STATISTICS( 1 ) SUSER_SNAME( 1 ) sys.sql_modules( 1 )
sys.syscacheobjects( 1 ) sys.types( 1 ) sys.views( 1 ) sys.XML_schema_collections( 1 ) syscomments( 1 ) sysdepends( 1 )
sysmessages( 2 ) sysobjects( 2 ) sysusers( 1 ) TOTAL_ERRORS( 1 ) TOTAL_READ( 1 ) USER( 1 )
USER_NAME( 1 ) views( 1 )

Yazı kategorisi: CTE, Cast, Cross-Tabs, Functions, Pivot Tables, SQL, Sql Server, Sql Server Error, Sql Server Join, Stored Procedure, Transact-SQL, Trigger | » yorum bırak;

Common Table Expressions (CTE) in SQL Server 2005 By Scott Mitchell

Yazan: esersahin 26/11/2008

http://www.4guysfromrolla.com/webtech/071906-1.shtml

 


Introduction
When crafting a query in SQL, there are often times when we may need to operate over a set of data that doesn’t inherently exist within the system. For example, the database for an eCommerce web application would have the standard tables – Products, Customers, Orders, OrderDetails, and so on – but we may need to run reports on a particular subset of the data or against aggregate data across these tables. Or the reporting queries we need might need to group or filter by results returned by scalar subqueries. Typically, views are used to break down complex queries into digestible chunks or to provide scalar subquery results that can be grouped and filtered. Views, however, are sometimes overkill, as they are permanent objects at the system-level. If we only need to reference this complex query in a single stored procedure or UDF, another option is to use a derived table. Unfortunately, derived tables muddle the readability of the query and must be repeated for each use in a statement.

Common Table Expressions, or CTE, are a new construct introduced in Microsoft SQL Server 2005 that offer a more readable form of the derived table that can be declared once and referenced multiple times in a query. Moreover, CTEs can be recursively defined, allowing a recursive entity to be enumerated without the need for recursive stored procedures. In this article we’ll examine the benefits, uses, and syntax of both recursive and non-recursive CTEs. Read on to learn more!

 

- continued -

Microsoft.com Operations Virtualizes MSDN and TechNet on Hyper-V
This article provides further details about testing methods and the results from Hyper-V Beta to RC0 that generated the confidence to fully roll out MSDN and TechNet on Hyper-V in production. »

Virtualization Case Study: Copa Airlines
Copa Airlines joined a Microsoft Rapid Deployment Program to test Hyper-V to provide a dynamic and reliable virtualization environment and System Center Virtual Machine Manager for the physical to virtual conversions of the chosen servers. The RDP program proved that a Microsoft virtualization solution could be a cost-effective way for Copa to increase business application availability, reduce data center costs, and optimize data center management. »

Virtualization from the Data Center to the Desktop
Integrated virtualization solutions can help you meet evolving demands more effectively as you transform IT infrastructure from a cost center to a strategic business asset. »

 

 

Obtaining the Northwind Traders Database for SQL Server 2005
The examples used in this article are all operating against the Northwind Traders database, which has a simple eCommerce schema (Products, Customers, Orders, Order Details, and so on). Originally, the Northwind database was released for Microsoft Access. A version for SQL Server 2000 was later provided. Microsoft has not posted an “official” Northwind database for SQL Server 2005. However, you can create a SQL Server 2005 database and then import the schema and data from the create scripts provided in the SQL Server 2000 version download. Or, even better yet, you can simply download the Northwind database files from the list below for SQL Server 2005 and bypass having to create this database yourself. 

A Simple Common Table Expression Example
Before we dive into the syntax or gritty details of CTEs, let’s start by looking at a simple example. I think you’ll agree that even without knowing the syntax of CTEs, they are pretty readable and straightforward (the hallmark of a well-designed programming language construct).

WITH ProductAndCategoryNamesOverTenDollars (ProductName, CategoryName, UnitPrice) AS
(
   SELECT
      p.ProductName,
      c.CategoryName,
      p.UnitPrice
   FROM Products p
      INNER JOIN Categories c ON
         c.CategoryID = p.CategoryID
   WHERE p.UnitPrice > 10.0
)

SELECT *
FROM ProductAndCategoryNamesOverTenDollars
ORDER BY CategoryName ASC, UnitPrice ASC, ProductName ASC

This query creates a CTE named ProductAndCategoryNamesOverTenDollars that returns the name, category name, and price of those products whose unit price exceeds $10.00. Once the CTE has been defined, it must then immediately be used in a query. The query treats the CTE as if were a view or table in the system, returning the three fields defined by the CTE (ProductName, CategoryName, and UnitPrice), ordered alphabetically by category, then by price, and then alphabetically by product name.

 

The results of the query.In short, a Common Table Expression allows us to define a temporary, view-like construct. We start by (optionally) specifying the columns it returns, then define the query. Following that, the CTE can be used in a SELECT, INSERT, UPDATE, or DELETE statement.

Common Table Expression Syntax
A Common Table Expression contains three core parts:

  • The CTE name (this is what follows the WITH keyword)
  • The column list (optional)
  • The query (appears within parentheses after the AS keyword)

The query using the CTE must be the first query appearing after the CTE. That is, you cannot do the following:

WITH ProductAndCategoryNamesOverTenDollars (ProductName, CategoryName, UnitPrice) AS
(
   SELECT
      p.ProductName,
      c.CategoryName,
      p.UnitPrice
   FROM Products p
      INNER JOIN Categories c ON
         c.CategoryID = p.CategoryID
   WHERE p.UnitPrice > 10.0
)

SELECT *
FROM Products

SELECT *
FROM ProductAndCategoryNamesOverTenDollars
ORDER BY CategoryName ASC, UnitPrice ASC, ProductName ASC

The ProductAndCategoryNamesOverTenDollars CTE only applies to the first query following it. So when the second query is reached, ProductAndCategoryNamesOverTenDollars is undefined, resulting in an “Invalid object name ‘ProductAndCategoryNamesOverTenDollars’” error message.

You can, however, define multiple CTEs after the WITH keyword by separating each CTE with a comma. For example, the following query uses two CTEs. The subsequent SELECT query then uses an INNER JOIN to match together the records from the two CTEs:

WITH CategoryAndNumberOfProducts (CategoryID, CategoryName, NumberOfProducts) AS
(
   SELECT
      CategoryID,
      CategoryName,
      (SELECT COUNT(1) FROM Products p
       WHERE p.CategoryID = c.CategoryID) as NumberOfProducts
   FROM Categories c
),

ProductsOverTenDollars (ProductID, CategoryID, ProductName, UnitPrice) AS
(
   SELECT
      ProductID,
      CategoryID,
      ProductName,
      UnitPrice
   FROM Products p
   WHERE UnitPrice > 10.0
)

SELECT c.CategoryName, c.NumberOfProducts,
      p.ProductName, p.UnitPrice
FROM ProductsOverTenDollars p
   INNER JOIN CategoryAndNumberOfProducts c ON
      p.CategoryID = c.CategoryID
ORDER BY ProductName

 

 

The results of the query.Unlike a derived table, CTEs can be defined just once, yet appear multiple times in the subsequent query. To demonstrate this, consider the following example: the Northwind database’s Employees table contains an optional ReportsTo column that, if specified, indicates the employee’s manager. ReportsTo is a self-referencing foreign key, meaning that, if provided, it refers back to another EmployeeID in the Employees table. Imagine that we wanted to display a list of employees including how many other employees they directly managed. This could be done using a simple, CTE-free SELECT statement, but let’s use a CTE for now (for reasons which will become clear soon):

WITH EmployeeSubordinatesReport (EmployeeID, LastName, FirstName, NumberOfSubordinates, ReportsTo) AS
(
   SELECT
      EmployeeID,
      LastName,
      FirstName,
      (SELECT COUNT(1) FROM Employees e2
       WHERE e2.ReportsTo = e.EmployeeID) as NumberOfSubordinates,
      ReportsTo
   FROM Employees e
)

SELECT LastName, FirstName, NumberOfSubordinates
FROM EmployeeSubordinatesReport

This query will return the employees records, showing each employee’s last and first name along with how many other employees they manage. As the figure below shows, only Andrew Fuller and Steven Buchanan are manager material.

 

The results of the query.Now, imagine that our boss (Andrew Fuller, perhaps) comes charging into our office and demands that the report also lists each employee’s manager’s name and number of subordinates (if the employee has a manager, that is – Mr. Fuller is all to quick to point out that he reports to no one). Adding such functionality is a snap with the CTE – just add it in a LEFT JOIN!

WITH EmployeeSubordinatesReport (EmployeeID, LastName, FirstName, NumberOfSubordinates, ReportsTo) AS
(
   SELECT
      EmployeeID,
      LastName,
      FirstName,
      (SELECT COUNT(1) FROM Employees e2
       WHERE e2.ReportsTo = e.EmployeeID) as NumberOfSubordinates,
      ReportsTo
   FROM Employees e
)

SELECT Employee.LastName, Employee.FirstName, Employee.NumberOfSubordinates,
   Manager.LastName as ManagerLastName, Manager.FirstName as ManagerFirstName, Manager.NumberOfSubordinates as ManagerNumberOfSubordinates
FROM EmployeeSubordinatesReport Employee
   LEFT JOIN EmployeeSubordinatesReport Manager ON
      Employee.ReportsTo = Manager.EmployeeID

With this additional LEFT JOIN, the employee’s manager’s results are returned; if there’s no manager for the employee, NULLs are returned instead.

 

The results of the query.

When to Use Common Table Expressions
Common Table Expressions offer the same functionality as a view, but are ideal for one-off usages where you don’t necessarily need a view defined for the system. Even when a CTE is not necessarily needed (as when listing just the employees and their subordinate count in the example above), it can improve readability. In Using Common Table Expressions, Microsoft offers the following four advantages of CTEs:

  • Create a recursive query.
  • Substitute for a view when the general use of a view is not required; that is, you do not have to store the definition in metadata.
  • Enable grouping by a column that is derived from a scalar subselect, or a function that is either not deterministic or has external access.
  • Reference the resulting table multiple times in the same statement.

Using a CTE offers the advantages of improved readability and ease in maintenance of complex queries. The query can be divided into separate, simple, logical building blocks. These simple blocks can then be used to build more complex, interim CTEs until the final result set is generated.

Using scalar subqueries (such as the (SELECT COUNT(1) FROM ...) examples we’ve looked at in this article) cannot be grouped or filtered directly in the containing query. Similarly, when using SQL Server 2005’s ranking functions – ROW_NUMBER(), RANK(), DENSE_RANK(), and so on – the containing query cannot include a filter or grouping expression to return only a subset of the ranked results. For both of these instances, CTEs are quite handy. (For more on SQL Server 2005’s ranking capabilities, be sure to read: Returning Ranked Results with Microsoft SQL Server 2005.)CTEs can also be used to recursively enumerate hierarchical data. We’ll examine this next!

Recursive Common Table Expressions
Recursion is the process of defining a solution to a problem in terms of itself. For example, a teacher needs to sort a stack of tests alphabetically by the students’ names. She could process the tests one at a time and, for each test, insert it into the appropriate spot to the left (called insertion sort), probably the way most people sort a hand of cards (at least that’s the way I do it). However, depending on the distribution of the tests, the size of the work space, the number of tests to sort, and so on, it may be far more efficient to break down the problem into pieces. Rather than doing an insertion sort right off the bat, it might first make sense to divide the stack of papers in half, and then do an insertion sort on one half, an insertion sort on the second half, and then a merge of the two piles. Or perhaps it would make sense to divide the tests into four piles, or eight piles. (This approach is referred to as merge sort.)

With a recursive solution you will always have the following two pieces:

  • The base case – what to do when you’re done recursing. After dividing the tests into separate piles of say, eight elements per pile, the base case is to sort these piles via insertion sort.
  • The recursive step – the action to perform that involves plugging the input “back into” the system. For merge sort, the recursive step is the division of one pile into two. Then into four. Then into eight, and so on, until the base case is reached.

For more on recursion, see Recursion, Why It’s Cool.

Returning to CTEs… the Employees database table holds the corporate hierarchy within its rows. Imagine that good ol’ Andrew Fuller has come back and insisted on a report that would list all persons in the company along with their position in the hierarchy. Since the Employees table can capture an arbitrary number of hierarchy levels, we need a recursive solution. Enter CTEs…

Like any recursive definition, a recursive Common Table Expression requires both a base case and the recursive step. In SQL parlance, this translates into two SQL queries – one that gets the “initial” data UNIONed with one that performs the recursion. For the Employees example, the base case is returning those employees that have no manager:

SELECT ...
FROM Employees
WHERE ReportsTo IS NULL

The recursion includes a query on the CTE itself. The following shows the CTE – with both the base case and recursive step – along with a SELECT query that returns the rows from the CTE:

WITH EmployeeHierarchy (EmployeeID, LastName, FirstName, ReportsTo, HierarchyLevel) AS
(
   -- Base case
   SELECT
      EmployeeID,
      LastName,
      FirstName,
      ReportsTo,
      1 as HierarchyLevel
   FROM Employees
   WHERE ReportsTo IS NULL

   UNION ALL

   -- Recursive step
   SELECT
      e.EmployeeID,
      e.LastName,
      e.FirstName,
      e.ReportsTo,
      eh.HierarchyLevel + 1 AS HierarchyLevel
   FROM Employees e
      INNER JOIN EmployeeHierarchy eh ON
         e.ReportsTo = eh.EmployeeID
)

SELECT *
FROM EmployeeHierarchy
ORDER BY HierarchyLevel, LastName, FirstName

The recursion occurs in the second query in the CTE by joining the results of Employees against the CTE itself (EmployeeHierarchy) where the employees’ ReportsTo field matches up to the CTE’s EmployeeID. Included in this query is the HierarchyLevel field, which returns 1 for the base case and one greater than the previous level for each recursive step down the hierarchy. As requested, this resultset clearly shows that Mr. Fuller is the alpha male in this organization. Furthermore, we can see that Steven, Laura, Nancy, Janet, and Margaret make up the second tier in the organizational hierarchy, while poor Anne, Robert, and Michael are down at the bottom:

 

The results of the query.

Alternatives to Recursive Common Table Expressions
As we saw in this article, enumerating hierarchical data recursively can be accomplished via CTEs (for more on using recursive CTEs, don’t forget to check out the official documentation – Recursive Queries Using Common Table Expressions). However, there are other options as well. One choice is to perform the recursion at the ASP/ASP.NET layer. That is, read in all employee information to a Recordset of DataSet in code, and then recurse there. My article Efficiently DisplayingParent-Child Data discusses this approach.If you need to perform the recursion in SQL, you can use recursive stored procedures, as discussed in The Zen of Recursion. If you are designing a data model that needs to support hierarchical data, your best bet is to bake in some lineage information directly into the table from the get-go. See SQL for Threaded Discussions and More Trees & Hierarchies in SQL for more information.

Conclusion
One of the many new features in SQL Server 2005 are Common Table Expressions (CTEs), which provide a more readable and usable approach to derived tables. Additionally, CTEs may be recursively defined, allowing a recursive entity to be enumerated without the need for recursive stored procedures. For more on the new features found in SQL Server 2005, be sure to also check out Returning Ranked Results with Microsoft SQL Server 2005 and TRY...CATCH in SQL Server 2005.

Happy Programming!

 

  • By Scott Mitchell
  • Yazı kategorisi: CTE, SQL, Sql Server | » yorum bırak;

    DATABASE JOURNAL – Featured Database Articles – MSSQL

    Yazan: esersahin 23/11/2008

    http://www.databasejournal.com/features/mssql/archives.php

    Archives
    Combine BottomCount() with Other MDX Functions to Add Sophistication – 11/21/2008

    Microsoft Windows PowerShell and SQL Server 2008 AMO – 11/18/2008
    SQL Server: Measuring Space Allocation and Index Distribution – 11/14/2008
    Installing a Two-node SQL Server 2008 Cluster – Advanced option – 11/12/2008
    Establishing Distributed SQL Server Express’ Service Broker Conversations Using Certificate-based Authentication – 11/10/2008
    SQL Server 2008 Recovery Models and Backups – 11/07/2008
    Using Windows PowerShell to get SQL Server connection information – 11/05/2008
    Attribute Member Values in Analysis Services – 11/04/2008
    Introducing Reporting Services Charts for Analysis Services – 10/29/2008
    Reports for SQL Server 2008 System Data Collections – 10/27/2008
    Exploring SQL 2005’s Ranking Functions – NTILE() and ROW_NUMBER() – 10/24/2008
    Configuring Certificate-based Authentication in SQL Server Express’ Distributed Service Broker Environment – 10/20/2008
    Check your SQL Server using Windows PowerShell – Part 7 – 10/15/2008
    MSSQL Analysis Services – Attribute Member Names – 10/13/2008
    SQL Server 2005 Express Edition – Part 32 – Distributed Service Broker Environment – Conducting Dialogs – 10/10/2008
    Setting up a Two-NODE SQL Server 2008 Cluster from the Command Prompt – Integrated Installation – 10/08/2008
    Basic Set Functions: The BottomCount() Function, Part I – 10/06/2008
    SQL 2008 Backup and Restore Part 1 – 10/03/2008
    Check your SQL Server using Windows PowerShell – Part 6 – 10/01/2008
    SQL Server 2008 Data Collections and the Management Data Warehouse – 09/29/2008
    SqlCredit – Part 19: Exploring SQL 2005’s Ranking Functions – RANK() and DENSE_RANK() – 09/26/2008
    Mastering OLAP Reports: Parameterized Grouping – 09/23/2008
    SQL Server 2005 Express Edition – Part 31 – Distributed Service Broker Environment – Routing – 09/22/2008
    Attribute Member Keys – Pt II: Composite Keys – 09/19/2008
    Check your SQL Server using Windows PowerShell – Part 5 – 09/17/2008
    Setting up a Two-node SQL Server 2008 Cluster from the Command Prompt – Preparation – 09/16/2008
    Intrinsic Member Properties: The MEMBER_VALUE Property – 09/12/2008
    SQL Server 2005 Express Edition – Part 30 – Distributed Service Broker Environment – Endpoints – 09/08/2008
    What is SQL Server – 09/05/2008
    Terminate User processes in SQL Server – 09/03/2008
    Attribute Member Keys – Pt 1: Introduction and Simple Keys – 08/29/2008
    What Kind of DBA Are You? – 08/26/2008
    SQL Server 2005 Express Edition – Part 29 – Implementing Service Broker Conversation – 08/25/2008
    SqlCredit, Part 18: Exploring the Performance of SQL 2005’s OUTPUT Clause – 08/21/2008
    Audit your Windows domain DBA group using PowerShell – 08/20/2008
    Discover SQL Server TCP Port – 08/19/2008
    Mastering OLAP Reports: Parameterizing Number of “Top” Items with the MDX TopCount() Function, Part II – 08/18/2008
    Intrinsic Member Properties: The MEMBER_UNIQUE_NAME Property – 08/08/2008
    Check your SQL Server using Windows PowerShell – Part 4 – 08/06/2008
    SQL Server 2005 Express Edition – Part 28 – Implementing Service Broker Conversation – 08/05/2008
    Create Your First SQL Server Database in 3 Quick Steps – 08/01/2008
    Mastering OLAP Reports: Parameterizing Number of “Top” Items with the MDX TopCount() Function, Part I – 07/29/2008
    SQL Server 2005 Express Edition – Part 27 – Implementing Basic Service Broker Objects – 07/28/2008
    SqlCredit – Part 17: Exploring SQL 2005’s OUTPUT Clause – 07/25/2008
    SQL Server 2008 MERGE Statement – 07/24/2008
    Intrinsic Member Properties: The MEMBER_NAME Property – 07/21/2008
    Check your SQL Server using Windows PowerShell – Part 3 – 07/16/2008
    SQL Server Audit in SQL Server 2008 – Part 2 – 07/14/2008
    SQL Server 2005 Express Edition – Part 26 – Introduction to Service Broker – 07/11/2008
    Dimension Attributes: Introduction and Overview, Part V – 07/07/2008
    SQL Server Profiler Part 2 – 07/02/2008
    Check your SQL Server using Windows PowerShell – Part 2 – 07/01/2008
    Mastering OLAP Reports: Parameterizing Number of “Look Back” Periods with the MDX LastPeriods() Function, Part II – 06/27/2008
    SQL Server 2008 Date Functions, Part 2 – 06/26/2008
    Enhancement in variable declaration – SQL Server 2008 – 06/24/2008
    Implementing Upgrade of SQL Server 2005 Express Edition – 06/23/2008
    Intrinsic Member Properties: The MEMBER_KEY Property – 06/20/2008
    Check your SQL Server using Windows PowerShell – Part 1 – 06/18/2008
    Mastering OLAP Reports: Parameterizing Number of “Look Back” Periods with the MDX LastPeriods() Function, Part I – 06/13/2008
    SQL Server 2005 Express Edition – Part 24 – Planning Upgrade of SQL Server 2005 Express Edition – 06/09/2008
    SQL Server Audit in SQL Server 2008 – Part 1 – 06/06/2008
    Compound Assignment Operators in SQL Server 2008 – 06/04/2008
    Introduction to SQL 2005 Profiler Part 1 – 06/02/2008
    Dimension Attributes: Introduction and Overview, Part IV – 05/29/2008
    New Date Data Types with SQL Server 2008 – 05/27/2008
    SqlCredit – Part 16: The Cost of Bloat – 05/23/2008
    Intrinsic Member Properties: The MEMBER_CAPTION Property – 05/22/2008
    SQL Server 2005 Express Edition – Part 23 – Manual Upgrade from Microsoft SQL Server Desktop Engine (MSDE) – 05/22/2008
    Table-valued parameters – SQL Server 2008 – 05/21/2008
    Dimension Attributes: Introduction and Overview, Part III – 05/15/2008
    Policy-based Management in SQL Server 2008 – Part II – 05/13/2008
    SQL Server 2005 Express Edition – Part 22 – Upgrading from Microsoft SQL Server Desktop Engine (MSDE) – 05/09/2008
    Row Value Constructor in SQL Server 2008 – 05/06/2008
    SQL Server Management Studio Reports and Dashboard – 05/02/2008
    Support Parameterization from Analysis Services – Parameter Defaults – 04/29/2008
    SqlCredit – Part 15: The Cost of Distribution – 04/25/2008
    SQL Server 2005 Express Edition – Part 21 – Using Replication Management Objects – 04/24/2008
    Connection Strategy for Multiple Database Environments – 04/22/2008
    Dimension Attributes: Introduction and Overview, Part II – 04/18/2008
    Policy-based Management in SQL Server 2008 – Part I – 04/17/2008
    UPSERT Functionality in SQL Server 2008 – 04/16/2008
    SQL Server 2005 Express Edition – Part 20 – Authenticating Merge Web Synchronization – 04/11/2008
    Set Functions: The StripCalculatedMembers() Function – 04/07/2008
    Storing Images and BLOB files in SQL Server Part 4 – 04/04/2008
    Top Queries in SQL Server 2005 – 04/02/2008
    Exam 70-443 Practice Test from uCertify.com – 03/31/2008
    SqlCredit – Part 14: The Cost of Translation – 03/28/2008
    Parameterization from Analysis Services – Cascading Picklists – 03/26/2008
    SQL Server 2005 Express Edition – Part 19 – Authenticating Merge Web Synchronization – 03/24/2008
    Using dtutil to copy SSIS packages stored in SQL Server – 03/20/2008
    Find space Usage by Table , Schema in SQL Server 2005 and 2008 – 03/18/2008
    Dimension Attributes: Introduction and Overview, Part I – 03/13/2008
    SQL Server 2005 Express Edition – Part 18 – Merge Web Synchronization Setup – 03/11/2008
    Storing Images and BLOB files in SQL Server Part 3 – 03/07/2008
    Microsoft SQL Server 2008 – Change Data Capture – Part 4 – 03/05/2008
    Set Functions: The AddCalculatedMembers() Function – 03/03/2008
    SQL Server DBA Dashboard – 02/29/2008
    Support Parameterization from Analysis Services – 02/26/2008
    SQL Server 2005 Express Edition – Part 17 – Merge Web Synchronization – 02/25/2008
    SqlCredit – Part 13: More on Indexed Persisted Computed Columns – 02/22/2008
    DST checking with Windows Powershell – 02/21/2008
    Microsoft SQL Server 2008 – Change Data Capture – Part 3 – 02/20/2008
    Dimensional Model Components: Dimensions Part II – 02/15/2008
    SQL Server 2005 Express Edition – Part 16 – Transactional and Merge Replication – 02/08/2008
    Microsoft SQL Server 2008 – Change Data Capture – Part 2 – 02/06/2008
    MDX Numeric Functions: The Min() Function – 02/04/2008
    Storing Images and BLOB files in SQL Server Part 2 – 02/01/2008
    Parameter Support Objects, Pt II: Support OLAP Parameter Defaults with Datasets – 01/31/2008
    Building Custom Reporting Services Reports for SQL Server Management Studio – 01/30/2008
    SQL Server 2005 Express Edition – Part 15 – Snapshot Replication – 01/28/2008
    SqlCredit – Part 12: Exploring Indexed Persisted Computed Columns – 01/25/2008
    Dimensional Model Components: Dimensions Part I – 01/24/2008
    Microsoft Windows PowerShell and SQL Server 2005 WMI Providers – Part 2 – 01/22/2008
    Reporting Services: Customize Automatically Created Parameter Support Objects – 01/16/2008
    Microsoft SQL Server 2008 – Change Data Capture – Part I – 01/11/2008
    SQL Server 2005 Express Edition – Part 14 – Replication Support – 01/07/2008
    Storing Images and BLOB files in SQL Server – 01/04/2008
    New datetime datatypes in SQL Server 2008 – 01/02/2008
    MDX Numeric Functions: The Max() Function – 12/31/2007
    SQL Server 2005 – Hacking password Encryption – 12/28/2007
    Disk Space Usage and SQL Server Performance – 12/26/2007
    SQL Server 2005 Express Edition – Part 13 – ClickOnce Deployment and Security – 12/24/2007
    BACKUP compression in SQL Server 2008 – 12/19/2007
    Manage Unknown Members in Analysis Services 2005, Part II – 12/14/2007
    SQL Server 2005 Express Edition – Part 12 – ClickOnce Deployment and Updates – 12/10/2007
    Set Functions: The .AllMembers Function – 12/07/2007
    SQL Server 2005 Encryption types – 12/05/2007
    Installing SQL Server 2008 – 12/03/2007
    Snapshot Reports II: SQL Server Management Studio Perspective – 11/30/2007
    SQL Server Security Model – 11/28/2007
    SqlCredit – Part 11: Change Tracking Using History Records – 11/26/2007

    MS SQL Archives

    2008   Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
    2007   Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
    2006   Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
    2005   Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
    2004   Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
    2003   Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
    2002   Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
    2001   Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
    2000   Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
    1999   Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
    1998   Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec

    Yazı kategorisi: Analysis Services, C#, CTE, Data, Data Mining, Integration Services, Report Builder, Report Designer, Report Server, Reporting Services, Sql Server, Sql Server Join, Transact-SQL | » yorum bırak;

    Common Table Expressions (CTE) on SQL 2005

    Yazan: esersahin 23/11/2008

    http://www.databasejournal.com/features/mssql/article.php/3502676/Common-Table-Expressions-CTE-on-SQL-2005.htm

    By Don Schlichting

    This article will introduce Common Table Expressions (CTE) on SQL 2005, and compare them with related SQL 2000 methods such as Derived and Temporary Tables.

    Introduction

    New in SQL 2005 are Common Table Expressions, CTE for short. A Common Table Expression is an expression that returns a temporary result set from inside a statement. This result set is similar to a hybrid Derived Table meets declared Temporary Table. The CTE contains elements similar to both. Some of the most frequent uses of a Common Table Expression include creating tables on the fly inside a nested select, and doing recursive queries. Common Table Expressions can be used for both selects and DML statements. The natural question is, if we have been using TSQL for this long without Common Table Expressions, why start using them now? There are several benefits to learning CTEs. Although new to SQL Server, Common Table Expressions are part of ANSI SQL 99, or SQL3. Therefore, if ANSI is important to you, this is a step closer. Best of all, Common Table Expressions provide a powerful way of doing recursive and nested queries in a syntax that is usually easier to code and review than other methods.

    CTE

    Below is very simple Common Table Expression example. All the CTE examples in this article were created on SQL 2005 Beta 2 Developer Edition. The example CTE will be used to return the list price of products, and our sell price, which is five percent below list. This first example is very simple, and could be replaced by a single select statement, but it will demonstrate some key CTE points. The examples will get more advanced as the article progresses.

    USE AdventureWorks
    GO
    
    WITH MyCTE( ListPrice, SellPrice) AS
    (
      SELECT ListPrice, ListPrice * .95
      FROM Production.Product
    )
    
    SELECT *
    FROM MyCTE
    
    GO

    The database, Adventure Works, is now the SQL 2005 default sample database. Gone are the days of Northwind. On the beta version used for this article, Adventure Works did not install by default. Instead, during install, click Advanced then select sample databases.

    The Common Table Expression is created using the WITH statement followed by the CTE name. Immediately trailing is a column list, in our case, we are returning two columns, ListPrice, and SellPrice. After the AS, the statement used to populate the two returning columns begins. The CTE is then followed by a select calling it.

    The BOL format of a Common Table Expression is listed below;

    [ WITH <common_table_expression> [ ,...n ] ]
    
    <common_table_expression>::=
        expression_name [ ( column_name [ ,...n ] ) ]
        AS
        ( CTE_query_definition )

    Temporary Tables

    This small example displays several interesting concepts. The CTE is called by name from the SELECT * statement, similar to a Temporary Table. However, if a Temporary Table were used, it would first have to be created, and then populated;

    CREATE TABLE #MyCTE
    (
      ListPrice money,
      SellPrice money
    )
    
    INSERT INTO #MyCTE
    	(ListPrice, SellPrice)
    	SELECT ListPrice, ListPrice * .95
    	FROM Production.Product

    However, a Temporary Table could be called over and over again from with in a statement. A Common Table Expression must be called immediately after stating it. Therefore, in this example, the call to the CTE will fail.

    USE AdventureWorks
    GO
    
    WITH MyCTE( ListPrice, SellPrice) AS
    (
      SELECT ListPrice, ListPrice * .95
      FROM Production.Product
    )
    
    SELECT *
    FROM Production.Location
    
    SELECT *
    FROM MyCTE
    
    GO

    The call to MyCTE will fail with the following error:

    Msg 208, Level 16, State 1, Line 14
    Invalid object name 'MyCTE'.

    The CTE itself has some syntactical restrictions. Compute, Order By (without a TOP), INTO, Option, FOR XML, and FOR BROWSE are all not allowed.

    Derived Tables

    A SQL 2000 method somewhat similar to a CTE is a Derived Table. These are temporary result sets created by a query statement. However, they cannot be referenced by name, and may be used only once. In complex statements, they may not be as readable as Common Table Expressions. The CTE rewritten as a Derived Table would be:

    SELECT *
    FROM (
      SELECT ListPrice, (ListPrice * .95) AS SellPrice
      FROM Production.Product
      )
    MyDerivedTable

    Common Table Expressions will not displace Derived Tables however. There will still be many instances when Derived Tables will be a better fit.  However, in some complex statements, Common Tables Expression may be clearer to understand.

    Recursive Queries

    One of the most powerful features of Common Table Expressions is their ability to be self-referenced by name, allowing for a recursive query. A Recursive Query is a query that calls itself. Below is a modified example of BOL recursive query. The purpose of the statement is to display each employee at Adventure Works, and who their manager is. The Employee table is self joined, where the ManagerID joins back on the same table to the EmployeeID.

    The statement first looks for all top-level managers, the records where the ManagerID is null. In this table, there is only one. Next, we will self-reference this CTE by using its name “DirectReports” joined back to our top-level managers.

    USE AdventureWorks ;
    GO
    WITH DirectReports(LoginID, ManagerID, EmployeeID) AS
    (
        SELECT LoginID, ManagerID, EmployeeID
        FROM HumanResources.Employee
        WHERE ManagerID IS NULL
        UNION ALL
        SELECT e.LoginID, e.ManagerID, e.EmployeeID
    	FROM HumanResources.Employee e
        INNER JOIN DirectReports d
        ON e.ManagerID = d.EmployeeID
    )
    SELECT *
    FROM DirectReports ;
    GO

    Running this statement produces the following result set:

    The first result line shows Ken, as the top-level manager, reporting to no one. Beneath him reports David, Terri, Peter, Jean, Laura, James and Brian. At Stephen, we see a change, with him reporting to Brian.

    The Recursive Common Table Expression introduces some additional syntax. The statement now has two definition components. The first is called the Anchor Member:

    SELECT LoginID, ManagerID, EmployeeID
        FROM HumanResources.Employee
        WHERE ManagerID IS NULL

    This statement must be followed by a UNION ALL. The purpose of the UNION ALL is to tie the results of two statements into one result set.

    The next definition is called the recursive member. It calls back to itself using the CTE name; INNER JOIN DirectReports d

    MAXRECURSION

    The key word MAXRECURSION can be used as a query hint to stop a statement after a defined number of loops. This can stop a CTE from going into an infinite loop on a poorly coded statement. To use it in our above example, include it on the last line;

    SELECT *
    FROM DirectReports;
    OPTION (MAXRECURSION 3);

    Conclusion

    New in SQL 2005, Common Table Expressions will be worth exploring for anyone doing TSQL work. Their use in Recursive Queries alone warrants them worthy of consideration. Combined with their straightforward syntax, expect to see them used frequently in complex statements.

    » See All Articles by Columnist Don Schlichting

    Yazı kategorisi: CTE, SQL, Sql Server, Transact-SQL | » yorum bırak;

    Find blocking processes using recursion in SQL Server 2005

    Yazan: esersahin 23/11/2008

    http://www.builderau.com.au/program/sqlserver/soa/Find-blocking-processes-using-recursion-in-SQL-Server-2005/0,339028455,339286600,00.htm

    Blocking occurs in SQL Server 2005 when one process has one or more records locked, while another process tries to acquire locks on the same set (or subset) of records.

    This causes the second process to wait until the first process is done so it can acquire the records; this can cause other processes to be blocked if they are waiting on the resources that the second connection has acquired. These processes are ultimately dependent upon the first process to complete its work before they can complete theirs. This can create a daisy-chain of processes waiting to complete their work.

    This blocking situation is a bit different than a deadlock scenario. A deadlock occurs when process A has ownership of resources that process B needs. Process B, in turn, owns resources that process A needs to complete its work. In theory, this would last forever. Fortunately, SQL Server 2005 has algorithms to find these scenarios and stop one process so the other can finish its work. On the other hand, blocking can last a lot longer than a deadlock because it isn’t stopped automatically by SQL Server 2005. The blocked processes must wait until the blocking connection finishes its work before they can finish theirs.

    Finding blocking connections

    SQL Server 2005 has several system tables and views that can provide a ton of insight into blocking problems that you may be facing in your database environment.

    Through these procedures, you can find blocking chains. I define a blocking chain as one particular process is blocking one or more processes, and those processes are blocking other processes. These blocking chains happen all the time, especially when there are instances of long-running transactions. Many times, I have seen a DBA find the process that is causing the most locking and stop the process. This is usually not a great idea, and it is definitely not the way to find the root of the problem. The processes that cause the most locking are usually doing so because they are being blocked by another process.

    The following statement pulls information from the sys.sysprocesses system table for user processes. The information is placed into a temporary table named #Processes that I will use for my recursive Common Table Expression (CTE) query. The sys.sysprocesses table is a great tool because it contains a lot of data in one table. (The sys.sysprocesses table may not be included in future versions of SQL Server.) I can also use the CROSS APPLY construct to get the actual SQL statement that is being used based upon the sql_handle value in the table.

    
    SELECT
                 s.spid, BlockingSPID = s.blocked, DatabaseName = DB_NAME(s.dbid),
                 s.program_name, s.loginame, ObjectName = OBJECT_NAME(objectid,                      s.dbid), Definition = CAST(text AS VARCHAR(MAX))
     INTO        #Processes
     FROM      sys.sysprocesses s
     CROSS APPLY sys.dm_exec_sql_text (sql_handle)
     WHERE
                s.spid > 50
    

    The following statement declares and uses the recursive CTE for finding blocking chains in the temp table I just created for the sys.sysprocesses table.

    The WITH statement declares the CTE with the code inside of the parentheses being the body of the expression. In the first SELECT statement, I am finding all processes that are not blocked themselves but are blocking at least one other process. To do this, I just join the #Processes temp table to itself based on the SPID field and the BlockingSPID field. This is a crucial step in the query, as I am locating the starting point for finding the chain of processes that are being blocked.

    This first SELECT can essentially be thought of as a “base case,” which will act as a root for the rest of the recursion. This SELECT has a couple of functions that will allow me to tell the hierarchy of the recursion. The RowNo field uses the ROW_NUMBER function which will indicate the separate number of processes that are blocking other processes. The LevelRow, which I initially declare as 0, will indicate the recursion level for that particular blocking process. (This information will make more sense later in the article when I give an example of the information that is provided by the CTE.)

    The next SELECT statement after UNION ALL (there always has to be a UNION ALL in a recursive CTE) is the recursive section; it joins what is returned by the CTE and the #Processes temp table based upon the BlockingSPID from the temp table and the SPID field from the CTE. For this statement, I am only concerned with the blocked statements.

    The last SELECT statement runs the recursive CTE and returns the values.

    
    WITH Blocking(SPID, BlockingSPID, BlockingStatement, RowNo, LevelRow)
     AS
     (
          SELECT
           s.SPID, s.BlockingSPID, s.Definition,
           ROW_NUMBER() OVER(ORDER BY s.SPID),
           0 AS LevelRow
         FROM
           #Processes s
           JOIN #Processes s1 ON s.SPID = s1.BlockingSPID
         WHERE
           s.BlockingSPID = 0
         UNION ALL
         SELECT
           r.SPID,  r.BlockingSPID, r.Definition,
           d.RowNo,
           d.LevelRow + 1
         FROM
           #Processes r
          JOIN Blocking d ON r.BlockingSPID = d.SPID
         WHERE
           r.BlockingSPID > 0
     )
     SELECT * FROM Blocking
     ORDER BY RowNo, LevelRow
    

    Analysing the sample code

    In the output, there are two processes blocking other processes; this is identified in a couple of ways. First, there are two records that have a 0 in the BlockingSPID field. These records will have the value 0 in the LevelRow field; they are also the “base case” for the recursion. The RowNo field indicates the separate set of blocking groups. The first set of statements that are blocked have the value 1 for the RowNo field, the second set of statements that are blocked have the value 2 for the RowNo field, etc.

    In analysing the first group of blocked statements, I see that procedure usp_StoredProcedure1 is the initial point of blocking — that procedure is blocking usp_StoredProcedure2. The LevelRow field can be used here, or I can try to match the SPID in one row to the BlockingSPID value in the next row. I find that the LevelRow field is the easier of the two choices. I also see the following:

    |>usp_StoredProcedure2 is blocking usp_StoredProcedure3.
    |>usp_StoredProcedure3 is blocking usp_StoredProcedure4.
    |>usp_StoredProcedure 4 is blocking two stored procedures: usp_StoredProcedure5 and usp_StoredProcedure14. The LevelRow value is the same for these two rows.
    |>The blocking analysis concludes for RowNo 1 with usp_StoredProcedure5 blocking the final statement usp_StoredProcedure6.

    Using this tool

    There are two very useful ways to use this tool for finding blocking on your SQL Server 2005 system. One way is to run it every couple of minutes and store the results in a table for later analysis. This is very handy if you encounter blocking problems during the night because it allows you to find the problem the next day. The other way is to wrap the functionality up into a system stored procedure that you can easily call anytime if someone is complaining about sessions timing out or the database engine running slow.

    Yazı kategorisi: CTE, SQL, Sql Server, Transact-SQL, WITH | » yorum bırak;

    CTE – CTE’s with Variables and Parameters

    Yazan: esersahin 23/11/2008

    http://sqlserverpedia.com/wiki/CTE_-_CTE%E2%80%99s_with_Variables_and_Parameters

    See Also: Main_PageTransact SQL Coding TechniquesReusable Coding TechniquesCommon Table Expressions

    CTE can reference variables declared within the same batch or parameters used within the same code module. For example, the following query uses variables with CTE:

    DECLARE @n TINYINT
    SET @n = 3;
    WITH direct_reports_CTE
    AS
     (
     SELECT
    	  TOP (@n) ManagerID AS manager_id,
    	  COUNT(*) AS number_of_direct_reports
     FROM HumanResources.Employee
     WHERE ManagerID IS NOT NULL
     GROUP BY ManagerID
     ORDER BY 2 DESC
     )
    SELECT SUBSTRING(LoginID, (CHARINDEX('\', LoginID)+1), (LEN(LoginID)-
    CHARINDEX('\', LoginID)-1)) AS ManagerName,
     number_of_direct_reports
    FROM direct_reports_CTE a
    INNER JOIN HumanResources.Employee b ON a.Manager_ID = b.EmployeeID
    ORDER BY 2 DESC

    Next set of statements creates a stored procedure which exploits a CTE referencing a stored procedure parameter:

    CREATE PROC return_top_bosses (@n TINYINT)
    AS
    WITH direct_reports_CTE
    AS
     (
     SELECT
    	  TOP (@n) ManagerID AS manager_id,
    	  COUNT(*) AS number_of_direct_reports
     FROM HumanResources.Employee
     WHERE ManagerID IS NOT NULL
     GROUP BY ManagerID
     ORDER BY 2 DESC
     )
    SELECT
     SUBSTRING(LoginID, (CHARINDEX('\', LoginID)+1), (LEN(LoginID)-
     CHARINDEX('\', LoginID)-1)) AS ManagerName,
     number_of_direct_reports
    FROM direct_reports_CTE a
    INNER JOIN HumanResources.Employee b ON a.Manager_ID = b.EmployeeID
    ORDER BY 2 DESC

    You could easily create a view or a user-defined function using the same CTE. We could call the stored procedure created by the previous statement as follows:

    EXEC return_top_bosses 5

    Yazı kategorisi: CTE, SQL, Sql Server, Transact-SQL, sqlserverpedia | » yorum bırak;

    Simplify queries with SQL Server 2005 common table expressions (CTEs)

    Yazan: esersahin 23/11/2008

    http://searchsqlserver.techtarget.com/tip/0,289483,sid87_gci1299502,00.html#

    SQL Server 2005 introduced a valuable new Transact-SQL language component – a common table expression (CTE) — that can be a handy alternative to derived tables and views. By using CTEs, you can create named result sets to reference from within your SELECT, INSERT, UPDATE, and DELETE statements without having to persist any metadata about the result set structure. In this article, I explain how to create CTEs in SQL Server 2005 – including how to create a recursive query using a CTE – and provide several examples that demonstrate how they work. Note that for these examples I use the AdventureWorks sample database that ships with SQL Server 2005.

     

    Creating a basic CTE in SQL Server 2005

    You construct CTEs by adding a WITH clause before the SELECT, INSERT, UPDATE, or DELETE statement. The following syntax shows the basic structure of the WITH clause and CTE definition:

    [WITH <CTE_definition> [,...n]]
    <SELECT, INSERT, UPDATE, or DELETE statement that
    calls the CTEs>

    <CTE_definition>::=
    CTE_name [(column_name [,...n ])]
    AS
    (
    CTE_query
    )

     

    As the syntax shows, you can define multiple CTEs within the optional WITH clause. The CTE definition includes the name of the CTE, the CTE column names, the AS keyword and the CTE query enclosed in parentheses. Note that the number of CTE column names must match the number of columns returned by the CTE query. In addition, the column names are optional if the CTE query supplies all column names.

    Now that you have a basic idea of the CTE syntax in SQL Server, let’s look at an example of a CTE definition to help better understand this syntax. The following example defines a CTE named ProductSold and then references the CTE within a SELECT statement:

    WITH ProductSold (ProductID, TotalSold)
    AS
    (
    SELECT ProductID, SUM(OrderQty)
    FROM Sales.SalesOrderDetail
    GROUP BY ProductID
    )
    SELECT p.ProductID, p.Name, p.ProductNumber,
    ps.TotalSold
    FROM Production.Product AS p
    INNER JOIN ProductSold AS ps
    ON p.ProductID = ps.ProductID

    As you can see, a WITH clause precedes the SELECT statement that references the CTE. The first line of the WITH clause includes the name of the CTE (ProductSold) and the names of the two columns within the CTE (ProductID and TotalSold). Next comes the AS keyword, followed by the CTE query in parentheses. In this case, the CTE query returns the total number of individual products sold.

    The SELECT statement that follows the WITH clause references the CTE by name when joining the Product table to the CTE, based on the ProductID columns. The statement calls the CTE as it would a table or view. However, unlike a table or view, the CTE is available only to the statement that immediately follows the WITH clause. If you reference the CTE in a subsequent statement — without redefining the CTE — you’ll receive an error.

    One advantage to using common table expressions is that you can reference a CTE multiple times in the calling statement. For example, the following statement defines a CTE named Employees and then calls that CTE twice in the SELECT statement that follows the WITH clause:

    WITH Employees (EmpID, MgrID, FName, LName, Email)
    AS
    (
    SELECT e.EmployeeID, e. ManagerID,
    c.FirstName, c.LastName, c.EmailAddress
    FROM HumanResources.Employee e
    INNER JOIN Person.Contact c
    ON e.ContactID = c.ContactID
    )
    SELECT e.FName + ' ' + e.LName AS EmpName,
    e.Email AS EmpEmail,
    m.FName + ' ' + m.LName AS MgrName,
    m.Email AS MgrEmail
    FROM Employees e
    LEFT OUTER JOIN Employees m
    ON e.MgrID = m.EmpID

    SELECT ProductID, AVG(StandardCost)
    FROM Production.ProductCostHistory
    GROUP BY ProductID
    ),
    Sold (ProductID, AvgSold)
    AS
    (
    SELECT ProductID, AVG(OrderQty)
    FROM Sales.SalesOrderDetail
    GROUP BY ProductID
    )
    SELECT p.ProductID, p.Name,
    (AvgCost * AvgSold)AS TotalCost
    FROM Sold s
    INNER JOIN Production.Product p
    ON s.ProductID = p.ProductID
    INNER JOIN Cost c
    ON p.ProductID = c.ProductID
    SELECT ProductID, AVG(StandardCost)
    FROM Production.ProductCostHistory
    GROUP BY ProductID
    ),
    Sold (ProductID, AvgSold)
    AS
    (
    SELECT ProductID, AVG(OrderQty)
    FROM Sales.SalesOrderDetail
    GROUP BY ProductID
    ),
    Total (ProductID, TotalCost)
    AS
    (
    SELECT c.ProductID, (AvgCost * AvgSold)
    FROM Cost c
    INNER JOIN Sold s
    ON c.ProductID = s.ProductID
    )
    SELECT p.ProductID, p.Name, t.TotalCost
    FROM Production.Product p
    INNER JOIN Total t
    ON p.ProductID = t.ProductID

    In this example, the SQL Server CTE query returns a list of employee IDs, names and email addresses, as well as their managers’ IDs. The SELECT statement following the WITH clause then joins the CTE with itself to return the managers’ names and email addresses. You can achieve the same results by using derived tables (subqueries), but that means repeating the same subquery multiple times and working with code that’s more complex.

    Creating multiple CTEs in a WITH clause

    As you saw in the CTE syntax, you can define multiple CTEs in your WITH clause and then call each of those CTEs as often as necessary in the statement that follows. Take a look at the example below that demonstrates how this works. The following WITH clause includes two CTE definitions:

    WITH
    Cost (ProductID, AvgCost)
    AS
    (

    The first CTE definition defines a CTE named Cost, and the second definition defines one named Sold. The Cost CTE returns the average cost of each product based on its cost history. The Sold CTE returns the average number of products sold per order. The SELECT statement after the WITH clause joins these two CTEs with the Product table to return the total cost of each product based on the average number sold and the average cost of the product.

    You can easily define multiple CTEs within the WITH clause, but you can take this a step further by defining CTEs that reference the CTEs defined before it. For example, the WITH clause below defines three CTEs (Cost, Sold, and Total):

    WITH
    Cost (ProductID, AvgCost)
    AS
    (

    Notice that the CTE query in the Total CTE definition joins the Cost and Sold CTEs, whose CTE definitions precede Total. You cannot reference an undefined CTE. For example, you cannot reference the Total CTE within the Sold CTE. Now, the SELECT statement that follows the WITH clause needs to join the Product table to the Total CTE only, rather than joining to both the Cost and Sold CTEs.

    Creating a recursive common table expression

    One of the most valuable features of a CTE in SQL Server is its ability to create a recursive query — a type of query that repeatedly references itself in order to return subsets of data. A recursive query is most commonly used to return hierarchical data. For instance, the Employee table in the AdventureWorks database includes the manager ID of each employee. The manager ID is actually the employee ID of that manager. As a result, the Employee table contains the entire hierarchical direct reports structure from the CEO on down.

    You can define a CTE to retrieve this hierarchical structure by creating a CTE query that uses a UNION ALL, UNION, INTERSECT, or EXCEPT operator to join multiple SELECT statements. The best way to show you how this works is through an example.

    In this WITH clause, the CTE query includes two SELECT statements joined by a UNION ALL operator:

    WITH Reports (EmpLevel, EmpID, ContactID, MgrID)
    AS
    (
    SELECT 1, EmployeeID, ContactID, ManagerID
    FROM HumanResources.Employee
    WHERE ManagerID IS NULL
    UNION ALL
    SELECT r.EmpLevel + 1, e.EmployeeID, e.ContactID,
    e.ManagerID
    FROM HumanResources.Employee e
    INNER JOIN Reports r
    ON e.ManagerID = r.EmpID
    )
    SELECT r.EmpLevel, r.EmpID,
    c.FirstName + ‘ ‘ + c.LastName AS EmpName,
    MgrID
    FROM Reports r
    INNER JOIN Person.Contact c
    ON r.ContactID = c.ContactID
    ORDER BY r.EmpLevel, r.MgrID, r.EmpID

    The first SELECT statement in the CTE query retrieves only the top-level employee — the CEO. To select the top-level employee, use a WHERE clause that specifies that the ManagerID value is null.

    Tips on tuning SQL Server performance:
  • T-SQL error handling with Try…Catch blocks 
  • Tricks to increase SQL Server query performance 
  • T-SQL performance problems and solutions
  • In other words, this is the person who does not directly report to another manager. Note: The first column in the SELECT statement is 1. This is used to designate that the employee returned by this query is at the top level, Level 1.

    The second SELECT statement (after the UNION ALL operator) joins the Employee table to the Reports CTE itself based on the manager and employee IDs. By self-referencing the CTE in this way, SQL Server automatically treats this as a recursive query and repeats the query as many times as necessary to return each level of employees. Every time the query runs, the first column adds 1 to the value so that each level is incremented by 1.

    The SELECT statement that follows the WITH clause joins the Reports CTE to the Contact table to retrieve the employees’ name. The following query results show a sample of the data returned by this statement:

    EmpLevel EmpID EmpName MgrID
    1 109 Ken Sanchez NULL
    2 6 David Bradley 109
    2 12 Terri Duffy 109
    2 42 Jean Trenary 109
    2 140 Laura Norman 109
    2 148 James Hamilton 109
    2 273 Brian Welcker 109
    3 2 Kevin Brown 6
    3 46 Sariya Harnpadoungsataya 6
    3 106 Mary Gibson 6
    3 119 Jill Williams 6
    3 203 Terry Eminhizer 6
    3 269 Wanida Benshoof 6
    3 271 John Wood 6
    3 272 Mary Dempsey 6
    3 3 Roberto Tamburello 12
    3 66 Janaina Bueno 42
    3 102 Dan Bacon 42
    3 117 François Ajenstat 42
    3 128 Dan Wilson 42
    3 149 Ramesh Meyyappan 42
    3 150 Stephanie Conroy 42
    3 176 Karen Berg 42
    3 30 Paula Barreto de Mattos 140
    3 71 Wendy Kahn 140
    3 103 David Barber 140
    3 139 David Liu 140
    3 21 Peter Krebs 148
    3 44 A. Scott Wright 148
    3 200 Hazem Abolrous 148
    3 218 Gary Altman 148
    3 268 Stephen Jiang 273
    3 284 Amy Alberts 273
    3 288 Syed Abbas 273
    4 4 Rob Walters 3
    4 9 Gail Erickson 3
    4 11 Jossef Goldberg 3

    The results are listed according to the employee’s level. Notice that the second through seventh rows show a MgrID value of 109, which is the ID of the top-level employee shown in the first row. The subsequent rows reflect the same hierarchical nature of the data.

    Recursive CTEs, like other common table expressions in SQL Server, provide powerful tools for retrieving data. Unlike views, you don’t have to persist the metadata. And unlike derived tables, you don’t have to repeat code unnecessarily. CTEs help simplify complex code by letting you more easily separate your code into discrete units. And when it comes to recursive queries, CTEs can’t be beat. When you first start using CTEs, you might have to play around a little to become comfortable with them, but once you do, you’ll never go back.

     

    ABOUT THE AUTHOR:   
     
    Robert Sheldon is a technical consultant and the author of numerous books, articles and training material related to Microsoft Windows and various relational database management systems (including SQL Server) as well as business intelligence design and implementation. He is also the author of the novel Dancing the River Lightly. You can find more information at http://www.rhsheldon.com.

    Yazı kategorisi: CTE, Sql Server, WITH | » yorum bırak;