I have a problem regarding using a stored procedure to build a view for a database. The stored procedure will use a cursor to cycle through child databases that are in a parent database (I have a company database, that holds facility database names in it). The stored procedure will get the facilities and then append the table to those databases.
For example:
OPEN cur_facdb
FETCH NEXT FROM cur_facdb INTO #fac_dw_db_name
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql_command = "CREATE VIEW dbo.BMK_LOCAL_FACILITY_VW
AS
SELECT *
FROM " + #fac_dw_db_name + " .dbo.BMK_FACILITY"
FETCH NEXT FROM cur_facdb INTO #fac_dw_db_name
END
CLOSE cur_facdb
DEALLOCATE cur_facdb
This right now will get me a list of 5 or 6 facilities that look like this:
SELECT * FROM facility_aaaa.dbo.BMK_FACILITY
SELECT * FROM facility_aaab.dbo.BMK_FACILITY
SELECT * FROM facility_aaac.dbo.BMK_FACILITY
Etc....
The problem is that I need to append at the end of each select statement UNION ALL, of course, all but the last record that is produced.
Now having said all of that, is there a way to dump the #FETCH_STATUS into a variable, and then append it to the statement like so:
SET #sql_command = "CREATE VIEW dbo.BMK_LOCAL_FACILITY_VW AS
SELECT * FROM " + #fac_dw_db_name + " .dbo.BMK_FACILITY
*CASE WHEN #Fetch_Variable = 0 THEN 'UNION ALL' ELSE '' END*
"
The reason I can't build a standard view and hard code the facilities is because facilities can be dropped and added monthly, so I am trying to dynamically create this view every month.
Thanks for taking a look.
Put the union all at the beginning, then stuff() the create view in place of the first union all. Like this:
declare #tbl table (name varchar(100))
insert into #tbl values ('facility_aaaa'),('facility_aaab'),('facility_aaac')
declare #sql varchar(max), #t varchar(100), #crlf char(2) = char(13) + char(10)
declare cr cursor local for
select name
from #tbl
order by name
set #sql = ''
open cr
fetch next from cr into #t
while ##fetch_status = 0
begin
set #sql = #sql + 'union all' + #crlf + 'select * from ' + #t + '.dbo.BMK_FACILITY' + #crlf
fetch next from cr into #t
end
close cr
deallocate cr
set #sql = stuff(#sql, 1, 9, 'create view dbo.BMK_LOCAL_FACILITY_VW AS')
print #sql
Which prints this:
create view dbo.BMK_LOCAL_FACILITY_VW AS
select * from facility_aaaa.dbo.BMK_FACILITY
union all
select * from facility_aaab.dbo.BMK_FACILITY
union all
select * from facility_aaac.dbo.BMK_FACILITY
Alternatively, you can accomplish the same thing and use a case statement to add union all to all but the last record. Add a new column to your cursor query rn = row_number() over (order by name desc) and then reverse sort it order by rn desc. You get a descending integer, where rn will equal 1 on the last record. Like this:
declare #tbl table (name varchar(100))
insert into #tbl values ('facility_aaaa'),('facility_aaab'),('facility_aaac')
declare #sql varchar(max), #t varchar(100), #crlf char(2) = char(13) + char(10), #rn int
declare cr cursor local for
select name, rn = row_number() over (order by name desc)
from #tbl
order by rn desc
set #sql = 'create view dbo.BMK_LOCAL_FACILITY_VW AS' + #crlf
open cr
fetch next from cr into #t, #rn
while ##fetch_status = 0
begin
set #sql = #sql + 'select * from ' + #t + '.dbo.BMK_FACILITY' + #crlf + case when #rn > 1 then 'union all' + #crlf else '' end
fetch next from cr into #t, #rn
end
close cr
deallocate cr
print #sql
Related
I need to select all unique values from all columns in a table.
I have tried to implement the query below which I found in the thread How to get unique values from all columns of a table in SQL Server.
declare #Sql_Str varchar(8000)='';
select #Sql_Str=#Sql_Str+' select cast (' +name +' as varchar(500))
from <yourtable> union'
from sys.columns
where [object_id]=object_id('<yourtable>');
set #Sql_Str=SUBSTRING(#Sql_Str,1,len(#Sql_Str)-6);
exec(#Sql_Str)
I cannot get that query to work however. My table has 118 columns. I think that may be more data than the query above may handle.
Try something like this:
DECLARE #Schema VARCHAR(500)='dbo';
DECLARE #tableName VARCHAR(500)='SomeTable';
DECLARE #cmd NVARCHAR(MAX)=
(
SELECT STUFF(
(
SELECT ' UNION ALL SELECT ''' + c.TABLE_SCHEMA + ''' AS TableSchema '
+ ',''' + c.TABLE_NAME + ''' AS TableName '
+ ',''' + c.COLUMN_NAME + ''' AS ColumnName '
+ ',''' + c.DATA_TYPE + ''' AS ColumnType '
+ ',CAST(' + QUOTENAME(c.COLUMN_NAME)+' AS NVARCHAR(MAX)) AS Value '
+ ' FROM ' + QUOTENAME(c.TABLE_SCHEMA) + '.' + QUOTENAME(c.TABLE_NAME)
+ ' WHERE ' + QUOTENAME(c.COLUMN_NAME) + ' IS NOT NULL '
+ ' GROUP BY ' + QUOTENAME(c.COLUMN_NAME) + ' '
FROM INFORMATION_SCHEMA.COLUMNS AS c
WHERE TABLE_NAME=#TableName
AND TABLE_SCHEMA=#Schema
--exclude not supported types
--AND c.DATA_TYPE NOT IN('xml') --add more types
FOR XML PATH(''),TYPE
).value('.','nvarchar(max)'),1,10,'')
);
--PRINT #cmd
EXEC(#cmd);
This statement will first create a long list of UNION ALL SELECT with GROUP BY (better than DISTINCT) as dynamically created SQL and executes this with EXEC().
You can decomment PRINT to examine the statement created.
This should work in tSQL:
declare #table_name varchar(55)
set #table_name= 'IV00101' ---- <-- Change this to your table name
create table #colcount (
colname varchar(55),
dct int,
tot int
)
create table #colContent (
colname varchar(55),
col_val nvarchar(max),
col_val_count int
)
create table #sqlexecs( s varchar(max))
declare #col_name varchar(max), #sql nvarchar(max), #sql2 nvarchar(max)
declare c cursor for
select name from sys.columns where [object_id]=object_id(#table_name)
open c
fetch next from c into #col_name
while ##FETCH_STATUS = 0
begin
set #sql = 'select cn.name, count(distinct '+#col_name+') as dct_numrow, count('+#col_name+') as tot_numrow from '+#table_name+' join (select name from sys.columns where name = '''+#col_name+''' and [object_id]=object_id('''+#table_name+''')) cn on cn.name = '''+#col_name+''' group by cn.name'
set #sql2 = 'select ' +#col_name+', count('+#col_name+') as colvalcnt from '+#table_name+' group by '+#col_name
--insert into #sqlexecs values (#sql) --uncomment to view sql selects produced by #sql
--insert into #sqlexecs values (#sql2) --uncomment to view sql selects produced by #sql2
insert into #colcount execute sp_executesql #sql
------
declare #d int, #t int
set #d = (select dct from #colcount where colname = #col_name)
set #t = (select tot from #colcount where colname = #col_name)
if (#d <> #t)
begin
insert into #colContent (colname) values (#col_name)
insert into #colContent (col_val,col_val_count) execute sp_executesql #sql2
end
else
begin
insert into #colContent values (#col_name,1,1)
end
fetch next from c into #col_name
end
close c
deallocate c
--select * from #sqlexecs -- uncomment to view sql code produced by #sql and #sql2
select * from #colcount --order by dct desc
select * from #colContent
drop table #colcount
drop table #colContent
drop table #sqlexecs
The first table shows column name, distinct value count, and total value count.
The second table shows column name, distinct values, and the number of times a distinct value appears. If values in column are all distinct (column is a candidate key), colname | 1 | 1 is shown. This should work if copy/pasted, please let me know it doesn't. Dev for use in Dynamics GP.
I have a master table which contains the table names and columns corresponding to that table.
I want to write a procedure which iterates through all the records of tables and gets all the data and returns it as a single result set.
You need to use Dynamic Query
DECLARE #sql VARCHAR(max)=''
SET #sql = (SELECT #sql + 'select ' + column_name + ' from '
+ table_name + ' union all '
FROM master_table
FOR xml path(''))
SELECT #sql = LEFT(#sql, Len(#sql) - 9)
EXEC (#sql)
Note : The datatype of all the columns should be same. If it is not the case then you may have to do explicit conversion to varchar
SET #sql = (SELECT #sql + 'select cast(' + column_name + ' as varchar(4000)) from '
+ table_name
+ ' union all '
FROM Master_table
FOR xml path(''))
Assuming that all tables listed in your Master table is having same columns with same order and data types. Then it will be as follows:
create table ##a
(
Value int
)
create table ##b
(
Value int
)
create table ##c
(
Value int
)
declare #all table
(
Value int
)
declare #master table
(
TableName varchar(10)
)
declare #TableName varchar(10)
insert ##a values (1), (2), (3)
insert ##b values (4), (5), (6)
insert ##c values (7), (8), (9)
insert #master values ('##a'), ('##b'),('##c')
declare looper cursor local static forward_only read_only for
select TableName from #master
open looper
fetch next from looper into #TableName
while ##fetch_status = 0
begin
insert #all exec('select Value from ' + #TableName)
fetch next from looper into #TableName
end
close looper
deallocate looper
select * from #all
drop table ##a
drop table ##b
drop table ##c
If the tables are of different structures, please visit Stored procedures and multiple result sets in T-SQL. It will squeeze the content of each table into a single XML cell. The article also explains how to read them back.
I assume that you are using many tables with different columns in your master table. You should loop your master table. Try like this,
DECLARE #sql NVARCHAR(max) = ''
DECLARE #start INT = 1
,#end INT = 0
,#tablename VARCHAR(100) = ''
DECLARE #TableList TABLE (
id INT identity(1, 1)
,tablename VARCHAR(128)
)
INSERT INTO #TableList (tablename)
SELECT DISTINCT table_name
FROM YourMasterTableName
WHERE TABLE_NAME = 'productss'
SET #end = ##ROWCOUNT
WHILE (#start <= #end)
BEGIN
SET #tablename = (
SELECT tablename
FROM #TableList
WHERE id = #start
)
SET #sql = (
SELECT ',[' + column_name + ']'
FROM YourMasterTableName M
WHERE TABLE_NAME = #tablename
FOR XML path('')
)
SET #sql = 'SELECT ' + stuff(#sql, 1, 1, '') + ' FROM ' + #tablename
EXEC sp_executesql #sql
SET #start = #start + 1
END
I have a table called raw_data that contains a column with a large string of data fields formatted in fixed length sub-strings. I also have a table table_1 that specifies the column name and the data range in the string for each value. I need to create a SQL INSERT statement to move data from raw_data into a table called table_2 with all the columns. table_1 has about 600 rows, so I am wondering if I can loop through each record to create the SQL statement that inserts the data into table_2.
Table_1
Name Start Length
AAA 1 2
BBB 3 3
CCC 6 1
I haven't learned how to use cursors; the below query could be incorrect. There will be 3 tables involved in this task. table_1 to look up the name, start, length values. table_2 will be the table I need to insert the data into. The third table raw_data has the column with the sub-strings of each needed value.
DECLARE #SQL VARCHAR(200)
DECLARE #NAME VARCHAR(200)
DECLARE #START VARCHAR(200)
DECLARE #LENGTH VARCHAR(200)
SET #NAME = ''
DECLARE Col_Cursor CURSOR FOR
SELECT Name, Start, Length FROM ODS_SIEMENS_LAYOUT WHERE RecordType = '1'
OPEN Col_Cursor
FETCH NEXT FROM Col_Cursor INTO #NAME, #START, #LENGTH
WHILE ##FETCH_STATUS = 0
BEGIN
SET #SQL = #NAME + '=' + 'SUBSTRING(RAW_DATA,' + #START + ',' + #LENGTH + ')'
FETCH NEXT FROM Col_Cursor INTO #NAME, #START, #LENGTH
END
CLOSE Col_Cursor
DEALLOCATE Col_Cursor
I need to generate something like the below query:
INSERT INTO TABLE_2
'AAA' = SUBSTRING(RAW_DATA,1,2)
'BBB' = SUBSTRING(RAW_DATA,3,3)
'CCC' = SUBSTRING(RAW_DATA,5,2)
........
Can I loop through each column to form the SQL Statement instead of manually coding 600 columns?
At the risk of sounding like Clippy... it looks like you're trying to import a flat file. Is your RAW_DATA coming from a flat file somewhere? If so you might look into using bulk insert:
Use a Format File to Bulk Import Data
If you are just asking how can you build your sql statement using the data from your column definition table... then the code you have is very close. You want something like this:
DECLARE #COLUMNS varchar(max)
DECLARE #SUBCOLUMNS varchar(max)
DECLARE #NAME VARCHAR(200)
DECLARE #START VARCHAR(200)
DECLARE #LENGTH VARCHAR(200)
SET #NAME = ''
DECLARE Col_Cursor CURSOR FOR
SELECT Name, Start, Length FROM ODS_SIEMENS_LAYOUT WHERE RecordType = '1'
OPEN Col_Cursor
FETCH NEXT FROM Col_Cursor INTO #NAME, #START, #LENGTH
set #SUBCOLUMNS = ''
set #COLUMNS = ''
WHILE ##FETCH_STATUS = 0
BEGIN
SET #COLUMNS = #COLUMNS + #NAME + ','
SET #SUBCOLUMNS = #SUBCOLUMNS + 'SUBSTRING(RAW_DATA,' + #START + ',' + #LENGTH + '),'
FETCH NEXT FROM Col_Cursor INTO #NAME, #START, #LENGTH
END
CLOSE Col_Cursor
DEALLOCATE Col_Cursor
set #COLUMNS = LEFT(#COLUMNS, len(#COLUMNS)-1) --get rid of last comma
set #SUBCOLUMNS = LEFT(#SUBCOLUMNS, len(#SUBCOLUMNS)-1) --get rid of last comma
print 'INSERT INTO TABLE_2 ' + '(' + #COLUMNS + ') SELECT ' + #SUBCOLUMNS + ' FROM RawDataTable'
You can take the text that prints and insert that SQL statement into your procedure that does the actual inserts.
Ahh I think I am beginning to unravel what you are trying to do. There is no need for a cursor or dynamic sql here at all. You just need to use a select statement as the values for your insert. Something like this maybe??
INSERT INTO TABLE_2(AAA, BBB, CCC)
SELECT SUBSTRING(RAW_DATA,1,2)
, SUBSTRING(RAW_DATA,3,3)
, SUBSTRING(RAW_DATA,5,2)
FROM ODS_SIEMENS_LAYOUT
WHERE RecordType = '1'
In DB I have #temp tables with data and I need to generate insert Scripts (for all data).
How it can be done ? I right clicked on tempDB and selected > Tasks > Generate Scripts but I can't select #temp tables to generate script (they are not avaialble to select).
how I can geneate Insert script from #temp tables I m using SQL Server 2008 R2.
You can insert your query results into sql table (temporary table , it will be created automatically ):
SELECT * INTO myTempTable FROM (query results)
e.g : SELECT * INTO myTempTable FROM user where condition
A table named myTempTable will be created inside schema dbo
Then click on database click :
Tasks > Generate Scripts
and you choose the table myTempTable
Another best way to do it just bit faster but longer.
Use SqlPubWiz
Just go:
C:\Program Files (x86)\Microsoft SQL Server\90\Tools\Publishing\1.4
and run and fill required information regarding log in into database and choose your database and get your whole database script and find the table's insert script that you wanted in your saved script file.
You can use the following query batch for generating scripts for temp tables and you can select the rows based on the conditions. I have got this from here. In the original source, the Author created Stored Procedure for generating scripts. I have formatted and modified for declaring TableName with Condition. You need to run this query batch in tempdb with your #temp table name. Thanks to Neeraj Prasad Sharma.
DECLARE #QUERY VARCHAR(MAX) = 'Dbo.#Temp where 1 = 1'
SET NOCOUNT ON
DECLARE #WithStrINdex AS INT
DECLARE #WhereStrINdex AS INT
DECLARE #INDExtouse AS INT
DECLARE #SchemaAndTAble VARCHAR(270)
DECLARE #Schema_name VARCHAR(30)
DECLARE #Table_name VARCHAR(240)
DECLARE #Condition VARCHAR(MAX)
SELECT #WithStrINdex = 0
SELECT #WithStrINdex = CHARINDEX('WITH', #Query), #WhereStrINdex = CHARINDEX('WHERE', #Query)
IF(#WithStrINdex != 0)
SELECT #INDExtouse = #WithStrINdex
ELSE
SELECT #INDExtouse = #WhereStrINdex
SELECT #SchemaAndTAble = LEFT(#Query, #INDExtouse - 1)
SELECT #SchemaAndTAble = LTRIM(RTRIM(#SchemaAndTAble))
SELECT #Schema_name = LEFT(#SchemaAndTAble, CHARINDEX('.', #SchemaAndTAble ) - 1)
,#Table_name = SUBSTRING(#SchemaAndTAble, CHARINDEX('.', #SchemaAndTAble ) + 1, LEN(#SchemaAndTAble))
,#CONDITION = SUBSTRING(#Query, #WhereStrINdex + 6, LEN(#Query))--27+6
DECLARE #COLUMNS TABLE([Row_number] SMALLINT, Column_Name VARCHAR(MAX))
DECLARE #CONDITIONS AS VARCHAR(MAX)
DECLARE #Total_Rows AS SMALLINT
DECLARE #Counter AS SMALLINT
DECLARE #ComaCol AS VARCHAR(MAX)
SELECT #ComaCol = '', #Counter = 1, #CONDITIONS = ''
print #Schema_name
print #Table_name
INSERT INTO #COLUMNS
SELECT ROW_NUMBER() OVER(ORDER BY ORDINAL_POSITION) [Count] ,COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = #Schema_name
AND TABLE_NAME = #Table_name
AND COLUMN_NAME NOT IN ('SYNCDESTINATION','PENDINGSYNCDESTINATION' ,'SKUID','SALECREDITEDTO')
SELECT #Total_Rows = COUNT(*) FROM #COLUMNS
SELECT #Table_name = '['+#Table_name+']'
SELECT #Schema_name = '['+#Schema_name+']'
WHILE (#Counter< = #Total_Rows )
BEGIN
SELECT #ComaCol = #ComaCol + ' ['+Column_Name+'],' FROM #COLUMNS
Where [Row_number] = #Counter
SELECT #CONDITIONS = #CONDITIONS+ ' + CASE WHEN ['+Column_Name+'] IS NULL THEN ''NULL'' ELSE '''''''' +
REPLACE( CONVERT(VARCHAR(MAX),['+Column_Name+']) ,'''''''','''')
+'''''''' END +'+''','''
FROM #COLUMNS WHERE [Row_number] = #Counter
SET #Counter = #Counter + 1
END
SELECT #CONDITIONS = RIGHT(#CONDITIONS, LEN(#CONDITIONS) -2)
SELECT #CONDITIONS = LEFT(#CONDITIONS, LEN(#CONDITIONS) -4)
SELECT #ComaCol = SUBSTRING (#ComaCol, 0, LEN(#ComaCol))
SELECT #CONDITIONS = '''INSERT INTO ' + #Schema_name + '.' + #Table_name + '(' + #ComaCol + ')' +' VALUES( '+'''' + '+' + #CONDITIONS
SELECT #CONDITIONS = #CONDITIONS + '+' + ''')'''
SELECT #CONDITIONS = 'SELECT' + #CONDITIONS + 'FROM' + #Schema_name + '.' + #Table_name + ' WITH(NOLOCK) ' + ' WHERE ' + #Condition
PRINT(#CONDITIONS)
EXEC(#CONDITIONS)
You have to right click on database and click on
Tasks -> Generate Scripts
now you are having a popup screen go to next click
Select specific database objects
now select your table from Tables option and click next now you have Advanced button there click on it.
You will have another small popup screen available choose
Types of data to script and select
Data only
click OK and don't forget to see the path as file name where your script save carefully.
Now click Next and again Next your script is ready with the data.
I have following XML:
<NewDataSet>
<Data>
<Id>560f05b2-b215-4fea-9ac6-7f012fbca331</Id>
<Number>384D25334E04593B6DE9955E72F413F8A0A828FF</Number>
<CurrentDate>2012-11-21T09:09:26+00:00</CurrentDate>
</Data>
<Data>
<Id>9cff574b-59ea-4cbd-a2db-9ed02b6cc602</Id>
<Number>384D25334E04593B6DE9955E72F413F8A0A828FF</Number>
<Location>Town</Location>
<CurrentDate>2012-11-21T09:09:53+00:00</CurrentDate>
</Data>
</NewDataSet>
I'm trying to write a query that will inster new record or update existing one based on given xml. The problem is I cannot use predefined names of columns, becuase table straucture sometimes is changing. So the idea is to generate dynamic query and apply it. So far I've got following thing:
SET NOCOUNT OFF;
DECLARE #TableName nvarchar(50)
DECLARE #TableData xml
DECLARE #Query nvarchar(max)
DECLARE #Id uniqueidentifier
DECLARE #CurrentDate datetime
-- declare cursor
DECLARE cursor_inserting CURSOR LOCAL FAST_FORWARD FOR
SELECT
r.value('fn:local-name(.)', 'nvarchar(50)'),
r.query('.')
FROM #Data.nodes('//NewDataSet/*') AS records(r)
ORDER BY r.value('fn:local-name(.)', 'nvarchar(50)')
-- open cursor
OPEN cursor_inserting
FETCH NEXT FROM cursor_inserting INTO #TableName, #TableData
WHILE ##FETCH_STATUS = 0
BEGIN
-- Get id
SELECT #Id = o.value('Id[1]', 'uniqueidentifier') FROM #TableData.nodes('*') as n(o)
SELECT #CurrentDate = o.value('CurrentDate[1]', 'datetime') FROM #TableData.nodes('*') as n(o)
SET #Query = NULL
-- temporary update query
SET #UpdateTemp = NULL
SELECT #UpdateTemp = COALESCE(#UpdateTemp + ', ', '') + o.value('fn:local-name(.)', 'nvarchar(50)') + ' = ''' + CAST(o.query('text()') as nvarchar(4000)) + '''' FROM #TableData.nodes('/*/*') as n(o)
SET #UpdateTemp = 'UPDATE ' + #TableName + ' SET ' + #UpdateTemp + ' WHERE Id = ''' + CAST(#Id as nvarchar(40)) + ''''
-- temporary insert query
SET #Insert1Temp = NULL
SELECT #Insert1Temp = COALESCE(#Insert1Temp + ', ', '') + o.value('fn:local-name(.)', 'nvarchar(50)') FROM #TableData.nodes('/*/*') as n(o)
SET #Insert2Temp = NULL
SELECT #Insert2Temp = COALESCE(#Insert2Temp + ', ', '') + '''' + CAST(o.query('text()') as nvarchar(4000)) + '''' FROM #TableData.nodes('/*/*') as n(o)
SET #InsertTemp = 'INSERT INTO ' + #TableName + ' ( ' + #Insert1Temp + ' ) VALUES ( ' + #Insert2Temp + ' )'
IF #TableName = 'Data'
BEGIN
IF EXISTS (SELECT * FROM Data WHERE Id = #Id)
BEGIN
IF EXISTS (SELECT * FROM tblAudit WHERE Id = #Id AND CurrentDate < #CurrentDate)
BEGIN
SET #Query = #UpdateTemp
END
END
ELSE
BEGIN
SET #Query = #InsertTemp
END
END
IF #Query IS NOT NULL
BEGIN
SELECT #Query
EXEC (#Query)
END
END
FETCH NEXT FROM cursor_inserting INTO #TableName, #TableData
END
CLOSE cursor_inserting
DEALLOCATE cursor_inserting
If there is any better way to achive this inside SQL I would like to know, I know that I can do this outside SQL in my application code, but I would like to have it in one place in stored procedure to provide xml and have required action taken.
UPDATE 1
I would like to clarify that my main problem is query proper generation based on XML. The different way of handling instert/update is nice to see, but as addition
UPDATE 2
There can be more than 1 table in xml. E.g. not only Data but also Data2
UPDATE 3
I've update what I have now - and it is now generating proper Insert/Update however I now have issues with conversion. E.g. Date string is in xml format and sql doesn't want to convert it automaticaly. So my next step is get proper column type from database and instead of generate query instert directly from xml.I hope this will work.
Yes.
You can use MERGE and SQL XQuery to do it in one statement.
Something like...
merge Data as target
using
(
select
x.q.value('Id[1]','uniqueidentifier') as ID,
x.q.value('Number[1]','varchar(50)') as Number,
x.q.value('Location[1]','varchar(50)') as Town,
x.q.value('CurrentDate[1]','datetime') as CurrentDate
from
#TableData.nodes('/NewDataSet/Data')x(q)
) as Source (ID,Number,Town,CurrentDate)
on target.id=source.id
when matched and target.CurrentDate < source.CurrentDate then
update set
Number = source.number,
town = source.town,
currentdate = source.currentdate
when not matched then
insert (ID,number,town,currentdate)
values (source.id,source.number,source.town,source.currentdate);