.net 在sql server中加载大xml文件
我必须在SQLServer2008R2中加载一个非常大的xml文件。 该文件看起来像:.net 在sql server中加载大xml文件,.net,sql-server,vb.net,c#-4.0,.net,Sql Server,Vb.net,C# 4.0,我必须在SQLServer2008R2中加载一个非常大的xml文件。 该文件看起来像: <?xml version="1.0" encoding="ISO-8859-1" standalone="no"?> <listaCupons xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <cupomVenda> <codFilial>123456</codFili
<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<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>1</numeroDoItem>
<codigoDoProduto>2134</codigoDoProduto>
<qtde>1</qtde>
<valorUnitario>399.000</valorUnitario>
<ultimoCusto>216.150</ultimoCusto>
</item>
</cupomVenda>
</listaCupons>
我接受任何解决方案,因为我必须在.net中使用它。我找到了一些使用sqlbulkcopy类的示例,但我觉得我不能将其用于xmlReader类,我想这是适合本例的 这个问题应该会让你开窍 关键是分解Xml。但是,由于要插入具有标识的表,因此必须使用“自然键”返回“代理标识键” 因此,只要您的“CodDurthit”(我称之为“codFilialNaturalKey”)是一个唯一的约束,您就可以利用它来匹配父表的PK和子表的FK 我为你做了几列数据(这也意味着我没有为你做每一列)。并添加了额外的“item”元素,以显示它适用于多个“item” 还列出了数据集日期时间转换器(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
你打算用什么样的表结构来存储它?你看过了吗?有一些特定的说明,说明如何将它与.NET.Table cupomVenda、字段idCupomVenda(自动递增)以及xml中的相同字段一起使用,它们的类型顺序分别为:int、int、date、varchar(20)、int、smallint、bit、varchar(80)、char(14)。我还将使用IdItemCupomVenda(自动递增)以及与xml中的字段顺序相同的字段类型存储在Item表中:int,int,int,float,float。加上idCupomVenda(int),使两者之间的关系。谢谢你的帮助@EduardoLion请编辑您的问题以添加此信息;从评论中读取重要的细节非常困难。您是想将xml内容存储在数据库中,还是想将值分解并存储到关系表中的数据库中?非常感谢@granadaCoder!我想这正是我所需要的,我还有一个疑问:如果您有
SET@data=N'
,我该如何使用xml文件的路径?因为它们的大小非常大,我无法打开它们将文本复制到sql server。我从来没有这样做过。我将上述代码放在一个存储过程中,并从DotNet代码调用该存储过程。也就是说,我的“xml”是“内存中的”,而不是磁盘上的文件。所以,您可以将文件推送到sql server中的一个保留表中并从那里读取它,或者文件流读取您的文件并以这种方式向下推。还有一个建议。。一次一行太少,您的整个文件可能太大,您可能想要“分块”…这里有一个演示:“非常大”是相对的。我做过xml…(如果它被写入磁盘上的文件),大约是4MB。你只要试试你的,看看会发生什么。超大意味着1GB甚至更多!那么,如果1000000条记录中有一条不“正确”,那么会发生什么?您是希望999999“运行”,但记录错误的一个,还是希望整个过程失败?如果您想记录偶尔发生的事故,并“继续前进”,那么我将遵循“将其分块”的示例。您将有一种方法来预先验证和/或按摩任何数据,您可以找到正确的“批量大小”(示例中为1000)…并调整该数字。我为我真正的项目所写的逻辑是“一次尝试1000次,如果失败了,那么逐个检查并记录错误的项目”……这样。。
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
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