这个查询应该让你离开地面。
关键是粉碎你的 Xml。但是由于您要插入带有 IDENTITY 的表,因此您必须使用“自然键”来返回“代理 IDENTITY 键”。
因此,只要您的“codFilial”(我称之为“codFilialNaturalKey”)是一个唯一约束,您就可以背负它以将父表的 PK 与子表的 FK 匹配。
我为你做了几列数据(这也意味着我没有为你做每一列)。并添加了额外的“项目”元素,以显示它适用于多个“项目”。
还列出了一个 DataSet DateTime 转换器 (UDF)。您需要将您的值作为 varchar 提取,然后通过 UDF 运行它以转换为 DateTime。
IF OBJECT_ID('tempdb..#DestinationCupomVendaParentTable') IS NOT NULL
begin
drop table #DestinationCupomVendaParentTable
end
IF OBJECT_ID('tempdb..#DestinationItemCupomVendaChildTable') IS NOT NULL
begin
drop table #DestinationItemCupomVendaChildTable
end
CREATE TABLE #DestinationCupomVendaParentTable
(
CupomVendaParentSurrogateIdentityKey int not null identity (1001, 1),
codFilialNaturalKey int,
tipoVenda int
)
CREATE TABLE #DestinationItemCupomVendaChildTable
(
DestinationChildSurrogateIdentityKey int not null identity (3001, 1),
CupomVendaParentSurrogateIdentityKeyFK int,
numeroDoItemNaturalKey int,
codigoDoProduto int
)
-- Declare XML variable
DECLARE @data XML;
-- Element-centered XML
SET @data = N'
<listaCupons xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<cupomVenda>
<codFilial>123456</codFilial>
<dtVenda>2013-01-01T00:00:00</dtVenda>
<numeroDePdv>0.000000000000000</numeroDePdv>
<cupomFiscal>12345</cupomFiscal>
<horaVenda xsi:nil="true"/>
<tipoVenda>1</tipoVenda>
<vendedorVip>FUlano de tal</vendedorVip>
<cpfCnpjAdquirente xsi:nil="true"/>
<item>
<numeroDoItem>9001</numeroDoItem>
<codigoDoProduto>2134</codigoDoProduto>
<qtde>1</qtde>
<valorUnitario>399.000</valorUnitario>
<ultimoCusto>216.150</ultimoCusto>
</item>
<item>
<numeroDoItem>9002</numeroDoItem>
<codigoDoProduto>32134</codigoDoProduto>
<qtde>1</qtde>
<valorUnitario>399.000</valorUnitario>
<ultimoCusto>216.150</ultimoCusto>
</item>
</cupomVenda>
<cupomVenda>
<codFilial>234567</codFilial>
<dtVenda>2013-01-01T00:00:00</dtVenda>
<numeroDePdv>0.000000000000000</numeroDePdv>
<cupomFiscal>23456</cupomFiscal>
<horaVenda xsi:nil="true"/>
<tipoVenda>4</tipoVenda>
<vendedorVip>FUlano de tal</vendedorVip>
<cpfCnpjAdquirente xsi:nil="true"/>
<item>
<numeroDoItem>9011</numeroDoItem>
<codigoDoProduto>3256</codigoDoProduto>
<qtde>4</qtde>
<valorUnitario>333.44</valorUnitario>
<ultimoCusto>333.55</ultimoCusto>
</item>
<item>
<numeroDoItem>9013</numeroDoItem>
<codigoDoProduto>33256</codigoDoProduto>
<qtde>4</qtde>
<valorUnitario>333.44</valorUnitario>
<ultimoCusto>333.55</ultimoCusto>
</item>
</cupomVenda>
</listaCupons>
';
INSERT INTO #DestinationCupomVendaParentTable ( codFilialNaturalKey , tipoVenda )
SELECT T.parentEntity.value('(codFilial)[1]', 'INT') AS codFilial,
T.parentEntity.value('(tipoVenda)[1]', 'INT') AS tipoVenda
FROM @data.nodes('listaCupons/cupomVenda') AS T(parentEntity)
/* add a where not exists check on the natural key */
where not exists (
select null from #DestinationCupomVendaParentTable innerRealTable where innerRealTable.codFilialNaturalKey = T.parentEntity.value('(codFilial)[1]', 'INT') )
;
/* Optional. You could do a UPDATE here based on matching the #DestinationCupomVendaParentTablecodFilialNaturalKey = T.parentEntity.value('(codFilial)[1]', 'INT')
You could Combine INSERT and UPDATE using the MERGE function on 2008 or later.
*/
INSERT INTO #DestinationItemCupomVendaChildTable ( CupomVendaParentSurrogateIdentityKeyFK , numeroDoItemNaturalKey , codigoDoProduto )
SELECT par.CupomVendaParentSurrogateIdentityKey ,
T.childEntity.value('(numeroDoItem)[1]', 'INT') AS numeroDoItem,
T.childEntity.value('(codigoDoProduto)[1]', 'INT') AS codigoDoProduto
FROM @data.nodes('listaCupons/cupomVenda/item') AS T(childEntity)
/* The next join is the "trick". Join on the natural key (codFilial)....**BUT** insert the CupomVendaParentSurrogateIdentityKey into the table */
join #DestinationCupomVendaParentTable par on par.codFilialNaturalKey = T.childEntity.value('(../codFilial)[1]', 'INT')
where not exists (
select null from #DestinationItemCupomVendaChildTable innerRealTable where innerRealTable.CupomVendaParentSurrogateIdentityKeyFK = par.CupomVendaParentSurrogateIdentityKey AND innerRealTable.numeroDoItemNaturalKey = T.childEntity.value('(numeroDoItem)[1]', 'INT'))
;
print '/#DestinationCupomVendaParentTable/'
select * from #DestinationCupomVendaParentTable
print '/#DestinationItemCupomVendaChildTable/'
select * from #DestinationItemCupomVendaChildTable
select codFilialNaturalKey , tipoVenda , numeroDoItemNaturalKey , codigoDoProduto , par.CupomVendaParentSurrogateIdentityKey as ParentPK , child.CupomVendaParentSurrogateIdentityKeyFK as childFK from #DestinationCupomVendaParentTable par join #DestinationItemCupomVendaChildTable child
on par.CupomVendaParentSurrogateIdentityKey = child.CupomVendaParentSurrogateIdentityKeyFK
IF OBJECT_ID('tempdb..#DestinationCupomVendaParentTable') IS NOT NULL
begin
drop table #DestinationCupomVendaParentTable
end
IF OBJECT_ID('tempdb..#DestinationItemCupomVendaChildTable') IS NOT NULL
begin
drop table #DestinationItemCupomVendaChildTable
end
这是一个将 DataSet DateTime 转换为 SqlServer 值的 UDF:
if exists (select * from sysobjects where id = object_id('udfConvertXmlDateToTsqlDate') and xtype = 'FN')
drop function udfConvertXmlDateToTsqlDate
GO
CREATE FUNCTION dbo.udfConvertXmlDateToTsqlDate (@input_xml_date varchar(64))
/*
Original Need : When adding a value to a DataSet/datetime column,
the DataSet stores the date as an xml formatted date
TSQL does not like xml formatted dates
This procedure will transfer a xml formatted date,
into a datetime tsql datatype.
Sample Usage :
select dbo.udfConvertXmlDateToTsqlDate ('2002-06-20T00:00:00.0000000+05:30') as myConvertedDate
will yield:
myConvertedDate
------------------------------------------------------
2002-06-20 00:00:00.000
DateTime.MinValue Test
select dbo.udfConvertXmlDateToTsqlDate ('0001-01-01T00:00:00-05:00') as myConvertedDate
Notes :
The procedure strips out the time part of the datetime.
*/
RETURNS
datetime
AS
BEGIN
--This is a DotNet/Xml/DataSet and DateTime.MinValue work around
if LEFT(@input_xml_date,16) = '0001-01-01T00:00' -- :00-05:00'
BEGIN
return null
END
RETURN
--CONVERT(datetime , LEFT(@input_xml_date , (CHARINDEX('T', @input_xml_date))-1))
CONVERT(datetime , LEFT(CONVERT(nvarchar(4000), @input_xml_date, 126), 10))
-- SEE "Data Type Coercions" (SQL Server 2000 Books Online)
-- this has the code above as the translation mechanism
-- for converted an xml formatted datestamp into a TSQL datetime
END
GO
GRANT REFERENCES ON udfConvertXmlDateToTsqlDate TO public
GO