1. Trang chủ
  2. » Công Nghệ Thông Tin

Microsoft SQL Server 2008 R2 Unleashed- P176 ppsx

10 57 0

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 10
Dung lượng 213,51 KB

Nội dung

ptg 1694 CHAPTER 43 Transact-SQL Programming Guidelines, Tips, and Tricks only in a trigger. The inserted and deleted tables provide access to the new/old images of the modified rows; this is similar to how they provide the information in triggers. In an INSERT statement, you are allowed to access only the inserted table. In a DELETE state- ment, you are allowed to access only the deleted table. In an UPDATE statement, you are allowed to access both the inserted and deleted tables. Following is the general syntax of the OUTPUT clause: UPDATE [ TOP ( expression ) [ PERCENT ] ] tablename SET { column_name = { expression | DEFAULT | NULL } | @variable = expression | @variable = column = expression [ , n ] } [ , n ] OUTPUT { DELETED | INSERTED | from_table_name}.{* | column_name} | scalar_expression [ INTO { @table_variable | output_table } [ ( column_list ) ] ] } [ FROM { table_name } [ , n ] ] [ WHERE search_conditions ] DELETE [ TOP ( expression ) [ PERCENT ] ] tablename OUTPUT { DELETED | from_table_name}.{* | column_name} | scalar_expression [ INTO { @table_variable | output_table } [ ( column_list ) ] ] } [ FROM ] table_name [ FROM table_name [ , n ] ] [ WHERE search_conditions ] INSERT [ TOP ( expression ) [ PERCENT ] ] [ INTO ] tablename { [ ( column_list ) ] [ OUTPUT { INSERTED | from_table_name}.{* | column_name} | scalar_expression [ INTO { @table_variable | output_table } [ ( column_list ) ] ] ] } { VALUES ( { DEFAULT | NULL | expression } [ , n ] ) | SELECT_statement } } The output table (output_table) may be a table variable, permanent table, or temporary table. If column_list is not specified, the output table must have the same number of columns as the OUTPUT result set. If column_list is specified, any omitted columns must either allow NULL values or have default values assigned to them. Any identity or computed columns in the output table must be skipped. In addition, output_table cannot have any enabled triggers defined on it, participate on either side of a foreign key constraint, or have any check constraints or enabled rules. ptg 1695 The OUTPUT Clause 43 One use of the OUTPUT clause is to verify the rows being deleted, updated, or inserted: begin tran delete from sales_big output deleted.* where sales_id in (select top 10 sales_id from sales_big order by ord_date) rollback go sales_id stor_id ord_num ord_date qty payterms title_id 168745 7067 P2121 2005-06-15 00:00:00.000 40 Net 30 TC3218 168746 7067 P2121 2005-06-15 00:00:00.000 20 Net 30 TC4203 168747 7067 P2121 2005-06-15 00:00:00.000 20 Net 30 TC7777 20 7067 P2121 2005-06-15 00:00:00.000 40 Net 30 TC3218 21 7067 P2121 2005-06-15 00:00:00.000 20 Net 30 TC4203 22 7067 P2121 2005-06-15 00:00:00.000 20 Net 30 TC7777 337470 7067 P2121 2005-06-15 00:00:00.000 40 Net 30 TC3218 337471 7067 P2121 2005-06-15 00:00:00.000 20 Net 30 TC4203 337472 7067 P2121 2005-06-15 00:00:00.000 20 Net 30 TC7777 506195 7067 P2121 2005-06-15 00:00:00.000 40 Net 30 TC3218 Another possible use of the OUTPUT clause is as a purge/archive solution. Suppose you want to periodically purge historic data from the sales_big table but also want to copy the purged data into an archive table called sales_big_archive. Rather than writing a process that has to select the rows to be archived before deleting them, or putting a delete trigger on the table, you could use the OUTPUT clause to insert the deleted rows into the archive table. On approach would be to implement a loop to delete historic data (for example, delete rows for the oldest month in the sales_big table) in chunks, using the TOP clause to specify the chunk size. The OUTPUT clause can be specified to copy the deleted rows into the sales_big_archive table, as shown in Listing 43.32. LISTING 43.32 Implementing a Purge/Archive Scenario, Using the OUTPUT Clause declare @purge_date datetime, @rowcount int find the oldest month in the sales_big table select @purge_date = dateadd(day, - (datepart(day, min(ord_date))) + 1, dateadd(month, 1, min(ord_date))), @rowcount = 1000 from sales_big while @rowcount = 1000 begin delete top (1000) sales_big output deleted.* into sales_big_archive where ord_date < @purge_date set @rowcount = @@rowcount end ptg 1696 CHAPTER 43 Transact-SQL Programming Guidelines, Tips, and Tricks In addition to referencing columns in the table being modified by using the INSERTED or DELETED qualifier, you can also retrieve information from another table included in the FROM clause of a DELETE or an UPDATE statement used to specify the rows to update or delete: begin tran delete top (5) sales output t.title_id from sales s join titles t on t.title_id = s.title_id where t.pub_id = ‘9906’ rollback go title_id FI9620 CH2080 BI7178 CH8924 FI2680 When used with an UPDATE command, OUTPUT produces both a deleted and an inserted table. The deleted table contains the values before the UPDATE command, and the inserted table has the values after the UPDATE command. The OUTPUT clause is also useful for retrieving the value of identity or computed columns after an INSERT or an UPDATE operation. Listing 43.33 shows an example of OUTPUT being used to capture the computed column as the result of an UPDATE. LISTING 43.33 Using OUTPUT to Capture a Computed Column create table UpdateOutputTest (col1 tinyint, col2 tinyint, computed_col3 as convert(float, col2/convert(float, col1))) go insert UpdateOutputTest (col1, col2) output inserted.computed_col3 values (10, 20) insert UpdateOutputTest (col1, col2) output inserted.computed_col3 values (10, 25) go computed_col3 ptg 1697 The OUTPUT Clause 43 2 computed_col3 2.5 declare @output_table TABLE (del_col1 int, ins_col1 int, del_col2 int, ins_col2 int, del_computed_col3 float, ins_computed_col3 float, mod_date datetime) update UpdateOutputTest set col2 = col2/5.0 output deleted.col1, inserted.col1, deleted.col2, inserted.col2, deleted.computed_col3, inserted.computed_col3, getdate() into @output_table output deleted.computed_col3, inserted.computed_col3, getdate() as mod_date select del_col1, ins_col1, del_col2, ins_col2, del_computed_col3 as del_col3, ins_computed_col3 as ins_col3, mod_date from @output_table go computed_col3 computed_col3 mod_date 2 0.4 2010-02-28 19:48:34.240 2.5 0.5 2010-02-28 19:48:34.240 del_col1 ins_col1 del_col2 ins_col2 del_col3 ins_col3 mod_date 10 10 20 4 2 0.4 2010-02-28 19:48:34.240 10 10 25 5 2.5 0.5 2010-02-28 19:48:34.240 The UPDATE statement in Listing 43.33 also demonstrates the capability to use OUTPUT to both insert values into a table and return values to the caller. Note that the OUTPUT clause is not supported in DML statements that reference local parti- tioned views, distributed partitioned views, remote tables, or INSERT statements that contain an execute_statement. Columns returned from OUTPUT reflect the data as it is after the INSERT, UPDATE, or DELETE statement has completed but before any triggers on the target table are executed. ptg 1698 CHAPTER 43 Transact-SQL Programming Guidelines, Tips, and Tricks Common Table Expressions A common table expression (CTE) is an ANSI SQL-99 expression that produces a table that is referred to by name within the context of a single query. The general syntax for a CTE is as follows: WITH expression_name [ ( column_name [ , n ] ) ] AS ( CTE_query_definition ) The WITH clause, in effect, defines a table and its columns. Note that the syntax of the WITH clause is similar to that of a view. You can think of a CTE as a temporary view that lasts only for the life of the query that defines the CTE. Listing 43.34 shows an example of a simple CTE. This CTE is used to return the average and maximum sales quantities for each store. The CTE is then joined to the sales table to return the average and maximum sales quantity for the store, along with sales records for a specific title_id. LISTING 43.34 An Example of a Simple CTE with sales_avg (stor_id, avg_qty, max_qty) as (select stor_id, avg(qty), max(qty) from sales group by stor_id) select top 5 s.stor_id, s.ord_num, convert(varchar(10), ord_date, 101) as ord_date, qty, title_id, avg_qty, max_qty from sales s join sales_avg a on s.stor_id = a.stor_id where s.title_id = ‘DR8514’ go stor_id ord_num ord_date qty title_id avg_qty max_qty A004 ONGGGGGGGGGGGGGGG 09/13/2006 1224 DR8514 1008 1716 A068 ONEEEEEEEEEEE 09/02/2007 1572 DR8514 961 1572 A071 ONWWWWWWWWWWWWWWWWWW 08/20/2006 1728 DR8514 948 1728 A161 ONDDDDDDDDDDDD 05/25/2006 624 DR8514 829 1668 A203 ONGGGGGGGGGGGGGGGGGG 11/16/2006 1572 DR8514 1056 1692 NOTE If the WITH clause for a CTE is not the first statement in the batch, you should delimit it from the preceding statement by placing a semicolon ( ;) in front of it. The semicolon is used to avoid ambiguity with other uses of the WITH clause (for example, for table hints). Including a semicolon is not necessary in all cases, but it is recommended that you use it consistently to avoid problems. ptg 1699 Common Table Expressions 43 It is also possible to define multiple CTEs in a single query, with each CTE delimited by a comma. Each CTE is able to refer to previously defined CTEs. Listing 43.35 shows an example of a nested CTE that calculates the minimum, maximum, and difference of counts of store orders. LISTING 43.35 An Example of Multiple CTEs in a Single Query WITH store_orders(stor_id, cnt) AS ( SELECT stor_id, COUNT(*) FROM sales GROUP BY stor_id ), MinMaxCTE(MN, MX, Diff) AS ( SELECT MIN(Cnt), MAX(Cnt), MAX(Cnt)-MIN(Cnt) FROM store_orders ) SELECT * FROM MinMaxCTE go MN MX Diff 1 22 21 A CTE must be followed by a single SELECT, INSERT, UPDATE, or DELETE statement that references some or all of the CTE columns. A CTE can also be specified in a CREATE VIEW statement as part of the defining SELECT statement of the view. Listing 43.36 shows an example of a CTE used in a DELETE statement. LISTING 43.36 An Example of a CTE in a DELETE with oldest_sales (stor_id, ord_num, ord_date) as (select top 100 stor_id, ord_num, ord_date from sales_big order by ord_date) delete sales_big from sales_big s, oldest_sales o where s.stor_id = o.stor_id and s.ord_num = o.ord_num and s.ord_date = o.ord_date go Most valid SELECT statement constructs are allowed in a CTE, except the following: . COMPUTE or COMPUTE BY . ORDER BY (except when a TOP clause is specified) . INTO . OPTION clause with query hints ptg 1700 CHAPTER 43 Transact-SQL Programming Guidelines, Tips, and Tricks . FOR XML . FOR BROWSE Recursive Queries with CTEs Nonrecursive CTEs are ANSI SQL-99 compliant expressions that provide T-SQL coding flex- ibility. However, for each nonrecursive CTE, there is usually another T-SQL construct that can be used to achieve the same results (for example, derived tables). The real power and capability of CTEs is revealed when you use them to create recursive queries. A recursive CTE can help simplify the code required to run a recursive query within a SELECT, INSERT, UPDATE, DELETE, or CREATE VIEW statement. Recursive queries are often useful for expanding a hierarchy stored in a relational table (for example, displaying employees in an organizational chart). In previous versions of SQL Server, a recursive query usually required using temporary tables, cursors, and logic to control the flow of the recursive steps. A CTE is considered recursive when it refers to itself within the CTE definition. Recursive CTEs are constructed from at least two queries. One is a nonrecursive query, also referred to as the anchor member (AM). The other is the recursive query, also referred to as the recursive member (RM). The queries are combined using the UNION ALL operator. The following pseudocode defines the basic structure of a recursive CTE: WITH cte_name ( column_name [, n] ) AS ( CTE_query_definition1 Anchor member (AM) is defined. UNION ALL CTE_query_definition2 Recursive member (RM) is referencing cte_name. ) Statement using the CTE SELECT col_list FROM cte_name Logically, you can think of the algorithm implementing the recursive CTE as follows: 1. The anchor member is activated, and the initial result set (R) is generated. 2. The recursive member is activated, using the initial result set (Rn) as input and generating result set Rn+1. 3. The logic of step 2 is run repeatedly, incrementing the step number (n) until an empty set is returned. 4. The outer query is executed, getting the cumulative ( UNION ALL) result of all the pre- vious steps when referring to the recursive CTE. You can have more than two members in a recursive CTE, but only the UNION ALL opera- tor is allowed between a recursive member and another recursive or nonrecursive member. Other operators, such as UNION, are allowed only between nonrecursive members. ptg 1701 Common Table Expressions 43 Recursive CTEs also require an exact match of the columns in all members, including the same data type, length, and precision. Listing 43.37 shows a simple recursive CTE that generates a list of sequential numbers. Note that the AM generates the base result, and the RM following the UNION ALL controls the recursion. It is important in this example that a valid endpoint be defined to avoid infinite recursion. LISTING 43.37 An Example of a Simple Recursive CTE with numlist (val) as (select 1 union all select val + 1 from numlist where val < 10) select * from numlist go val 1 2 3 4 5 6 7 8 9 10 The following sections present some examples and uses of recursive CTEs. Using Recursive CTEs for Expanding a Hierarchy For this hierarchy example, we use the parts table in the bigpubs2008 database. This table contains a simplified hierarchy of car parts, as shown in Figure 43.1. In the parts table, any part that is a subpart of another part has the parent part ID stored in the parentpartid column. The parentpartid column is a foreign key that references the partid column. Therefore, the parentpartid must either correspond to a valid partid within the table or be NULL. For example, the car itself has NULL in the parentpartid column. Following are some common requests that might be run on the parts table: . Return all the parts for the engine. ptg 1702 CHAPTER 43 Transact-SQL Programming Guidelines, Tips, and Tricks Car Body DriveTrain Frame Engine Transmission Driveshaft Axle Flywheel Clutch Gearbox Reverse Gear First Gear Second Gear Third Gear Fourth Gear Radiator Intake Manifold Exhaust Manifold Carburetor Piston Crankshaft Piston Rings Float Valve FIGURE 43.1 The parts table hierarchy. The first request is probably the most common one: returning a part (for example, the engine, which has partid = 2) and all subparts. The recursive CTE shown in Listing 43.38 provides a solution to this request. LISTING 43.38 A Recursive CTE to Return a Part and All Subparts WITH PartsCTE(partid, partname, parentpartid, lvl) AS ( SELECT partid, partname, parentpartid, 0 FROM PARTS WHERE partid = 2 Engine UNION ALL SELECT P.partid, P.partname, P.parentpartid, PP.lvl+1 FROM Parts as P JOIN PartsCTE as PP ON P.parentpartid = PP.Partid ) . Show me all parts that are two levels below the drivetrain. . Show me all the parts in such a way that it is easy to see their hierarchical depen- dencies. ptg 1703 Common Table Expressions 43 SELECT PartID, Partname, ParentPartid, lvl FROM PartsCTE go PartID Partname ParentPartid lvl 2 Engine 1 0 5 Radiator 2 1 6 Intake Manifold 2 1 7 Exhaust Manifold 2 1 8 Carburetor 2 1 13 Piston 2 1 14 Crankshaft 2 1 21 Piston Rings 13 2 11 Float Valve 8 2 Notice that the lvl value is repeatedly incremented with each recursive invocation of the CTE. You can use this level counter to limit the number of iterations in the recursion. For example, Listing 43.39 shows an example of a CTE that returns all parts two levels below the drivetrain. LISTING 43.39 A Recursive CTE to Return All Subparts Two Levels Below a Part WITH PartsCTE(partid, partname, parentpartid, lvl) AS ( SELECT partid, partname, parentpartid, 0 FROM PARTS WHERE partid = 1 Drivetrain UNION ALL SELECT P.partid, P.partname, P.parentpartid, PP.lvl+1 FROM Parts as P JOIN PartsCTE as PP ON P.parentpartid = PP.Partid where lvl < 2 ) SELECT PartID, Partname, ParentPartid, lvl FROM PartsCTE where lvl = 2 go PartID Partname ParentPartid lvl 9 Flywheel 3 2 . 43 Transact -SQL Programming Guidelines, Tips, and Tricks . FOR XML . FOR BROWSE Recursive Queries with CTEs Nonrecursive CTEs are ANSI SQL- 99 compliant expressions that provide T -SQL coding flex- ibility executed. ptg 1698 CHAPTER 43 Transact -SQL Programming Guidelines, Tips, and Tricks Common Table Expressions A common table expression (CTE) is an ANSI SQL- 99 expression that produces a table. table (for example, displaying employees in an organizational chart). In previous versions of SQL Server, a recursive query usually required using temporary tables, cursors, and logic to control

Ngày đăng: 05/07/2014, 02:20

TỪ KHÓA LIÊN QUAN