Monday, December 17, 2012

Execute Keyword in SQL Server 2012


Today, I have provided an article showing you an improved version of the execute keyword in SQL Server 2012. The EXECUTE keyword is used to execute a command string. You cannot change the column name and datatype using the execute keyword in SQL Server 2005/2008. You have to modify the stored procedure respectively. The previous version of SQL Server only has the WITH RECOMPILE option to force a new plan to be re-compiled. The ability to do that in SQL Server 2012dramatically improves this part.  In SQL Server 2012, there is no need to modify a stored procedure. You can change the column name and datatype using the execute keyword. So let's take a look at a practical example. The example is developed in SQL Server 2012 using the SQL Server Management Studio. 
The table looks as in the following:


Create TABLE UserDetail
(
       User_Id int NOT NULL IDENTITY(1,1),     
       FirstName varchar(20),
       LastName varchar(40) NOT NULL,
       Address varchar(255),     
       PRIMARY KEY (User_Id)
)

INSERT INTO UserDetail(FirstName, LastName, Address)
VALUES ('Smith', 'Kumar','Capetown'),
      ('Crown', 'sharma','Sydney'),
      ('Copper', 'verma','Jamaica'),
      ('lee', 'verma','Sydney')
go

Now create a stored procedure for the select statement in SQL Server 2008: 
Create PROCEDURE SelectUserDetail
as
begin
select FirstName,LastName, Address from UserDetail
end  

Now use an Execute command to run the stored procedure: 
-- SQL Server 2008
execute SelectUserDetail
Output
img1.jpg

SQL Server 2012

Now we see how we can change the column name and datatype using an execute keyword in SQL Server 2012. The previous version of SQL Server only has the WITH RECOMPILE option to force a new plan to be re-compiled. To do that in SQL Server 2012 dramatically improves this part. We change the FirstName to Name and the datatype varchar(20) to char(4). Now execute the following code in SQL Server 2012:


WITH result SETS 
 ( 
 (   
      Name CHAR(4), 
      Lastname VARCHAR(20), 
     Address varchar(25)    
 ) 
 ); 

Now Press F5 to run the query and see the result:


img2.jpg

Tuesday, October 30, 2012

Magic of Derived Tables


Using Derived Tables to Simplify the SQL Server Query Process

Problem
Sometimes querying data is not that simple and there may be the need to create temporary tables or views to predefine how the data should look prior to its final output.  Unfortunately there are problems with both of these approaches if you are trying to query data on the fly. 
With the temporary tables approach you need to have multiple steps in your process, first to create the temporary table, then to populate the temporary table, then to select data from the temporary table and lastly cleanup of the temporary table.
With the view approach you need to predefine how this data will look, create the view and then use the view in your query.  Granted if this is something that you would be doing over and over again this might make sense to just create a view, but let's look at a totally different approach.

Solution
With SQL Server you have the ability to create derived tables on the fly and then use these derived tables within your query.  In concept this is similar to creating a temporary table and then using the temporary table in your query, but the approach is much simpler, because it can all be done in one step.
Let's take a look at an example where we query the Sales database to try to find out how many customers fall into various categories based on sales.  The categories that we have predefined are as follows:
Ø  Total Sales between 0 and 5,000 = Micro
Ø  Total Sales between 5,001 and 10,000 = Small
Ø  Total Sales between 10,001 and 15,000 = Medium
Ø  Total Sales between 15,001 and 20,000 = Large
Ø  Total Sales > 20,000 = Very Large
There are several ways that this data can be pulled, but let's look at an approach using a derived table.
The first step is to find out the total sales by each customer, which can be done with the following statement.
SELECT   o.CustomerID
         SUM(UnitPrice QuantityAS TotalSales 
FROM     [Order Details] AS od 
         INNER JOIN Orders AS 
           ON od.OrderID o.OrderID 
GROUP BY o.CustomerID

This is a partial list of the output:
CustomerID
TotalSales
ALFKI 
4596.2000
ANATR
1402.9500
ANTON
7515.3500
...

WOLZA
3531.9500

The next step is to classify the TotalSales value into the OrderGroups that were specified above:
SELECT   o.CustomerID
         SUM(UnitPrice QuantityAS TotalSales
         CASE  
           WHEN SUM(UnitPrice Quantity)  
               BETWEEN AND 5000 THEN 'Micro' 
           WHEN SUM(UnitPrice Quantity)  
               BETWEEN 5001 AND 10000 THEN 'Small' 
           WHEN SUM(UnitPrice Quantity)  
               BETWEEN 10001 AND 15000 THEN 'Medium' 
           WHEN SUM(UnitPrice Quantity)  
               BETWEEN 15001 AND 20000 THEN 'Large' 
           WHEN SUM(UnitPrice Quantity)  
               > 20000 THEN 'Very Large' 
         END AS OrderGroup 
FROM     [Order Details] AS od 
         INNER JOIN Orders AS o  
          ON od.OrderID o.OrderID 
GROUP BY o.CustomerID

This is a partial list of the output:
CustomerID
TotalSales
OrderGroup
ALFKI 
4596.2000
Micro
ANATR
1402.9500
Micro
ANTON
7515.3500
Small
...


WOLZA
3531.9500
Micro
The next step is to figure out how many customers fit into each of these groups and this is where the derived table comes into play.  Take a look at the following query which uses a derived table called OG.  What we are doing here is using the same query from the step above, but calling this derived table OG. Then we are selecting data from this derived table for our final output just like we would with any other query.  All of the columns that are created in the derived table are now available for our final query.
SELECT   OG.OrderGroup
         COUNT(OG.OrderGroupAS OrderGroupCount 
FROM     (SELECT   o.CustomerID
                   SUM(UnitPrice QuantityAS TotalSales
                   CASE  
                     WHEN SUM(UnitPrice Quantity)  
                       BETWEEN AND 5000 THEN 'Micro' 
                     WHEN SUM(UnitPrice Quantity)  
                       BETWEEN 5001 AND 10000 THEN 'Small' 
                     WHEN SUM(UnitPrice Quantity)  
                       BETWEEN 10001 AND 15000 THEN 'Medium' 
                     WHEN SUM(UnitPrice Quantity)  
                       BETWEEN 15001 AND 20000 THEN 'Large' 
                     WHEN SUM(UnitPrice Quantity)  
                       > 20000 THEN 'Very Large' 
                   END AS OrderGroup 
          FROM     [Order Details] AS od 
                   INNER JOIN Orders AS 
                     ON od.OrderID o.OrderID 
          GROUP BY o.CustomerIDAS OG 
GROUP BY OG.OrderGroup

This is the complete list of the output from the above query.

OrderGroup
OrderGroupCount
Large
10
Medium
11
Micro
33
Small
15
Very Large
20

Tuesday, July 17, 2012

Query to Display Foreign Key Relationships and Name of the Constraint for Each Table in Database



SELECT K_Table = FK.TABLE_NAME,
FK_Column = CU.COLUMN_NAME,
PK_Table = PK.TABLE_NAME,
PK_Column = PT.COLUMN_NAME,
Constraint_Name = C.CONSTRAINT_NAME
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK
ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK
ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU
ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME
INNER JOIN (
SELECT I1.TABLE_NAME, I2.COLUMN_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS I1
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE I2
ON I1.CONSTRAINT_NAME = I2.CONSTRAINT_NAME
WHERE I1.CONSTRAINT_TYPE = 'PRIMARY KEY'
) PT ON PT.TABLE_NAME = PK.TABLE_NAME
ORDER BY 1,2,3,4

Wednesday, July 11, 2012

SQL Tuning/SQL Optimization Techniques:


1) The sql query becomes faster if you use the actual columns names in SELECT statement instead of than '*'.
For Example: Write the query as
SELECT id, first_name, last_name, age, subject FROM student_details;
Instead of:
SELECT * FROM student_details;

2) HAVING clause is used to filter the rows after all the rows are selected. It is just like a filter. Do not use HAVING clause for any other purposes.
For Example: Write the query as
SELECT subject, count(subject) 
FROM student_details 
WHERE subject != 'Science' 
AND subject != 'Maths' 
GROUP BY subject;
Instead of:
SELECT subject, count(subject) 
FROM student_details 
GROUP BY subject 
HAVING subject!= 'Vancouver' AND subject!= 'Toronto';

3) Sometimes you may have more than one subqueries in your main query. Try to minimize the number of subquery block in your query.
For Example: Write the query as
SELECT name 
FROM employee 
WHERE (salary, age ) = (SELECT MAX (salary), MAX (age) 
FROM employee_details) 
AND dept = 'Electronics'; 
Instead of:
SELECT name 
FROM employee
WHERE salary = (SELECT MAX(salary) FROM employee_details) 
AND age = (SELECT MAX(age) FROM employee_details) 
AND emp_dept = 'Electronics';

4) Use operator EXISTS, IN and table joins appropriately in your query.
a) Usually IN has the slowest performance.
b) IN is efficient when most of the filter criteria is in the sub-query.
c) EXISTS is efficient when most of the filter criteria is in the main query.
For Example: Write the query as
Select * from product p 
where EXISTS (select * from order_items o 
where o.product_id = p.product_id)
Instead of:
Select * from product p 
where product_id IN 
(select product_id from order_items

5) Use EXISTS instead of DISTINCT when using joins which involves tables having one-to-many relationship.
For Example: Write the query as
SELECT d.dept_id, d.dept 
FROM dept d 
WHERE EXISTS ( SELECT 'X' FROM employee e WHERE e.dept = d.dept);
Instead of:
SELECT DISTINCT d.dept_id, d.dept 
FROM dept d,employee e 
WHERE e.dept = e.dept;

6) Try to use UNION ALL in place of UNION.
For Example: Write the query as
SELECT id, first_name 
FROM student_details_class10 
UNION ALL 
SELECT id, first_name 
FROM sports_team;
Instead of:
SELECT id, first_name, subject 
FROM student_details_class10 
UNION 
SELECT id, first_name 
FROM sports_team;

7) Be careful while using conditions in WHERE clause.
For Example: Write the query as
SELECT id, first_name, age FROM student_details WHERE age > 10;
Instead of:
SELECT id, first_name, age FROM student_details WHERE age != 10;
Write the query as
SELECT id, first_name, age 
FROM student_details 
WHERE first_name LIKE 'Chan%';
Instead of:
SELECT id, first_name, age 
FROM student_details 
WHERE SUBSTR(first_name,1,3) = 'Cha';
Write the query as
SELECT id, first_name, age 
FROM student_details 
WHERE first_name LIKE NVL ( :name, '%');
Instead of:
SELECT id, first_name, age 
FROM student_details 
WHERE first_name = NVL ( :name, first_name);
Write the query as
SELECT product_id, product_name 
FROM product 
WHERE unit_price BETWEEN MAX(unit_price) and MIN(unit_price)
Instead of:
SELECT product_id, product_name 
FROM product 
WHERE unit_price >= MAX(unit_price) 
and unit_price <= MIN(unit_price)
Write the query as
SELECT id, name, salary 
FROM employee 
WHERE dept = 'Electronics' 
AND location = 'Bangalore';
Instead of:
SELECT id, name, salary 
FROM employee 
WHERE dept || location= 'ElectronicsBangalore';
Use non-column expression on one side of the query because it will be processed earlier.
Write the query as
SELECT id, name, salary 
FROM employee 
WHERE salary < 25000;
Instead of:
SELECT id, name, salary 
FROM employee 
WHERE salary + 10000 < 35000;
Write the query as
SELECT id, first_name, age 
FROM student_details 
WHERE age > 10;
Instead of:
SELECT id, first_name, age 
FROM student_details 
WHERE age NOT = 10;
8) Use DECODE to avoid the scanning of same rows or joining the same table repetitively. DECODE can also be made used in place of GROUP BY or ORDER BY clause.
For Example: Write the query as
SELECT id FROM employee 
WHERE name LIKE 'Ramesh%' 
and location = 'Bangalore';
Instead of:
SELECT DECODE(location,'Bangalore',id,NULL) id FROM employee 
WHERE name LIKE 'Ramesh%';
9) To store large binary objects, first place them in the file system and add the file path in the database.
10) To write queries which provide efficient performance follow the general SQL standard rules.
a) Use single case for all SQL verbs
b) Begin all SQL verbs on a new line
c) Separate all words with a single space
d) Right or left aligning verbs within the initial SQL verb