如何根据行计数将完整的XML记录写入列

时间:2016-03-25 02:22:35

标签: sql sql-server xml xp-cmdshell for-xml-path

我有一个存储过程,我根据供应商要求集成两个系统来编写自定义XML。我想将每个记录写入一列以绕过sql列中的char限制。我包含了一个非常简单的SP版本。我在真正的SP中有600个字段。我在表中有4700条记录,我的XML在200行处理后被切断了。有没有办法在自己的列中返回Command action =“Upsert”invalidLookupBehavior =“Skip”和“/ Command”之间的所有内容? 我很难过。我为重复的帖子道歉.. TAB

USE [DEV]
GO
/****** Object:  StoredProcedure [dbo].[MASTER_TABLE_XML_PHASE_I]   ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[MASTER_TABLE_XML_PHASE_I_SIMPLE]
AS
declare
@xml nvarchar(max),
@metaEMPLOYEE nvarchar(max)

CREATE TABLE #MASTER_TABLE_IMPORT
(
[EMP_COMPANY_ID] [int] NOT NULL,
[EMP_LAST_NAME] [nvarchar](50) NULL,
[EMP_MIDDLE_NAME] [nvarchar](50) NULL,
[EMP_FIRST_NAME] [nvarchar](50) NULL,
[EMP_PREFIX] [nchar](6) NULL,
[EMP_PREFERRED_NAME] [nvarchar](50) NULL,
[EMP_FORMER_NAME] [nvarchar](50) NULL,
[EMP_SYSTEM_NUMBER] [nvarchar](100) NOT NULL,
[IMP_CREATE_DATE] [datetime] NULL,
[IMP_LAST_UPDATE_DATE] [datetime] NULL,
)

INSERT INTO #MASTER_TABLE_IMPORT
(
[EMP_COMPANY_ID] ,
[EMP_LAST_NAME] ,
[EMP_MIDDLE_NAME] ,
[EMP_FIRST_NAME],
[EMP_PREFIX] ,
[EMP_PREFERRED_NAME],
[EMP_FORMER_NAME] ,
[EMP_SYSTEM_NUMBER] ,
[IMP_CREATE_DATE],
[IMP_LAST_UPDATE_DATE]
)

SELECT
EMP_COMPANY_ID ,
EMP_LAST_NAME,
EMP_MIDDLE_NAME ,
EMP_FIRST_NAME,
EMP_PREFIX ,
EMP_PREFERRED_NAME,
EMP_FORMER_NAME ,
T1.EMP_SYSTEM_NUMBER,
IMP_CREATE_DATE,
IMP_LAST_UPDATE_DATE

FROM MASTER_TABLE_PHASE_I AS T1
INNER JOIN (SELECT EMP_SYSTEM_NUMBER ,MAX(IMP_CREATE_DATE) AS MaxDate
FROM MASTER_TABLE_PHASE_I
GROUP BY EMP_SYSTEM_NUMBER) AS T2
ON (T1.EMP_SYSTEM_NUMBER = T2.EMP_SYSTEM_NUMBER AND T1.IMP_CREATE_DATE =     T2.MaxDate)
/*OPEN XML FULL FILE TAGS*/
set @xml =
N'<DataChange><Commands>'
+ N'' + CHAR(10);

/*OPEN EMPLOYEE TABLE*/
/*OPEN EMPLOYEE FIELDS*/

select @metaEMPLOYEE =
CONVERT(nvarchar(max),
(
(select
/*OPEN XML UNIQUE RECORD TAGS*/
'<Command action="Upsert" invalidLookupBehavior="Skip"><Tables><Table     name="EMPLOYEE"><Fields>'+
'<Field name="COMPANY_ID" lookupValue="False">84</Field>',
'<Field name="LAST_NAME">' + EMP_LAST_NAME + '</Field>',
'<Field name="MIDDLE_NAME">' + EMP_MIDDLE_NAME + '</Field>',
'<Field name="FIRST_NAME">' + EMP_FIRST_NAME + '</Field>',
'<Field name="PREFIX" lookupValue="True">' + EMP_PREFIX + '</Field>',
'<Field name="PREFERRED_NAME">' + EMP_PREFERRED_NAME + '</Field>',
'<Field name="FORMER_NAME">' + EMP_FORMER_NAME + '</Field>',
'<Field name="SYSTEM_NUMBER" recordIdentifier="True">' + EMP_SYSTEM_NUMBER +         '</Field>',
/*CLOSE EMPLOYEE FIELDS*/
'</Fields>',
/*CLOSE EMPLOYEE TABLE*/
'</Table>',
/*CLOSE EMPLOYEE RECORD ALL TABLES*/
'</Tables>',
/*CLOSE XML COMMAND*/
/*CLOSE XML UNIQUE RECORD TAGS*/
'</Command>'
FROM #MASTER_TABLE_IMPORT
WHERE 1=1

FOR XML PATH(''),TYPE).value('(./text())[1]','NVARCHAR(MAX)')))
/*BUILD XML*/
/*CLOSING MASTER COMMAND*/
/*CLOSING MASTER DATA CHANGE*/

SET @xml = @xml + @metaEMPLOYEE +'</Commands></DataChange>'
SELECT @xml;

CREATE TABLE XMLDATA
(
xCol XML
) ;

INSERT INTO XMLDATA ( xCol )
SELECT @xml


DECLARE @Command VARCHAR(255)
DECLARE @Filename VARCHAR(100)

SELECT @Filename = 'C:\Client_XML\Data.dat'

SELECT @Command = 'bcp "select xCol from ' + DB_NAME()
+ '..XMLDATA" queryout '
+ @Filename + ' -w -T -S' + @@servername
EXECUTE master..xp_cmdshell @command
--WRITE THE XML TO A FILE

SELECT CONVERT(nVARCHAR(max),BulkColumn)
FROM OPENROWSET(BULK 'C:\Client_XML\Data.dat', SINGLE_BLOB) AS x

DROP TABLE XMLDATA

谢谢Shnugo。我不是SQL开发人员。不幸的是我们有资源问题,所以我想我会尝试一下。我理解足够危险并正确提问。这要好得多。谢谢谢谢。在这个例子中只有少数字段(我有近600个字段和4700条记录每15分钟处理一次,因此需要这样做)。当我运行它时,XML仍然在第1200行被截断。有没有办法获取@myXML结果并根据数据源的行id解析为列?一排? SQL表中是否存在列号限制?这是我希望这张桌子看起来像的屏幕截图。 SQL Table concept

感谢您的帮助和耐心。 彭涅

我确定它是以两种方式截断的。 1-我使用xp_cmd_shell将文件保存到HD上的文件夹中 2-我已保存查询结果。

这是返回的文件行1200

中的最后一条记录
<Command action="Upsert" invalidLookupBehavior="Skip"><Tables><Table name="EMPLOYEE" /><Fields><Field name="COMPANY_ID" lookupValue="False">84</Field><Field name="LAST_NAME">Auditore</Field><Field name="MIDDLE_NAME" /><Field name="FIRST_NAME">Ezio</Field><Field name="PREFIX" loo

就在那里结束。 彭涅

嗨Shnugo。如何添加子节点==&gt; ChildTables到你的概念?我只是不断收到错误。 ASSIGNMENT语句中不允许使用FOR XML子句。

这就是XML结果的样子。我也有ChildTables嵌套在ChildTables中。

<Command action="Upsert" invalidLookupBehavior="Skip"><Tables><Table name="EMPLOYEE"><Fields><Field name="COMPANY_ID" lookupValue="False">84</Field><Field name="LAST_NAME">Pinot</Field><Field name="FIRST_NAME">Gris</Field><Field name="PREFIX" lookupValue="True">Ms.</Field><Field name="SYSTEM_NUMBER" recordIdentifier="True">1603-XXXXX</Field><Field name="GENDER" lookupValue="True">Female</Field><Field name="MARITAL_STATUS" lookupValue="True">Married</Field><Field name="BIRTH_COUNTRY" lookupValue="True">Guatemala</Field><Field name="USER_ID_EMAIL">gris.pinot@me.com</Field></Fields><ChildTables><Table name="EMPLOYEE_CF"><Fields><Field name="CF_TEXT001">Gris</Field><Field name="CF_TEXT002">Pinot</Field><Field name="CF_TEXT003">Pinot</Field><Field name="CF_TEXT026">Family</Field><Field name="CF_TEXT027">No</Field><Field name="CF_NUMBER001">2</Field></Fields></Table><Table name="EMPLOYEE_PASSPORT"><Fields><Field name="ISSUE_COUNTRY" lookupValue="True">Guatemala</Field></Fields></Table><Table name="ASSIGNMENT"><Fields><Field name="NUMBER" recordIdentifier="True">1603-XXXXX</Field><Field name="FROM_COUNTRY" lookupValue="True">United Arab Emirates</Field><Field name="TO_COUNTRY" lookupValue="True">Malaysia</Field><Field name="TYPE" lookupValue="True">Long Term</Field><Field name="PHASE" lookupValue="True">New Assignment</Field><Field name="SCHEDULED_END_DATE">04/30/2019</Field><Field name="FROM_COMPANY_LEVEL1">From Level1</Field><Field name="FROM_COMPANY_LEVEL2">From Level2</Field><Field name="FROM_COMPANY_LEVEL3">From Level3</Field><Field name="FROM_COMPANY_LEVEL4">From Level4</Field><Field name="TO_COMPANY_LEVEL1">To Level1</Field><Field name="TO_COMPANY_LEVEL2">To Level2</Field><Field name="TO_COMPANY_LEVEL3">To Level3</Field><Field name="TO_COMPANY_LEVEL4">To Level4</Field></Fields><ChildTables><Table name="ASSIGNMENT_CF"><Fields><Field name="CF_TEXT002">No</Field><Field name="CF_TEXT005">1234567</Field><Field name="CF_TEXT009">1111111</Field><Field name="CF_TEXT010">2222222</Field><Field name="CF_DATE004">03/22/2016</Field><Field name="CF_DATE005">03/23/2016</Field></Fields></Table><Table name="ASSIGNMENT_EMPLOYEE_CONTACT"><Fields><Field name="LOCATION_TYPE" recordIdentifier="true">Current Address</Field><Field name="CONTACT_TYPE" recordIdentifier="true">Address</Field></Fields></Table><Table name="ASSIGNMENT_CONTACT"><Fields><Field name="TYPE" recordIdentifier="true">Manager</Field><Field name="NAME">Trinity</Field><Field name="EMAIL">trinity@me.com.com</Field><Field name="PHONE">5555555555</Field></Fields></Table><Table name="ASSIGNMENT_CONTACT"><Fields><Field name="TYPE" recordIdentifier="true">Home HR Contact</Field><Field name="NAME">Kim</Field><Field name="EMAIL">kim.@me.com</Field><Field name="PHONE">5555555551</Field></Fields></Table><Table name="ASSIGNMENT_CONTACT"><Fields><Field name="TYPE" recordIdentifier="true">HR Contact</Field><Field name="NAME">Pennie</Field><Field name="EMAIL">me@me.com</Field><Field name="PHONE">5555555552</Field></Fields></Table><Table name="ASSIGNMENT_MAILING_ADDRESS"><Fields><Field name="LOCATION_TYPE" recordIdentifier="true">Home Address</Field> </Fields></Table><Table name="POLICY"><Fields><Field name="NAME">424</Field></Fields></Table><Table name="UT_ACCOUNT_SPECIFIC_MISC_COMP_DATA"><Fields><Field name="HOME_BUSINESS_FUNCTION">Finance</Field><Field name="HOST_BUSINESS_FUNCTION">Finance</Field><Field name="EST_ASSIGNMENT_START_DATE">07/01/2016</Field></Fields></Table></ChildTables></Table></ChildTables></Table></Tables></Command>

我很感激帮助。 彭涅 4/5 @Shnugo由于我无法使用@command,因此仍未解决。另一部分是我无法从结果集中编写XML。这是定制的。结果集来自我不拥有的系统。虽然这非常有帮助。我正在处理这些建议。我想投票,因为你非常敏感,知识渊博。也许是因为我这么新,我无法投票。无论如何,我不清楚如何投票。 P

1 个答案:

答案 0 :(得分:2)

你正在做大量不必要的工作......

  • 您似乎不需要临时表
  • 您应从不通过字符串连接将XML构建为字符串
  • SELECT ... FOR XML返回的结果(几乎)没有大小限制
  • 在大多数情况下,大小限制都绑定到中间步骤/转换/计算/其他,返回类型不够大

如果你这样,整个结果都在@myXML。 从那里你可以继续,但你喜欢......

DECLARE @myXML XML;

WITH CTE_instead_of_TempTable AS
(
    SELECT  EMP_COMPANY_ID ,
            EMP_LAST_NAME,
            EMP_MIDDLE_NAME ,
            EMP_FIRST_NAME,
            EMP_PREFIX ,
            EMP_PREFERRED_NAME,
            EMP_FORMER_NAME ,
            T1.EMP_SYSTEM_NUMBER,
            IMP_CREATE_DATE,
            IMP_LAST_UPDATE_DATE
    --This is the source you are using to fill your temp table. Cannot know, wheter it's correct or not
    --The two "FROM" lines are disturbing...
    FROM MASTER_TABLE_PHASE_I AS T1
    INNER JOIN (SELECT EMP_SYSTEM_NUMBER ,MAX(IMP_CREATE_DATE) AS MaxDate
    FROM MASTER_TABLE_PHASE_I
    GROUP BY EMP_SYSTEM_NUMBER) AS T2
    ON (T1.EMP_SYSTEM_NUMBER = T2.EMP_SYSTEM_NUMBER AND T1.IMP_CREATE_DATE =     T2.MaxDate)
)
SELECT @myXML=
(
    SELECT
    (
     SELECT
         'Upsert'               AS [@action]
        ,'Skip'                 AS [@invalidLookupBehavior]
        ,(
            SELECT 
                'EMPLOYEE'             AS [Table/@name]
               ,(
                    SELECT
                         'COMPANY_ID'           AS [Field/@name]
                        ,'False'                AS [Field/@lookupValue]
                        ,84                     AS [Field]
                        ,''
                        ,'LAST_NAME'            AS [Field/@name]
                        ,EMP_LAST_NAME          AS [Field]
                        ,''
                        ,'MIDDLE_NAME'          AS [Field/@name]
                        ,EMP_MIDDLE_NAME        AS [Field]
                        ,''
                        ,'FIRST_NAME'           AS [Field/@name]
                        ,EMP_FIRST_NAME         AS [Field]
                        ,''
                        ,'PREFIX'               AS [Field/@name]
                        ,'True'                 AS [Field/@lookupValue]
                        ,EMP_PREFIX             AS [Field]
                        ,''
                        ,'PREFERRED_NAME'       AS [Field/@name]
                        ,EMP_PREFERRED_NAME     AS [Field]
                        ,''
                        ,'FORMER_NAME'          AS [Field/@name]
                        ,EMP_FORMER_NAME        AS [Field]
                        ,''
                        ,'SYSTEM_NUMBER'        AS [Field/@name]
                        ,'True'                 AS [Field/@recordIdentifier]
                        ,EMP_SYSTEM_NUMBER      AS [Field]
                    FOR XML PATH(''),TYPE
                ) AS [Fields]
            FOR XML PATH('Tables'),TYPE
          ) 
        FROM CTE_instead_of_TempTable
        FOR XML PATH('Command'),TYPE
      )
    FOR XML PATH('Commands'),ROOT('DataChange'),TYPE
)

SELECT @myXML;