Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2008 Forums
 Transact-SQL (2008)
 HELP - Compare 2 datasets using dynamic sql.

Author  Topic 

ashley.sql
Constraint Violating Yak Guru

299 Posts

Posted - 2010-09-23 : 15:59:42
I have a following table which needs to have comparison between today and yesterdays data.
If customer deletes or adds items it will show up in 2 rows for both days as ORDER AMENDED. If order is not in yesterday it will show up as
NEW ORDER ADDED. If its in yesterday data and not today it will show as ORDER SHIPPED.

Thats what the script below does. Now I want to be able to do the following using a dynamic SQL. Say a new column called NUMBER_ITEMS and WEIGHT are added to #temp
changes will have to be made to this comparison.

Well is there a way to make this DYNAMIC so that it does not matter columns are added or deleted it should compare by custid. CustID will always be there.


create table #temp
(
custid INT,
num_orders INT,
Tot_Amount MONEY,
Data_Date DATETIME
)

INSERT INTO #temp
SELECT 11, 2, 250, '9/14/2010' UNION ALL
SELECT 22, 3, 120, '9/14/2010' UNION ALL
SELECT 55, 1, 1000, '9/14/2010' UNION ALL
SELECT 44, 1, 500, '9/14/2010' UNION ALL
SELECT 77, 15, 15000, '9/14/2010' UNION ALL
SELECT 11, 3, 350, '9/15/2010' UNION ALL
SELECT 22, 4, 100, '9/15/2010' UNION ALL
SELECT 44, 1, 500, '9/15/2010' UNION ALL
SELECT 77, 10, 10000, '9/15/2010' UNION ALL
SELECT 33, 5, 140, '9/15/2010'

DECLARE @previousdate DATETIME, @currentdate datetime
SET @previousdate = '9/14/2010'
SET @currentdate = '9/15/2010'

Select * into #previousdate from #temp where data_date = @previousdate
Select * into #currentdate from #temp where data_date = @currentdate

SELECT 'NEW ORDER ADDED' AS [STATUS], * ,'NEW' AS STAMP
FROM
#currentdate c
WHERE c.custid NOT IN (Select custid FROM #previousdate)

UNION ALL

SELECT 'ORDERS SHIPPED', * ,'SHIPPED'
FROM
#previousdate p
WHERE p.custid NOT IN (SELECT custid FROM #currentdate)

UNION ALL


SELECT 'ORDER AMENDED', p.*,'PREVIOUS VALUE'
FROM
#previousdate p
INNER JOIN #currentdate C
ON c.custid = p.custid
WHERE c.Data_Date <> p.Data_Date OR
c.Tot_Amount <> c.Tot_Amount OR
c.num_orders <> c.num_orders

UNION ALL

SELECT 'ORDER AMENDED', c.*,'CURRENT VALUE'
FROM
#previousdate p
INNER JOIN #currentdate C
ON c.custid = p.custid
WHERE c.Data_Date <> p.Data_Date OR
c.Tot_Amount <> c.Tot_Amount OR
c.num_orders <> c.num_orders

ORDER BY custid, STATUS, Data_Date

DROP TABLE #temp,#previousdate,#currentdate

-----------------------------------------------------------------------------------------------
Ashley Rhodes

rohitvishwakarma
Posting Yak Master

232 Posts

Posted - 2010-09-24 : 06:26:21
DECLARE @objname nvarchar(776)
SET @objname = 'Sales' -- Your Table Name

DECLARE @objid int
DECLARE @sysobj_type char(2)

SELECT @objid = object_id, @sysobj_type = type FROM sys.all_objects WHERE object_id = object_id(@objname)

SELECT name into #temp_table FROM sys.all_columns where object_id = @objid WHERE name NOT IN(custid ) -- Add columns which are going to be constant.



Use WHILE LOOP on #temp_table to get the column list as string
Go to Top of Page

rohitvishwakarma
Posting Yak Master

232 Posts

Posted - 2010-09-24 : 10:19:55
Here is the complete query:



DECLARE @objname nvarchar(776)
SET @objname = '#temp' -- give the table name here

DECLARE @objid int
DECLARE @sysobj_type char(2)
SELECT @objid = object_id, @sysobj_type = type from sys.all_objects where object_id = object_id(@objname)


DECLARE @previousdate DATETIME, @currentdate datetime
DECLARE @union VARCHAR(15)
DECLARE @sql_final VARCHAR(MAX)
DECLARE @sql_fill_previous_table VARCHAR(1000)
DECLARE @sql_fill_current_table VARCHAR(1000)
DECLARE @sql_NEW_ORDER_ADDED VARCHAR(1000)
DECLARE @sql_ORDERS_SHIPPED VARCHAR(1000)
DECLARE @sql_ORDER_AMENDED_PREVIOUS VARCHAR(1000)
DECLARE @sql_ORDER_AMENDED_CURRENT VARCHAR(1000)

SET @union = 'UNION ALL'
SET @previousdate = '9/14/2010'
SET @currentdate = '9/15/2010'
SET @sql_fill_previous_table = 'SELECT * INTO #previousdate FROM #temp WHERE data_date = ' + '''' + CAST(@previousdate AS VARCHAR(50)) + ''''
SET @sql_fill_current_table = ' SELECT * INTO #currentdate FROM #temp WHERE data_date = ' + '''' + CAST(@currentdate AS VARCHAR(50)) +''''



SET @sql_NEW_ORDER_ADDED = '
SELECT ''NEW ORDER ADDED'' AS [STATUS], * ,''NEW'' AS STAMP
FROM #currentdate c
WHERE c.custid NOT IN (SELECT custid FROM #previousdate)'

SET @sql_ORDERS_SHIPPED = '
SELECT ''ORDERS SHIPPED'', * ,''SHIPPED''
FROM
#previousdate p
WHERE p.custid NOT IN (SELECT custid FROM #currentdate) '

SET @sql_ORDER_AMENDED_PREVIOUS = '
SELECT ''ORDER AMENDED'', p.*,''PREVIOUS VALUE''
FROM
#previousdate p
INNER JOIN #currentdate C
ON c.custid = p.custid
WHERE c.Data_Date <> p.Data_Date OR '




SET @sql_ORDER_AMENDED_CURRENT = '
SELECT ''ORDER AMENDED'', c.*,''CURRENT VALUE''
FROM
#previousdate p
INNER JOIN #currentdate C
ON c.custid = p.custid
WHERE c.Data_Date <> p.Data_Date OR '


CREATE table #temp_table
(
id INT IDENTITY(1,1),
Column_Names VARCHAR(150)
)
INSERT INTO #temp_table
SELECT name FROM sys.all_columns WHERE object_id = @objid AND name NOT IN ('custid','Data_Date')

DECLARE @count INT
DECLARE @count_max INT
DECLARE @or_part VARCHAR(200)

SET @count = 1
SET @count_max = (SELECT MAX(id) FROM #temp_table)
SET @or_part = ''
WHILE (@count < @count_max)
BEGIN
DECLARE @column VARCHAR(150)

SELECT @column = Column_Names FROM #temp_table WHERE id = @count
SET @or_part = ' c.' + @column + ' <> ' + ' p.'+@column +' OR '

SET @sql_ORDER_AMENDED_PREVIOUS += @or_part
SET @sql_ORDER_AMENDED_CURRENT += @or_part
SET @count = @count + 1
END



SET @sql_final = @sql_fill_previous_table + @sql_fill_current_table + @sql_NEW_ORDER_ADDED + @union +
@sql_ORDERS_SHIPPED + @union +
@sql_ORDER_AMENDED_PREVIOUS + @union +
@sql_ORDER_AMENDED_CURRENT


PRINT @sql_final
-- EXEC(@sql_final)



Thanks

Rohit






Go to Top of Page

ashley.sql
Constraint Violating Yak Guru

299 Posts

Posted - 2010-09-24 : 11:44:58
You cannot hard code dynamic SQL it has to be created using information schema.


-----------------------------------------------------------------------------------------------
Ashley Rhodes
Go to Top of Page

rohitvishwakarma
Posting Yak Master

232 Posts

Posted - 2010-09-24 : 12:08:42
quote:
Originally posted by ashley.sql

You cannot hard code dynamic SQL it has to be created using information schema.


-----------------------------------------------------------------------------------------------
Ashley Rhodes



It is being created using Schema using the part:


CREATE table #temp_table
(
id INT IDENTITY(1,1),
Column_Names VARCHAR(150)
)
INSERT INTO #temp_table
SELECT name FROM sys.all_columns WHERE object_id = @objid AND name NOT IN ('custid','Data_Date') -- this will get the columns other than those present in 'IN',you may add other columns which are fixed but not mentioned in the post.

and WHILE loop. This WHILE loop adds the condition inh the WHERE Claues for the last two SELECT Statements using the columns retrieved above. so in future if any columns gets added to your table you don't need to modify the query


I have hardcoded the parts which are going to be remain same i.e for date and customer_id columns & SELECT statements,only the WHERE cluase needs to be dynamic.

Thanks
Rohit
Go to Top of Page

robvolk
Most Valuable Yak

15732 Posts

Posted - 2010-09-24 : 14:24:07
The following uses non-dynamic SQL, gives the same results as your original query, and will work no matter how many columns are added:
;WITH pre(custid,data_date) AS (SELECT custid,data_date FROM #temp WHERE data_date=@previousdate),
cur(custid,data_date) AS (SELECT custid,data_date FROM #temp WHERE data_date=@currentdate),
shipped(custid) AS (SELECT custid FROM pre EXCEPT SELECT custid FROM cur),
added(custid) AS (SELECT custid FROM cur EXCEPT SELECT custid FROM pre)
SELECT 'ORDERS SHIPPED' Status, a.*, 'SHIPPED' STAMP FROM #temp a INNER JOIN shipped b ON a.custid=b.custid
UNION
SELECT 'NEW ORDER ADDED', a.*, 'NEW' FROM #temp a INNER JOIN added b ON a.custid=b.custid
UNION
SELECT 'ORDER AMENDED', a.*, 'PREVIOUS VALUE'
FROM #temp a INNER JOIN pre b ON a.custid=b.custid AND a.data_date=b.data_date
WHERE a.custid NOT IN(SELECT custid FROM shipped)
UNION
SELECT 'ORDER AMENDED', a.*, 'CURRENT VALUE'
FROM #temp a INNER JOIN cur b ON a.custid=b.custid AND a.data_date=b.data_date
WHERE a.custid NOT IN(SELECT custid FROM added)
ORDER BY custid, STATUS, Data_Date
This does not require column comparisons since it assumes anything not shipped nor added is amended. I noticed CustID 44 in your sample data has not changed (except for Data_date), is that considered a dupe? If not then this will satisfy your requirements.
Go to Top of Page
   

- Advertisement -