0

SQL Server 2008 r2 に非常に大きな xml ファイルをロードする必要があります。ファイルは次のようになります。

<?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>

次のテーブル構造があります。

Table CupomVenda
idCupomVenda int auto increment
codFilial int
dtVenda date
numeroDePdv varchar (20)
cupomFiscal int
horaVenda smallint
tipoVenda bit
vendedorVip varchar(80)
cpfCnpjAdquirente char(14)

Table ItemCupomVenda (child from CupomVenda)

idItemCupomVenda int auto Increment
numeroDoItem int
codigoDoProduto int
qtde int
valorUnitario float
ultimoCusto float
idCupomVenda int (relation with primary key from CupomVenda)

.netで使用する必要があるため、どのソリューションも受け入れます。sqlbulkcopy クラスを使用する例をいくつか見つけましたが、xmlReader クラスでは使用できないと思います。これは、この場合に適していると思います。

4

1 に答える 1

0

このクエリですぐに始められるはずです。

重要なのは、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
于 2013-05-07T22:16:07.280 に答える