简体   繁体   English

将XML文档插入SQL Server 2008数据库

[英]Inserting XML documents into SQL Server 2008 database

I need help inserting xml files into SQL Server 2008. 我需要将xml文件插入SQL Server 2008的帮助。

I have the following SQL statement: 我有以下SQL语句:

insert into dbo.articles(id, title, contents)
  SELECT  X.article.query('id').value('.', 'INT'),
        X.article.query('article').value('.', 'VARCHAR(50)'),
        X.article.query('/doc/text()').value('.', 'VARCHAR(MAX)')
   FROM (
     SELECT CAST(x AS XML)
     FROM OPENROWSET(
           BULK 'E:\test\test_files\1000006.xml',
           SINGLE_BLOB) AS T(x)
        ) AS T(x)
CROSS APPLY x.nodes('doc') AS X(article);

which basically shreds an XML doc into a columns. 基本上将XML文档切成一列。 However, I want to be able to insert all the files in a folder, and not manually specify the file, as in this case E:\\test\\test_files\\1000006.xml 但是,我希望能够将所有文件插入文件夹中,而不是手动指定文件,在这种情况下为E:\\ test \\ test_files \\ 1000006.xml

Ok, first crack at answering a question in stackoverflow... 好的,首先要回答stackoverflow中的一个问题...

You have two issues:- firstly getting the filenames from the folder into a SQL table or table variable, and then reading the XML from each. 您有两个问题:-首先将文件夹中的文件名放入SQL表或表变量中,然后从每个文件中读取XML。

The first is easy, if you don't mind using xp_cmdshell 第一个很简单,如果您不介意使用xp_cmdshell

DECLARE @Folder         VARCHAR(255)    = 'C:\temp\*.xml'
DECLARE @Command        VARCHAR(255)
DECLARE @FilesInAFolder TABLE  (XMLFileName VARCHAR(500))

--
SET @Command = 'DIR ' + @Folder + ' /TC /b'
--
INSERT INTO @FilesInAFolder
EXEC MASTER..xp_cmdshell @Command
--
SELECT * FROM @FilesInAFolder
WHERE XMLFileName IS NOT NULL

The second part, converting the XML files to SQL rows is a little trickier because BULK INSERT won't take a parameter and you can't BULK INSERT into an XML table type. 第二部分,将XML文件转换为SQL行有点棘手,因为BULK INSERT不会接受参数,并且您不能将BULK INSERT转换为XML表类型。 Here's code that works for ONE file... 这是适用于一个文件的代码...

DECLARE @x              xml
DECLARE @Results        TABLE  (result xml)
DECLARE @xmlFileName    NVARCHAR(300) = 'C:\temp\YourXMLFile.xml'
DECLARE @TempTable      TABLE 
    (
    ID                  INT,        
    Article             NVARCHAR(50),
    doctext             NVARCHAR(MAX)
    )   

/* ---- HAVE TO USE DYNAMIC sql BECAUSE BULK INSERT WON'T TAKE A PARAMETER---------*/
DECLARE @sql NVARCHAR(4000) =
 'SELECT * FROM OPENROWSET ( BULK ''' + @xmlFileName + ''', SINGLE_BLOB )AS xmlData'

/* ---- have to use a normal table variable because we can't directly bulk insert
        into an XML type table variable  ------------------------------------------*/
INSERT INTO @results EXEC(@SQL)

SELECT @x = result FROM @Results

/* ---- this is MUCH faster than using a cross-apply ------------------------------*/
INSERT INTO @TempTable(ID,Article,doctext)                                              
SELECT 
                x.value('ID[1]',        'INT'           ),      
                x.value('Article[1]',   'NVARCHAR(50)'  ),                      
                x.value('doctext[1]',   'NVARCHAR(MAX)' )   
FROM @x.nodes(N'/doc')      t(x) 

SELECT * FROM @TempTable

Now the hard bit is putting these two together. 现在,很难将这两者放在一起。 I tried several ways to get this code into a function but you can't use dynamic SQL or EXEC in a function and you can't call an SP from a function and you can't put the code into two separate SPs because you can't have cascading EXEC statements ie you try and EXEC an SP with the above code in it that also has an EXEC in it, so... you have to either use a cursor to put the two code blocks above together ie cursor through the @FilesInAFolder passing each XMLFileName value into the second code block as variable @XMLFileName or you use SSIS or CLR. 我尝试了几种方法将此代码放入函数中,但是您不能在函数中使用动态SQL或EXEC,也不能从函数中调用SP,也不能将代码放入两个单独的SP中,因为您可以没有级联的EXEC语句,即您尝试使用上面的代码在其中执行EXEC的SP中也包含EXEC,因此...您必须使用光标将上面的两个代码块放在一起,即光标通过@FilesInAFolder将每个XMLFileName值作为变量@XMLFileName传递到第二个代码块中,或者您使用SSIS或CLR。

Sorry I ran out of time to build a complete SP with a directory name as a parameter and a cursor but that is pretty straightforward. 抱歉,我没有时间用目录名作为参数和游标来构建一个完整的SP,但这很简单。 Phew!

Are you using a stored procedure? 您正在使用存储过程吗? You can specify the file name as a parameter. 您可以将文件名指定为参数。

Something like... 就像是...

CREATE PROCEDURE sp_XMLLoad
   @FileName
AS SET NOCOUNT ON
SELECT  X.article.query('id').value('.', 'INT'),
        X.article.query('article').value('.', 'VARCHAR(50)'),   
        X.article.query('/doc/text()').value('.', 'VARCHAR(MAX)')
FROM (
      SELECT CAST(x AS XML)
      FROM OPENROWSET(
            BULK @FileName,
            SINGLE_BLOB) AS T(x)

Not exactly like that ... you'll need to add quotes around the @Filename I bet. 不完全一样...您需要在我打赌的@Filename周围加上引号。 Maybe assemble it with quotes and then use that variable. 也许用引号将其组合起来,然后使用该变量。

If you're using SSIS, you can then pump all the files from a directory to the stored procedure, or to the SSIS code used. 如果使用的是SSIS,则可以将目录中的所有文件泵送到存储过程或所用的SSIS代码中。

I think you can do it with a cursor and xp_cmdshell. 我认为您可以使用游标和xp_cmdshell做到这一点。 I would not recommend to ever use xp_cmdshell though. 我不建议您使用xp_cmdshell。

DECLARE @FilesInAFolder TABLE  (FileNames VARCHAR(500))
DECLARE @File VARCHAR(500)
INSERT INTO @FilesInAFolder
EXEC MASTER..xp_cmdshell 'dir /b c:\'


DECLARE CU CURSOR FOR 
SELECT 'c:\' + FileNames
FROM @FilesInAFolder
WHERE RIGHT(FileNames,4) = '.xml'

OPEN CU
FETCH NEXT FROM CU INTO @File
WHILE @@FETCH_STATUS = 0
BEGIN
    INSERT INTO dbo.articles(id, title, contents)
    SELECT  X.article.query('id').value('.', 'INT'),
            X.article.query('article').value('.', 'VARCHAR(50)'),
            X.article.query('/doc/text()').value('.', 'VARCHAR(MAX)')
    FROM (
            SELECT CAST(x AS XML)
            FROM OPENROWSET(
                    BULK @File,
                    SINGLE_BLOB) AS T(x)
         ) AS T(x)
    CROSS APPLY x.nodes('doc') AS X(article);

    FETCH NEXT FROM CU INTO @File
END

CLOSE CU
DEALLOCATE CU

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM