G. Green 1
Options include: Script Files already covered APIs last course topic Database-Stored Code our focus 2
T-SQL Basics Cursors Parameters procedure-with-parameters/ Good Practices look at this one! practices-checklist.aspx 3
Program code stored in database T-SQL CLR Languages (C#, VB.net, …) Good for: sharing code performance Enforcing security, business rules, audits 4 Procedure A SQL… SQL end A Application Program execute A execute B Database
Stored Procedure T-SQL block Procedural programming features stored in database * invoked by name * accepts arguments Database Trigger T-SQL block Procedural programming features stored in database * invoked by DML (Insert, Update, or Delete) * accepts no arguments 5
6 CREATE PROCEDURE [parameter_information] AS DECLARE /* program variables defined here */ BEGIN /* program logic goes here */ END
7 /* retrieves and displays all customer records */ IF EXISTS (SELECT NAME FROM SYSOBJECTS WHERE NAME = 'show_all_customers' AND TYPE = 'P') DROP PROCEDURE show_all_customers; GO CREATE PROCEDURE show_all_customers AS BEGIN SELECT customer_id, customer_name, postal_code FROM customer_t; END;
8 execute show_all_customers; -- OR Exec show_all_customers;
9 /* retrieves a specific customer record based on a given customer ID. */ /* if the customer lives in the state of FL, then append “-1111” after the zip code & print a message to user */ /* CONVERTs needed since we're concatenating numeric data to text data */ IF EXISTS (SELECT NAME FROM SYSOBJECTS WHERE NAME = 'alter_zip_and_print' AND TYPE = 'P') DROP PROCEDURE alter_zip_and_print; GO CREATE PROCEDURE numeric(5) = null AS varchar(12); BEGIN = = = state FROM customer_t WHERE customer_id = ' fl ' BEGIN + ' ' UPDATE customer_t SET postal_code WHERE customer_id print 'cust#: ' + zipcode changed to: ' END; GO
10 /* statement below included ONLY so I can undo changes after demo. You DO NOT need to do this */ Set implicit_transactions on GO /* show customer 9's record before calling procedure */ Select * from customer_t where customer_id = 9; exec = 9; -or- exec alter_zip_and_print 9 GO /* check to see if procedure updated customer 9's record */ Select * from customer_t where customer_id = 9; GO /* statement below included ONLY so I can undo changes after demo. You DO NOT need to do this */ Rollback; Set implicit_transactions off
Require cursorscursors 1. Declare CURSOR 2. OPEN cursor 3. FETCH data from cursor 4. CLOSE & DEALLOCATE cursor Use control structures to process each record WHILE … [BREAK can be used to force exit from WHILE loop] END; IF ELSE IF BEGIN END; ELSE BEGIN END; 11
12 /* retrieve customer records based on NAME; if customer(s) live in FL, ‘-1111’ is appended to zip */ IF EXISTS (SELECT NAME FROM SYSOBJECTS WHERE NAME = 'getcust' AND TYPE = 'P') DROP PROCEDURE getcust; GO CREATE PROCEDURE varchar(25) AS DECLARE custcursor CURSOR FOR SELECT customer_id, state, postal_code from customer_t WHERE customer_name like ' % ' + ' % ' ; numeric varchar(12); BEGIN -- logic OPEN custcursor; --find customers meeting criteria IF = 0 BEGIN RAISERROR ( ' no customer found ', 10,1) RETURN; END; FETCH FROM @pcode; /* code continued here… */ WHILE = 0 BEGIN -- loop thru each customer record found = ' fl ' BEGIN -- process and display old & new zip PRINT ' id: ' + + ', name: ' PRINT ' old zip: ' SET + ' ' UPDATE customer_t SET postal_code WHERE customer_id PRINT ' new zip: ' PRINT ' ======================= ' ; END; -- processing and displaying of zip FETCH NEXT FROM @pcode; END; -- looping thru records CLOSE custcursor; DEALLOCATE custcursor; END; -- logic
13 Set implicit_transactions on GO Update customer_t set state= ' fl ' where customer_id=2; Select * from customer_t where customer_name like ' %furn% ' ; Exec getcust ' furniture ' GO Select * from customer_t where customer_name like ' %furn% ' ; GO Rollback; Set implicit_transactions off
14 /* for a given order, show the total number of products on the order, and the description of each product on the order */ IF EXISTS (SELECT NAME FROM SYSOBJECTS WHERE NAME = 'showordereditems' AND TYPE = 'P') DROP PROCEDURE showordereditems; GO CREATE PROCEDURE numeric(11) AS DECLARE ordercursor CURSOR FOR select ol.order_id, ol.product_id, p.product_description from order_line_t ol, product_t p where ol.product_id = p.product_id and ol.order_id numeric(11), -- storing order numeric(11), -- storing product varchar(50), -- storing product numeric(4); -- to store the number of products on order BEGIN -- logic -- initialize the counter = count(*) FROM order_line_t ol WHERE ol.order_id -- calculate total # of products on given order PRINT '** order# ' + + ' has ' + + ' products:**'; -- print the total # of products on the order OPEN ordercursor; -- find the products associated with the given order IF BEGIN RAISERROR ('order not found',10,1) RETURN; END; FETCH FROM @pdesc; WHILE = 0 -- loop thru each product on the order BEGIN PRINT 'product#: ' + convert ) + ' product desc: ' -- print each product on the order FETCH NEXT FROM @pdesc; END; CLOSE ordercursor; DEALLOCATE ordercursor; END; -- logic
15 Exec showordereditems 1002 GO
Store code that creates procedure in a script Run and debug script in SSMS Creates & stores procedure in database Invoke procedure Issue "execute" command Include parameter values where required 16
Common Uses: Implementing RI Complex defaults Interrelation constraints/updates Updating views Auditing business activities 2 Kinds in SQL Server: After Instead of (see to-use-instead-of-trigger-guest-post-by-vikas-munjal-koenig- solutions/) to-use-instead-of-trigger-guest-post-by-vikas-munjal-koenig- solutions/ 17
18 CREATE TRIGGER ON AS DECLARE /* program variables defined here */ BEGIN /* program logic goes here */ END
19 /* maintain the orders placed counter in the customer table */ /* add 1 to the counter each time a customer places a new order */ IF EXISTS (SELECT name FROM sysobjects WHERE name = 'add_order_placed' AND type = 'TR') DROP TRIGGER add_order_placed; GO CREATE TRIGGER add_order_placed ON order_t AFTER INSERT AS AS numeric(11,0) BEGIN = customer_ID FROM INSERTED; UPDATE customer_t SET orders_placed = orders_placed+1 WHERE customer_t.customer_ID END; GO
20 /* Maintain the orders placed counter in the customer table */ /* Every time the customer# on an order is changed, the orders_placed column in the customer table is updated */ /* to reflect the # of orders placed by both the original and new customer */ IF EXISTS (SELECT name FROM sysobjects WHERE name = 'change_order_placed' AND type = 'TR') DROP TRIGGER change_order_placed; GO CREATE TRIGGER change_order_placed ON order_t AFTER UPDATE AS AS AS numeric(11,0) BEGIN = customer_ID FROM INSERTED; = customer_ID FROM DELETED; UPDATE customer_t SET orders_placed = orders_placed+1 WHERE customer_t.customer_ID UPDATE customer_t SET orders_placed = orders_placed-1 WHERE customer_t.customer_ID END; GO
Set implicit_transactions on GO /* check status of customer’s orders_placed counter before placing new orders */ select customer_id, orders_placed from customer_t where customer_id=10; /* fire insert trigger by placing orders for customer #10 */ insert into order_t values (9900, '10-OCT-01', 10); insert into order_t values (9901, '10-OCT-01', 10); insert into order_t values (9902, '10-OCT-01', 10); /* issue select statement to verify that trigger updated orders_placed counter */ select customer_id, orders_placed from customer_t where customer_id=10; /* select status of customer’s orders_placed counters before placing new orders */ select customer_id, orders_placed from customer_t where customer_id=10; select customer_id, orders_placed from customer_t where customer_id=1; /* fire update trigger by changing the customer# of one of the orders for customer #10 */ update order_t set customer_id = 1 where order_id = 9901; /* issue select statement to verify that the orders_placed counter is correct */ select customer_id, orders_placed from customer_t where customer_id=10; select customer_id, orders_placed from customer_t where customer_id=1; GO Rollback; Set implicit_transactions off
/* when a new product is added, if the standard price is NOT given, then set the product’s standard price to either: */ /* the highest standard price of a product in the same product line if one exists, OR to $300 */ IF EXISTS (SELECT name FROM sysobjects WHERE name = 'set_standard_price' AND type = 'TR') DROP TRIGGER set_standard_price; GO CREATE TRIGGER set_standard_price ON product_t AFTER INSERT AS as as as as numeric (11,0) = = standard_price FROM INSERTED; IS NULL BEGIN = MAX(standard_price) FROM product_t WHERE product_line_id IS NOT NULL ELSE = 300; UPDATE product_t SET standard_price WHERE product_id END --end IF END; -- end program GO 22
Set implicit_transactions on GO /* issue select statement to view product table before adding new products */ select * from product_t; /* fire insert trigger adding new products to the product_t table*/ insert into product_t values (999,null,null,null,null,20001); insert into product_t values (998, null, null, 123, 3, 33333); Insert into product_t values (997,null,null,null,null,44444); /* issue select statement to verify that trigger updated standard prices for products */ select product_id, product_line_id, standard_price from product_t where product_id>900; GO Rollback; Set implicit_transactions off 23