从 SQL 服务器 table 到 XML 的数据
Data from SQL Server table to XML
我有 2 张桌子
CREATE TABLE [dbo].[TestData]
(
[Data] [varchar](2000) NULL,
[DataType] AS (SUBSTRING([Data], (3), (3)))
)
CREATE TABLE [dbo].[TestDataTypes]
(
DataTypeID varchar(3) NOT NULL,
DateTypeName varchar(50) NOT NULL
)
这里是一些测试数据:
INSERT INTO TestDataTypes (DataTypeID, DateTypeName)
VALUES ('010', 'DataHeader'),
('020', 'SectionHeader'),
('030', 'SectionData'),
('080', 'SectionFooter'),
('090','DataFooter');
INSERT INTO TestData ([Data])
VALUES ('FI0103146701200242606660000000000000000000020210908074601P'),
('FI020836740675301000031012700000000000000000000000020210908074601'),
('FI03020210907710000000002395847961930920210907018990006320210908000000000689708 CC000000000N'),
('FI03020210907710000000002396398519301520210907395125022320210908000000000016036 CC000000000N'),
('FI03020210907710000000002392918856530120210907738990002520210908000000000024424 CC000000000N'),
('FI0808367406700000000154000000023679373000000000000000'),
('FI09031467012002426066600000000000000000000100000000154');
现在我可以加入我的数据了
SELECT
TD.DataType, TDT.DateTypeName, TD.[data]
FROM
TestData AS TD
INNER JOIN
TestDataTypes TDT ON TD.DataType = TDT.DataTypeID
输出:
010 DataHeader FI0103146701200242606660000000000000000000020210908074601P
020 SectionHeader FI020836740675301000031012700000000000000000000000020210908074601
030 SectionData FI03020210907710000000002395847961930920210907018990006320210908000000000689708 CC000000000N
030 SectionData FI03020210907710000000002396398519301520210907395125022320210908000000000016036 CC000000000N
030 SectionData FI03020210907710000000002392918856530120210907738990002520210908000000000024424 CC000000000N
080 SectionFooter FI0808367406700000000154000000023679373000000000000000
090 DataFooter FI09031467012002426066600000000000000000000100000000154
如何在XML中让它变成这样:
<DataHeader DataType="010" girodata="FI0103146701200242606660000000000000000000020210908074601P" >
<SectionHeader DataType="020" girodata="FI020836740675301000031012700000000000000000000000020210908074601" >
<SectionData DataType="030" girodata="FI03020210907710000000002395847961930920210907018990006320210908000000000689708 CC000000000N" ></SectionData>
<SectionData DataType="030" girodata="FI03020210907710000000002396398519301520210907395125022320210908000000000016036 CC000000000N" ></SectionData>
<SectionData DataType="030" girodata="FI03020210907710000000002392918856530120210907738990002520210908000000000024424 CC000000000N" ></SectionData>
</SectionHeader>
<SectionFooter DataType="080" girodata="FI0808367406700000000154000000023679373000000000000000"></SectionFooter>
<DataFooter DataType="090" girodata="FI09031467012002426066600000000000000000000100000000154"></GiroFooter>
</DataHeader>
您可以使用 FOR XML EXPLICIT
来实现。
虽然使用 EXPLICIT
可能比对应的 RAW
、AUTO
更冗长,但它可以轻松地为您提供使用具有特定属性的嵌套节点的输出所需的控制级别.重要的是要注意,有 Tag
(作为整数)和 Parent
列分别指示标签 ID 及其关联的父级。其余列使用列命名格式 <NODE_NAME>!<TagId>!<AttributeName>
。理想情况下,您会在不需要数据的地方输出 NULL
值(我在下面使用案例表达式来实现此目的),因为这会导致返回给客户端的数据较少,但无论哪种方式都有效,我已经包含了几个您可以从下面的备选方案中进行选择,并提供一个工作演示 fiddle。我还根据您想要的 DataType
或节点使用 where 子句进行了过滤。
推荐
SELECT
CAST(TD.DataType AS INT) as Tag,
CASE
WHEN TD.DataType='010' THEN NULL
WHEN TD.DataType='030' THEN 20
ELSE 10
END as Parent,
CASE WHEN TD.DataType='010' THEN TD.DataType END as 'DataHeader!010!DataType',
CASE WHEN TD.DataType='010' THEN TD.[data] END as 'DataHeader!010!girodata',
CASE WHEN TD.DataType='020' THEN TD.DataType END as 'SectionHeader!020!DataType',
CASE WHEN TD.DataType='020' THEN TD.[data] END as 'SectionHeader!020!girodata',
CASE WHEN TD.DataType='030' THEN TD.DataType END as 'SectionData!030!DataType',
CASE WHEN TD.DataType='030' THEN TD.[data] END as 'SectionData!030!girodata',
CASE WHEN TD.DataType='080' THEN TD.DataType END as 'SectionFooter!080!DataType',
CASE WHEN TD.DataType='080' THEN TD.[data] END as 'SectionFooter!080!girodata',
CASE WHEN TD.DataType='090' THEN TD.DataType END as 'DataFooter!090!DataType',
CASE WHEN TD.DataType='090' THEN TD.[data] END as 'DataFooter!090!girodata'
FROM TestData as TD
WHERE TD.DataType IN ('010','020','080','090','030')
FOR XML EXPLICIT
其他选择
WITH my_data AS (
SELECT
TD.DataType,TDT.DateTypeName,TD.[data] as dataval
FROM TestData as TD
INNER JOIN TestDataTypes TDT on TD.DataType = TDT.DataTypeID
WHERE DataType IN ('010','020','080','090','030')
)
SELECT
CAST(DataType AS INT) as Tag,
CASE
WHEN DateTypeName='DataHeader' THEN NULL
WHEN DateTypeName='SectionData' THEN 20
ELSE 10
END as Parent,
CASE WHEN DateTypeName='DataHeader' THEN DataType END as 'DataHeader!010!DataType',
CASE WHEN DateTypeName='DataHeader' THEN dataval END as 'DataHeader!010!girodata',
CASE WHEN DateTypeName='SectionHeader' THEN DataType END as 'SectionHeader!020!DataType',
CASE WHEN DateTypeName='SectionHeader' THEN dataval END as 'SectionHeader!020!girodata',
CASE WHEN DateTypeName='SectionData' THEN DataType END as 'SectionData!030!DataType',
CASE WHEN DateTypeName='SectionData' THEN dataval END as 'SectionData!030!girodata',
CASE WHEN DateTypeName='SectionFooter' THEN DataType END as 'SectionFooter!080!DataType',
CASE WHEN DateTypeName='SectionFooter' THEN dataval END as 'SectionFooter!080!girodata',
CASE WHEN DateTypeName='DataFooter' THEN DataType END as 'DataFooter!090!DataType',
CASE WHEN DateTypeName='DataFooter' THEN dataval END as 'DataFooter!090!girodata'
FROM my_data
FOR XML EXPLICIT
或更简洁
WITH my_data AS (
SELECT
TD.DataType,TDT.DateTypeName,TD.[data] as dataval
FROM TestData as TD
INNER JOIN TestDataTypes TDT on TD.DataType = TDT.DataTypeID
WHERE DataType IN ('010','020','080','090','030')
)
SELECT
CAST(DataType AS INT) as Tag,
CASE
WHEN DateTypeName='DataHeader' THEN NULL
WHEN DateTypeName='SectionData' THEN 20
ELSE 10
END as Parent,
DataType as 'DataHeader!010!DataType',
dataval as 'DataHeader!010!girodata',
DataType as 'SectionHeader!020!DataType',
dataval as 'SectionHeader!020!girodata',
DataType as 'SectionData!030!DataType',
dataval as 'SectionData!030!girodata',
DataType as 'SectionFooter!080!DataType',
dataval as 'SectionFooter!080!girodata',
DataType as 'DataFooter!090!DataType',
dataval as 'DataFooter!090!girodata'
FROM my_data
FOR XML EXPLICIT
或
SELECT
CAST(TD.DataType AS INT) as Tag,
CASE
WHEN TDT.DateTypeName='DataHeader' THEN NULL
WHEN TDT.DateTypeName='SectionData' THEN 20
ELSE 10
END as Parent,
TD.DataType as 'DataHeader!010!DataType',
TD.[data] as 'DataHeader!010!girodata',
TD.DataType as 'SectionHeader!020!DataType',
TD.[data] as 'SectionHeader!020!girodata',
TD.DataType as 'SectionData!030!DataType',
TD.[data] as 'SectionData!030!girodata',
TD.DataType as 'SectionFooter!080!DataType',
TD.[data] as 'SectionFooter!080!girodata',
TD.DataType as 'DataFooter!090!DataType',
TD.[data] as 'DataFooter!090!girodata'
FROM TestData as TD
INNER JOIN TestDataTypes TDT on TD.DataType = TDT.DataTypeID
WHERE TD.DataType IN ('010','020','080','090','030')
FOR XML EXPLICIT
或没有连接更高效
SELECT
CAST(TD.DataType AS INT) as Tag,
CASE
WHEN TD.DataType='010' THEN NULL
WHEN TD.DataType='030' THEN 20
ELSE 10
END as Parent,
TD.DataType as 'DataHeader!010!DataType',
TD.[data] as 'DataHeader!010!girodata',
TD.DataType as 'SectionHeader!020!DataType',
TD.[data] as 'SectionHeader!020!girodata',
TD.DataType as 'SectionData!030!DataType',
TD.[data] as 'SectionData!030!girodata',
TD.DataType as 'SectionFooter!080!DataType',
TD.[data] as 'SectionFooter!080!girodata',
TD.DataType as 'DataFooter!090!DataType',
TD.[data] as 'DataFooter!090!girodata'
FROM TestData as TD
WHERE TD.DataType IN ('010','020','080','090','030')
FOR XML EXPLICIT
工作演示数据库<>fiddle here
让我知道这是否适合你。
这是完成任务的更简单的方法。
它使用标准 XML API:XQuery 及其 FLWOR 表达式。
此方法允许分两步组成XML'visually':
- 通过
FOR XML ...
创建原始 XML。
- 通过 XQuery 编写准确的输出 XML。
SQL
-- DDL and sample data population, start
DECLARE @TestData TABLE ([Data] [varchar](2000) NULL, [DataType] AS (SUBSTRING([Data], (3), (3))));
INSERT INTO @TestData ([Data]) VALUES
('FI0103146701200242606660000000000000000000020210908074601P'),
('FI020836740675301000031012700000000000000000000000020210908074601'),
('FI03020210907710000000002395847961930920210907018990006320210908000000000689708 CC000000000N'),
('FI03020210907710000000002396398519301520210907395125022320210908000000000016036 CC000000000N'),
('FI03020210907710000000002392918856530120210907738990002520210908000000000024424 CC000000000N'),
('FI0808367406700000000154000000023679373000000000000000'),
('FI09031467012002426066600000000000000000000100000000154');
-- DDL and sample data population, end
SELECT (
SELECT * FROM @TestData
FOR XML PATH('r'), TYPE, ROOT('root')
).query('<DataHeader DataType="010" girodata="{/root/r[DataType/text()="010"]/Data}" >
<SectionHeader DataType="020" girodata="{/root/r[DataType/text()="020"]/Data}" >
{
for $x in /root/r[DataType/text()="030"]
return <SectionData DataType="030" girodata="{$x/Data}"></SectionData>
}
</SectionHeader>
<SectionFooter DataType="080" girodata="{/root/r[DataType/text()="080"]/Data}"></SectionFooter>
<DataFooter DataType="090" girodata="{/root/r[DataType/text()="090"]/Data}"></DataFooter>
</DataHeader>');
输出
<DataHeader DataType="010" girodata="FI0103146701200242606660000000000000000000020210908074601P">
<SectionHeader DataType="020" girodata="FI020836740675301000031012700000000000000000000000020210908074601">
<SectionData DataType="030" girodata="FI03020210907710000000002395847961930920210907018990006320210908000000000689708 CC000000000N" />
<SectionData DataType="030" girodata="FI03020210907710000000002396398519301520210907395125022320210908000000000016036 CC000000000N" />
<SectionData DataType="030" girodata="FI03020210907710000000002392918856530120210907738990002520210908000000000024424 CC000000000N" />
</SectionHeader>
<SectionFooter DataType="080" girodata="FI0808367406700000000154000000023679373000000000000000" />
<DataFooter DataType="090" girodata="FI09031467012002426066600000000000000000000100000000154" />
</DataHeader>
我有 2 张桌子
CREATE TABLE [dbo].[TestData]
(
[Data] [varchar](2000) NULL,
[DataType] AS (SUBSTRING([Data], (3), (3)))
)
CREATE TABLE [dbo].[TestDataTypes]
(
DataTypeID varchar(3) NOT NULL,
DateTypeName varchar(50) NOT NULL
)
这里是一些测试数据:
INSERT INTO TestDataTypes (DataTypeID, DateTypeName)
VALUES ('010', 'DataHeader'),
('020', 'SectionHeader'),
('030', 'SectionData'),
('080', 'SectionFooter'),
('090','DataFooter');
INSERT INTO TestData ([Data])
VALUES ('FI0103146701200242606660000000000000000000020210908074601P'),
('FI020836740675301000031012700000000000000000000000020210908074601'),
('FI03020210907710000000002395847961930920210907018990006320210908000000000689708 CC000000000N'),
('FI03020210907710000000002396398519301520210907395125022320210908000000000016036 CC000000000N'),
('FI03020210907710000000002392918856530120210907738990002520210908000000000024424 CC000000000N'),
('FI0808367406700000000154000000023679373000000000000000'),
('FI09031467012002426066600000000000000000000100000000154');
现在我可以加入我的数据了
SELECT
TD.DataType, TDT.DateTypeName, TD.[data]
FROM
TestData AS TD
INNER JOIN
TestDataTypes TDT ON TD.DataType = TDT.DataTypeID
输出:
010 DataHeader FI0103146701200242606660000000000000000000020210908074601P
020 SectionHeader FI020836740675301000031012700000000000000000000000020210908074601
030 SectionData FI03020210907710000000002395847961930920210907018990006320210908000000000689708 CC000000000N
030 SectionData FI03020210907710000000002396398519301520210907395125022320210908000000000016036 CC000000000N
030 SectionData FI03020210907710000000002392918856530120210907738990002520210908000000000024424 CC000000000N
080 SectionFooter FI0808367406700000000154000000023679373000000000000000
090 DataFooter FI09031467012002426066600000000000000000000100000000154
如何在XML中让它变成这样:
<DataHeader DataType="010" girodata="FI0103146701200242606660000000000000000000020210908074601P" >
<SectionHeader DataType="020" girodata="FI020836740675301000031012700000000000000000000000020210908074601" >
<SectionData DataType="030" girodata="FI03020210907710000000002395847961930920210907018990006320210908000000000689708 CC000000000N" ></SectionData>
<SectionData DataType="030" girodata="FI03020210907710000000002396398519301520210907395125022320210908000000000016036 CC000000000N" ></SectionData>
<SectionData DataType="030" girodata="FI03020210907710000000002392918856530120210907738990002520210908000000000024424 CC000000000N" ></SectionData>
</SectionHeader>
<SectionFooter DataType="080" girodata="FI0808367406700000000154000000023679373000000000000000"></SectionFooter>
<DataFooter DataType="090" girodata="FI09031467012002426066600000000000000000000100000000154"></GiroFooter>
</DataHeader>
您可以使用 FOR XML EXPLICIT
来实现。
虽然使用 EXPLICIT
可能比对应的 RAW
、AUTO
更冗长,但它可以轻松地为您提供使用具有特定属性的嵌套节点的输出所需的控制级别.重要的是要注意,有 Tag
(作为整数)和 Parent
列分别指示标签 ID 及其关联的父级。其余列使用列命名格式 <NODE_NAME>!<TagId>!<AttributeName>
。理想情况下,您会在不需要数据的地方输出 NULL
值(我在下面使用案例表达式来实现此目的),因为这会导致返回给客户端的数据较少,但无论哪种方式都有效,我已经包含了几个您可以从下面的备选方案中进行选择,并提供一个工作演示 fiddle。我还根据您想要的 DataType
或节点使用 where 子句进行了过滤。
推荐
SELECT
CAST(TD.DataType AS INT) as Tag,
CASE
WHEN TD.DataType='010' THEN NULL
WHEN TD.DataType='030' THEN 20
ELSE 10
END as Parent,
CASE WHEN TD.DataType='010' THEN TD.DataType END as 'DataHeader!010!DataType',
CASE WHEN TD.DataType='010' THEN TD.[data] END as 'DataHeader!010!girodata',
CASE WHEN TD.DataType='020' THEN TD.DataType END as 'SectionHeader!020!DataType',
CASE WHEN TD.DataType='020' THEN TD.[data] END as 'SectionHeader!020!girodata',
CASE WHEN TD.DataType='030' THEN TD.DataType END as 'SectionData!030!DataType',
CASE WHEN TD.DataType='030' THEN TD.[data] END as 'SectionData!030!girodata',
CASE WHEN TD.DataType='080' THEN TD.DataType END as 'SectionFooter!080!DataType',
CASE WHEN TD.DataType='080' THEN TD.[data] END as 'SectionFooter!080!girodata',
CASE WHEN TD.DataType='090' THEN TD.DataType END as 'DataFooter!090!DataType',
CASE WHEN TD.DataType='090' THEN TD.[data] END as 'DataFooter!090!girodata'
FROM TestData as TD
WHERE TD.DataType IN ('010','020','080','090','030')
FOR XML EXPLICIT
其他选择
WITH my_data AS (
SELECT
TD.DataType,TDT.DateTypeName,TD.[data] as dataval
FROM TestData as TD
INNER JOIN TestDataTypes TDT on TD.DataType = TDT.DataTypeID
WHERE DataType IN ('010','020','080','090','030')
)
SELECT
CAST(DataType AS INT) as Tag,
CASE
WHEN DateTypeName='DataHeader' THEN NULL
WHEN DateTypeName='SectionData' THEN 20
ELSE 10
END as Parent,
CASE WHEN DateTypeName='DataHeader' THEN DataType END as 'DataHeader!010!DataType',
CASE WHEN DateTypeName='DataHeader' THEN dataval END as 'DataHeader!010!girodata',
CASE WHEN DateTypeName='SectionHeader' THEN DataType END as 'SectionHeader!020!DataType',
CASE WHEN DateTypeName='SectionHeader' THEN dataval END as 'SectionHeader!020!girodata',
CASE WHEN DateTypeName='SectionData' THEN DataType END as 'SectionData!030!DataType',
CASE WHEN DateTypeName='SectionData' THEN dataval END as 'SectionData!030!girodata',
CASE WHEN DateTypeName='SectionFooter' THEN DataType END as 'SectionFooter!080!DataType',
CASE WHEN DateTypeName='SectionFooter' THEN dataval END as 'SectionFooter!080!girodata',
CASE WHEN DateTypeName='DataFooter' THEN DataType END as 'DataFooter!090!DataType',
CASE WHEN DateTypeName='DataFooter' THEN dataval END as 'DataFooter!090!girodata'
FROM my_data
FOR XML EXPLICIT
或更简洁
WITH my_data AS (
SELECT
TD.DataType,TDT.DateTypeName,TD.[data] as dataval
FROM TestData as TD
INNER JOIN TestDataTypes TDT on TD.DataType = TDT.DataTypeID
WHERE DataType IN ('010','020','080','090','030')
)
SELECT
CAST(DataType AS INT) as Tag,
CASE
WHEN DateTypeName='DataHeader' THEN NULL
WHEN DateTypeName='SectionData' THEN 20
ELSE 10
END as Parent,
DataType as 'DataHeader!010!DataType',
dataval as 'DataHeader!010!girodata',
DataType as 'SectionHeader!020!DataType',
dataval as 'SectionHeader!020!girodata',
DataType as 'SectionData!030!DataType',
dataval as 'SectionData!030!girodata',
DataType as 'SectionFooter!080!DataType',
dataval as 'SectionFooter!080!girodata',
DataType as 'DataFooter!090!DataType',
dataval as 'DataFooter!090!girodata'
FROM my_data
FOR XML EXPLICIT
或
SELECT
CAST(TD.DataType AS INT) as Tag,
CASE
WHEN TDT.DateTypeName='DataHeader' THEN NULL
WHEN TDT.DateTypeName='SectionData' THEN 20
ELSE 10
END as Parent,
TD.DataType as 'DataHeader!010!DataType',
TD.[data] as 'DataHeader!010!girodata',
TD.DataType as 'SectionHeader!020!DataType',
TD.[data] as 'SectionHeader!020!girodata',
TD.DataType as 'SectionData!030!DataType',
TD.[data] as 'SectionData!030!girodata',
TD.DataType as 'SectionFooter!080!DataType',
TD.[data] as 'SectionFooter!080!girodata',
TD.DataType as 'DataFooter!090!DataType',
TD.[data] as 'DataFooter!090!girodata'
FROM TestData as TD
INNER JOIN TestDataTypes TDT on TD.DataType = TDT.DataTypeID
WHERE TD.DataType IN ('010','020','080','090','030')
FOR XML EXPLICIT
或没有连接更高效
SELECT
CAST(TD.DataType AS INT) as Tag,
CASE
WHEN TD.DataType='010' THEN NULL
WHEN TD.DataType='030' THEN 20
ELSE 10
END as Parent,
TD.DataType as 'DataHeader!010!DataType',
TD.[data] as 'DataHeader!010!girodata',
TD.DataType as 'SectionHeader!020!DataType',
TD.[data] as 'SectionHeader!020!girodata',
TD.DataType as 'SectionData!030!DataType',
TD.[data] as 'SectionData!030!girodata',
TD.DataType as 'SectionFooter!080!DataType',
TD.[data] as 'SectionFooter!080!girodata',
TD.DataType as 'DataFooter!090!DataType',
TD.[data] as 'DataFooter!090!girodata'
FROM TestData as TD
WHERE TD.DataType IN ('010','020','080','090','030')
FOR XML EXPLICIT
工作演示数据库<>fiddle here
让我知道这是否适合你。
这是完成任务的更简单的方法。
它使用标准 XML API:XQuery 及其 FLWOR 表达式。
此方法允许分两步组成XML'visually':
- 通过
FOR XML ...
创建原始 XML。 - 通过 XQuery 编写准确的输出 XML。
SQL
-- DDL and sample data population, start
DECLARE @TestData TABLE ([Data] [varchar](2000) NULL, [DataType] AS (SUBSTRING([Data], (3), (3))));
INSERT INTO @TestData ([Data]) VALUES
('FI0103146701200242606660000000000000000000020210908074601P'),
('FI020836740675301000031012700000000000000000000000020210908074601'),
('FI03020210907710000000002395847961930920210907018990006320210908000000000689708 CC000000000N'),
('FI03020210907710000000002396398519301520210907395125022320210908000000000016036 CC000000000N'),
('FI03020210907710000000002392918856530120210907738990002520210908000000000024424 CC000000000N'),
('FI0808367406700000000154000000023679373000000000000000'),
('FI09031467012002426066600000000000000000000100000000154');
-- DDL and sample data population, end
SELECT (
SELECT * FROM @TestData
FOR XML PATH('r'), TYPE, ROOT('root')
).query('<DataHeader DataType="010" girodata="{/root/r[DataType/text()="010"]/Data}" >
<SectionHeader DataType="020" girodata="{/root/r[DataType/text()="020"]/Data}" >
{
for $x in /root/r[DataType/text()="030"]
return <SectionData DataType="030" girodata="{$x/Data}"></SectionData>
}
</SectionHeader>
<SectionFooter DataType="080" girodata="{/root/r[DataType/text()="080"]/Data}"></SectionFooter>
<DataFooter DataType="090" girodata="{/root/r[DataType/text()="090"]/Data}"></DataFooter>
</DataHeader>');
输出
<DataHeader DataType="010" girodata="FI0103146701200242606660000000000000000000020210908074601P">
<SectionHeader DataType="020" girodata="FI020836740675301000031012700000000000000000000000020210908074601">
<SectionData DataType="030" girodata="FI03020210907710000000002395847961930920210907018990006320210908000000000689708 CC000000000N" />
<SectionData DataType="030" girodata="FI03020210907710000000002396398519301520210907395125022320210908000000000016036 CC000000000N" />
<SectionData DataType="030" girodata="FI03020210907710000000002392918856530120210907738990002520210908000000000024424 CC000000000N" />
</SectionHeader>
<SectionFooter DataType="080" girodata="FI0808367406700000000154000000023679373000000000000000" />
<DataFooter DataType="090" girodata="FI09031467012002426066600000000000000000000100000000154" />
</DataHeader>