Wednesday, August 27, 2008

Working with xml output in SQL Server.

Today I came across a nice article on MSSQLtips.com .
It says "Running a Dynamic Query against SQL Server without using Dynamic SQL".
This introduced me to the idea, that I could create xml output from a select query that I fire on a SQl Server (2000 & above).

Off-course this was not enough and I googled for more and found out many other links. A few noteworthy are as follows :

1) Nice Blog for XML Explicit : This blog shows the basic usage of 'For XML Explicit' syntax and example used for retrieving XML output from a simple Select query.

2) Retrieving XML from SQL Server Using SELECT ... FOR XML : Very good article. Explains Raw Mode, Auto Mode and Explicit Mode. Simple to understand.

3) How to export data from SQL Server 2000 to XML : Explains how to write the output to an Xml File. The idea is to create view based on the query used and then use "BCP QUERYOUT" to write the ourpur to an xml file with the help of "FOR XML" command.

4) XML in SQL Server 2000 and SQLXML :
Good explaination of the "For XML" Syntax. Along with some code in .NET with ADO objects.
I will say its a must read.

After going through the database I created some output with in my database. The Best query I found was on link number 4. I used bcp Queryout to create xml file. But I also took two approaches 1) to use FOR XML EXPLICIT and 2) to use FOR XML Auto, Bith of these create different outputs, though I am sure we can modify the query for EXPLICIT for a desired ouput.

Assume that there is a table which stores if the days of the current month are holidays in a particular country.
Now assume that there are three columns which are used to store this information. Namely "CountryId", "DAYID" and "Holiday"
Then using

1)
Create view XMlOutput as
(
Select 1 as [TAG], NULL as [Parent] , NULL as [Countries!1!],
NULL as [Country!2!CountryID] ,
NULL as [DAY!3!DAYID],
NULL as [DAY!3!Holiday!Element],

Union

(SELECT 2 as [TAG] , 1 as [Parent], NULL, CountryID , NULL , NULL, NULL
from CountryHolidays )

UNION
(SELECT 3 as [TAG] , 2 as [Parent], NULL, NULL , DAYID , Holiday from CountryHolidays )
)

now use this view to bcp Queryout the result to a XML file.

bcp "select * from TABLENAME..XMlOutput FOR XML EXPLICIT" queryout "D:\Akshay\data.xml" -w -r "" -T

Please find the output of the file here.

2) Using the For XML Auto command

bcp "Select 1 as TAG ,* from Country..CountryHolidays FOR XML AUTO, XMLDATA, BINARY BASE64, ELEMENTS" queryout "D:\Akshay\data.xml" -w -r "" -T
This will consider each row as a tag and each column will be a tag with the row as a parent.

Friday, June 27, 2008

Retrieve the days of a month which are not populated in a column

The following query retrieves the days of a particular month which are not used in a particular column.
Please change the column name and tablename alongwith the month and year to give expected results. Also this can be used to create a function or procedure by replacing the variables by parameters.


Create table #t1
(
checkdate datetime
)

DECLARE @checkdate AS DATETIME;
DECLARE @month AS varchar(2);
DECLARE @year AS varchar(4);
DECLARE @tablename AS varchar(100);
DECLARE @columnname AS varchar(100);

set @month = '06'
set @year = '2008'
set @tablename = 'tablename'
set @columnname = 'columndate'
select @checkdate = Convert(DATETIME,(select @year + '-' + @month + '-01'))


--select @checkdate

WHILE MONTH(@checkdate) = @month
BEGIN
insert into #t1
select @checkdate ;
select @checkdate = dateadd(dd,1,@checkdate) ;
END

execute ('select DAY(checkdate) , checkdate from #t1' +
' LEFT JOIN ('+
'select distinct DAY('+ @columnname+') as [d1] from '+ @tablename +'
where YEAR('+ @columnname+') = '+ @year +' and MONTH('+ @columnname+') = '+ @month +
') split '+
'ON ( day(#t1.checkdate) = split.[d1] ) '+
'where split.[d1] is NULL '+
'order by checkdate' )


/*
select DAY(checkdate), checkdate from #t1
where DAY(checkdate) not in (
select distinct DAY(columnname) from tblsplitmthis
where YEAR(columnname) = @year and MONTH(columnname) = @month
) from #t1
*/

drop table #t1

Wednesday, June 18, 2008

Finding and listing columns with default values in a database

This one is a handy script I found on a blog.


SELECT SO.NAME AS "Table Name", SC.NAME AS "Column Name", SM.TEXT AS "Default Value"
FROM dbo.sysobjects SO INNER JOIN dbo.syscolumns SC ON SO.id = SC.id
INNER JOIN dbo.syscomments SM ON SC.cdefault = SM.id
WHERE SO.xtype = 'U'
ORDER BY SO.[name], SC.colid



Read more at mssqltips.com

The power of Cross (Cartesian) Joins

This is a very good example of where the Cartesian (Cross) Join may be very helpful. Though proper understanding and enough experimentation should be done to try it out.
Jeff @ SQLTeam.com

It explains an example where a Join may be required to return some value ['0'] in this case when there are no matching records found. for e.g. return 0 for sales of all combination of products and stores which dont have a value i.e. null.


SELECT S.Store, P.Product, ISNULL(C.TotalSales,0) as TotalSales
FROM Stores S
CROSS JOIN Products P
LEFT OUTER JOIN
(SELECT Store, Product, SUM(Sales) as TotalSales
FROM Sales
GROUP BY Store, Product) C
ON
S.Store = C.Store AND
P.Product = C.Product

Also Refer:
Join Clause in SQl

Image representation of Joins in SQL










Found a similar blog with name
Visual Explanation of SQL JOINS

Tuesday, June 17, 2008

Deleting duplicate records.

Its a nice post on deleting duplicate records. She has mentioned 3 different methods with their advantages and disadvantages.

SQLteam.com

Object Oriented approach for SQL

Implementing Table inheritance in SQL Server.
SQlTeam.com

Implementing Table Interfaces
SQLTeam.com

The Golden Rule of Data Manipulation

This is a very good post about data design.
SQLTeam Golden Rule Of Data manipulation

It is suggested that Concatenating is easier than parsing scripts. Thus wherever possible one must segregate the data. e.g Full name phone numbers etc.

Tuesday, June 10, 2008

Basics and some tips on writing joins in T-SQL

Link to article on Joins in T-SQl : Basics

sqlteam.com

Points
1) when using aggregates with joins take care to include the column, as aggregating on '*' i.e. the row, might return false result specially for columns with null values.
2) when executing multiple joins using the left outer joins may be useful as using inner join might not return some rows with NULL values in the intermediate table.