如何将 SQL 转换为每个 ID 一行的 XML 模式(用于 XML RAW)

Posted

技术标签:

【中文标题】如何将 SQL 转换为每个 ID 一行的 XML 模式(用于 XML RAW)【英文标题】:How to convert SQL into XML schema of one row per ID (FOR XML RAW) 【发布时间】:2020-01-03 14:31:18 【问题描述】:

我必须使用每个 ID 只生成一行的架构将 SQL 转换为 XML 文件。该查询转换 ID 的“文档”并将它们全部放入单行模式中。与其为每个文档创建一个新行,不如使用节点“documentData”向现有 ID 行添加其他文档

为测试弹出创建和插入语句:

CREATE TABLE person  
(
birthDate varchar(255),
lastName varchar(255),
firstName varchar(255), 
externalStudentId3 varchar(255),
externalStudentId2 varchar(255),
externalStudentId1 varchar(255),
socialSecurityNumber varchar(255),  
documentRequirementStatusChangeOnDate datetime, 
reason varchar(255),    
scopeValue varchar(255),     
documentScope varchar(255), 
status varchar(255),    
documentName varchar(255),  
externalDocumentId varchar(255),    
dateReviewed datetime,
dateReceived datetime,
dateCreated datetime,
documentRequirementExternalId varchar(255)
)

INSERT INTO person
VALUES ('19540309','Smith','Jon','100000166','3014925','3014925','999999999',NULL,NULL,NULL,'PERSON','UNSATISFIED','ApplicationUpdate','Application_Update','20190222','20190223','20190224','01309757'),
('19540309','Smith','Jon','100000166','3014925','3014925','999999999','20190220','Document added to wrong year requirement.','2020','AwardYear','SATISFIED','CertOne','Cert_one','20190221','20190220','20190220','01294555')

样本数据:

excel screenshot of sample data

birthDate           lastName    firstName   externalStudentId3  externalStudentId2  externalStudentId1  socialSecurityNumber    documentRequirementStatusChangeOnDate   reason                                      scopeValue  documentScope   status      documentName        externalDocumentId  dateReviewed                    dateReceived                    dateCreated                     documentRequirementExternalId
1954-03-09-05:00    Smith       Jon         100000166           3014925             3014925             999999999               NULL                                    NULL                                        NULL        PERSON          UNSATISFIED ApplicationUpdate   Application_Update  2019-12-05T08:40:17.737-05:00   2019-12-05T08:40:17.737-05:00   2019-12-05T08:40:17.737-05:00   01-309757
1954-03-09-05:00    Smith       Jon         100000166           3014925             3014925             999999999               2019-02-20T10:54:08.670-05:00

每个 ID 提取多行的当前代码:

SELECT
   DISTINCT
          s.dateOfBirth as birthDate
          ,s.lastName
          ,s.firstName
          ,s.externalId3 as externalStudentId3
          ,s.externalId2 as externalStudentId2
          ,s.externalid1 as externalStudentId1
          ,s.socialSecurityNumber as socialSecurityNumber
          ,s.message as reason
          ,s.documentScopeCode as documentScope
          ,s.documentRequirementStatusCode as status
          ,s.name as documentName
          ,s.externalId as externalDocumentId
          ,s.revieweddate as dateReviewed
          ,s.receiveddate as dateReceived
          ,s.createddate as dateCreated
          ,s.documentRequirementExternalId as documentRequirementExternalId

FROM dbo.[person] s
FOR XML RAW ('student'), ROOT ('students');`

电流输出:

current output screenshot

<persons>
<person birthDate="1954-03-09-05:00" lastName="Smith" firstName="Jon" externalStudentId3="100000166" 
externalStudentId2="3014925" externalStudentId1="3014925" socialSecurityNumber="999999999" 
documentScope="PERSON" status="UNSATISFIED" documentName="ApplicationUpdate" 
externalDocumentId="Application_Update" dateReceived="2019-12-05T08:40:17.737-05:00" 
dateCreated="2019-12-05T08:40:17.737-05:00" documentRequirementExternalId="01-309757" />
<person birthDate="1954-03-09-05:00" lastName="Smith" firstName="Jon" externalStudentId3="100000166" 
externalStudentId2="3014925" externalStudentId1="3014925" socialSecurityNumber="999999999" 
documentRequirementStatusChangeOnDate="2019-02-20T10:54:08.670-05:00" reason="Document added to 
wrong year requirement." scopeValue="2020" documentScope="AwardYear" status="SATISFIED" 
documentName="CertOne" externalDocumentId="Cert_one" dateReviewed="2019-02-20T10:54:08.670-05:00" 
dateReceived="2019-02-19T13:35:03.143-05:00" dateCreated="2019-02-15T14:19:02.417-05:00" 
documentRequirementExternalId="01-294517" />
</person>

期望的输出:

desired output screenshot

<?xml version='1.0' encoding='UTF-8'?>
<persons>
  <person birthDate="1954-03-09-05:00" lastName="Smith" firstName="Jon" externalStudentId3="100000166" externalStudentId2="3014925" externalStudentId1="3014925" socialSecurityNumber="999999999"><documentData documentScope="PERSON" status="UNSATISFIED" documentName="ApplicationUpdate" externalDocumentId="Application_Update" dateReceived="2019-12-  05T08:40:17.737-05:00" dateCreated="2019-12-05T08:40:17.737-05:00" documentRequirementExternalId="01-309757" /><documentData documentRequirementStatusChangeOnDate="2019-02-20T10:54:08.670-05:00" reason="Document added to  wrong year requirement." scopeValue="2020" documentScope="AwardYear" status="SATISFIED" documentName="CertOne" externalDocumentId="Cert_one" dateReviewed="2019-02-20T10:54:08.670-05:00" dateReceived="2019-02-19T13:35:03.143-05:00" dateCreated="2019-02-15T14:19:02.417-05:00" documentRequirementExternalId="01-294517" />
  </person>
</persons>

【问题讨论】:

样本数据在这里真的很有帮助。向我们展示您(失败的)尝试的结果对我们没有帮助;我们不知道它之前是什么样子。 另外,您提供的第一个 XML 数据无效。 谢谢拉努。我尝试添加示例数据并给出了它的屏幕截图。如果每个 ID 有多个文档,这本质上就是需要将数据转换为带有附加节点的一行的数据。让我知道是否还有其他我可以提供的东西! 你的样本数据只有一张表;您的查询表明有 3 在一个困难的说明中,您为什么滥用NOLOCK 提示?它给你错误的结果:Bad habits : Putting NOLOCK everywhere 【参考方案1】:

检查一下。我只用了很少的专栏来展示这个概念。您可以轻松扩展它以获得完整的解决方案。

SQL

USE tempdb;
GO

-- DDL and sample data population, start
DROP TABLE IF EXISTS dbo.person;

CREATE TABLE dbo.person  
(
    birthDate varchar(255),
    lastName varchar(255),
    firstName varchar(255), 
    externalStudentId3 varchar(255),
    externalStudentId2 varchar(255),
    externalStudentId1 varchar(255),
    socialSecurityNumber varchar(255),  
    documentRequirementStatusChangeOnDate datetime, 
    reason varchar(255),    
    scopeValue varchar(255),     
    documentScope varchar(255), 
    status varchar(255),    
    documentName varchar(255),  
    externalDocumentId varchar(255),    
    dateReviewed datetime,
    dateReceived datetime,
    dateCreated datetime,
    documentRequirementExternalId varchar(255)
);

INSERT INTO dbo.person
VALUES ('19540309','Smith','Jon','100000166','3014925','3014925','999999999',NULL,NULL,NULL,'PERSON','UNSATISFIED','ApplicationUpdate','Application_Update','20190222','20190223','20190224','01309757')
, ('19540309','Smith','Jon','100000166','3014925','3014925','999999999','20190220','Document added to wrong year requirement.','2020','AwardYear','SATISFIED','CertOne','Cert_one','20190221','20190220','20190220','01294555');
-- DDL and sample data population, end

;WITH rs AS
(
    -- select columns pertaining to the person only
    SELECT DISTINCT externalStudentId3
        , firstName
        , lastName
    FROM dbo.person
)
SELECT p.externalStudentId3 AS [@id]
    , p.firstName AS [@firstName]
    , p.lastName AS [@lastName]
    , (SELECT c.externalStudentId3 AS [@id]
            ,c.documentScope AS [@documentScope]
            ,c.documentName AS [@documentName]
  FROM dbo.person AS c
  WHERE c.externalStudentId3 = p.externalStudentId3
  FOR XML PATH('documentData'), TYPE)
FROM rs AS p
FOR XML PATH('person'), ROOT('persons');

输出

<persons>
  <person id="100000166" firstName="Jon" lastName="Smith">
    <documentData id="100000166" documentScope="PERSON" documentName="ApplicationUpdate" />
    <documentData id="100000166" documentScope="AwardYear" documentName="CertOne" />
  </person>
</persons>

【讨论】:

感谢 Yitzhak,您的解决方案非常适合输出显示的内容。但是,当我添加代码时,它添加了空格以不将其全部放在一行中。我附上的屏幕截图显示为一行,但我粘贴的原始代码输出没有。我现在能够编辑它以显示为一行,并希望它与您提供的代码的编辑一样容易,以将其更改为一行。再次感谢! 是否可以快速编辑您的代码以使其看起来像新的输出?再次感谢您的帮助! 杰森,XML 不是字符串。此外,它本质上是分层的。我分享了 SSMS 显示的输出。 Jason,你不必担心 XML 是如何缩进的。 所以从 SQL 到 XML 至少没有一种好方法可以让每个人的 ID 为一行?我们的一个系统使用这个模式,这就是为什么我试图找到一种体面的方法来创建它。感谢您的持续帮助!您有什么方法可以推荐吗?【参考方案2】:

您可以使用 FOX XML PATH 实现此目的。我无法测试代码,可能需要进行一些调整:

 CREATE TABLE person  
(
birthDate varchar(255),
lastName varchar(255),
firstName varchar(255), 
externalStudentId3 varchar(255),
externalStudentId2 varchar(255),
externalStudentId1 varchar(255),
socialSecurityNumber varchar(255),  
documentRequirementStatusChangeOnDate datetime, 
reason varchar(255),    
scopeValue varchar(255),     
documentScope varchar(255), 
status varchar(255),    
documentName varchar(255),  
externalDocumentId varchar(255),    
dateReviewed datetime,
dateReceived datetime,
dateCreated datetime,
documentRequirementExternalId varchar(255)
)

INSERT INTO person
VALUES ('19540309','Smith','Jon','100000166','3014925','3014925','999999999',NULL,NULL,NULL,'PERSON','UNSATISFIED','ApplicationUpdate','Application_Update','20190222','20190223','20190224','01309757'),
('19540309','Smith','Jon','100000166','3014925','3014925','999999999','20190220','Document added to wrong year requirement.','2020','AwardYear','SATISFIED','CertOne','Cert_one','20190221','20190220','20190220','01294555')


;WITH cte_person(birthDate,lastName,firstName,externalStudentId3,externalStudentId2,externalStudentId1,socialSecurityNumber)
AS
(
  SELECT DISTINCT
    s.birthDate as birthDate
    ,s.lastName
    ,s.firstName
    ,s.externalStudentId3
    ,s.externalStudentId2
    ,s.externalStudentId1
    ,s.socialSecurityNumber as socialSecurityNumber
  FROM dbo.[person] s
)
SELECT
  s.birthDate as '@birthDate'
  ,s.lastName as '@lastName'
  ,s.firstName as '@firstName'
  ,s.externalStudentId3 as '@externalStudentId3'
  ,s.externalStudentId2 as '@externalStudentId2'
  ,s.externalStudentId1 as '@externalStudentId1'
  ,s.socialSecurityNumber as '@socialSecurityNumber',
  (SELECT
    d.documentScope as '@documentScope'
    ,d.reason as '@reason'
    ,d.status as '@status'
    ,d.documentName as '@documentName'
    ,d.externalDocumentId as '@externalDocumentId'
    ,d.dateReviewed as '@dateReviewed'
    ,d.dateReceived as '@dateReceived'
    ,d.dateCreated as '@dateCreated'
    ,d.documentRequirementExternalId as '@documentRequirementExternalId'
  FROM dbo.[person] d
  WHERE d.socialSecurityNumber=s.socialSecurityNumber
  FOR XML PATH ('documentData'), TYPE)
FROM cte_person s
FOR XML PATH ('student'), ROOT ('students');

输出:

<students>
  <student birthDate="19540309" lastName="Smith" firstName="Jon" externalStudentId3="100000166" externalStudentId2="3014925" externalStudentId1="3014925" socialSecurityNumber="999999999">
    <documentData documentScope="PERSON" status="UNSATISFIED" documentName="ApplicationUpdate" externalDocumentId="Application_Update" dateReviewed="2019-02-22T00:00:00" dateReceived="2019-02-23T00:00:00" dateCreated="2019-02-24T00:00:00" documentRequirementExternalId="01309757" />
    <documentData documentScope="AwardYear" reason="Document added to wrong year requirement." status="SATISFIED" documentName="CertOne" externalDocumentId="Cert_one" dateReviewed="2019-02-21T00:00:00" dateReceived="2019-02-20T00:00:00" dateCreated="2019-02-20T00:00:00" documentRequirementExternalId="01294555" />
  </student>
</students>

【讨论】:

谢谢你,彼得!这非常有用,而且看起来非常接近。这是我目前遇到的错误。我还将尝试添加一个 CREATE 和 INSERT 语句,以便更轻松地提供帮助。消息 422,级别 16,状态 4,行 28 已定义但未使用的公用表表达式。消息 156,级别 15,状态 1,第 50 行关键字“FOR”附近的语法不正确。 更新为使用提供的表/数据

以上是关于如何将 SQL 转换为每个 ID 一行的 XML 模式(用于 XML RAW)的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 BigQuery 和 Apache Beam 将 SQL 表转换为行序列列表?

将字符串转换为xml并插入Sql Server

将 T-SQL 交叉应用转换为 Oracle

如何使用 LEFT JOIN 查询将 RAW SQL 转换为 DQL

替代多个SQL自联接来转换表

如何在sql中将行转换为列