从 Sql 服务器中的 XML 返回所有子节点作为列
Returning all child nodes as columns from XML in Sql Server
我正在对来自 XML 字符串的 select 节点执行以下操作,第一部分只是为了向您展示我 select 的来源。
问题是我想对各种不同的 XML 列执行此操作,并且我不想在我的 select 中为每个列指定节点名称,有没有办法到 select 所有节点自动作为列,甚至使用计数的游标?
DECLARE @MyXML XML
SET @MyXML = (SELECT
CAST (
'<AllowAdd>N</AllowAdd>
<Allowed>NUMSEG</Allowed>
<AllSegmentsEqualValue>N</AllSegmentsEqualValue>
<ClusterLevelSA>Y</ClusterLevelSA>
<ClusterLevelPremium>Y</ClusterLevelPremium>
<AllowAssignedAndInTrust>N</AllowAssignedAndInTrust>
<MinSegments>1</MinSegments>
<MaxSegments>100</MaxSegments>
<DefaultSegments>10</DefaultSegments>
<RoundPremiumsTo>2</RoundPremiumsTo>
<TaxDeferredAllowance>0.05</TaxDeferredAllowance>
<HigherTaxValueBands>HTVB</HigherTaxValueBands>
<NumberYearsCalculationType>NONFIN</NumberYearsCalculationType>
<OnShore>POLICY</OnShore>
<OffShore>NONFIN</OffShore>'as XML) as x)
SELECT
Data.Col.value('(/AllowAdd)[1]','Varchar(10)') as [Allow Addition of]
,Data.Col.value('(/Allowed)[1]','Varchar(10)') as [Allowed]
,Data.Col.value('(/MinSegments)[1]','Int') as [Min Segments]
,Data.Col.value('(/MaxSegments)[1]','Int') as [Max Segments]
,Data.Col.value('(/DefaultSegments)[1]','Int') as [Default Segments]
,Data.Col.value('(/RoundPremiumsTo)[1]','Int') as [Round Premiums To]
,Data.Col.value('(/AllSegmentsEqualValue)[1]','Varchar(10)') as [All Segments Equal Value]
--,Data.Col.value('(/TaxDeferredAllowance)[1]','Varchar(10)') as [Tax Deferred Allowance]
,Data.Col.value('(/HigherTaxValueBands)[1]','Varchar(10)') as [Higher Tax Value Bands]
,Data.Col.value('(/NumberYearsCalculationType)[1]','Varchar(10)') as [Number Years Calculation Type]
,Data.Col.value('(/OnShore)[1]','Varchar(10)') as [OnShore]
,Data.Col.value('(/OffShore)[1]','Varchar(10)') as [OffShore]
FROM @MyXML.nodes('/OffShore') AS Data(Col)
根据您的输入 XML,您可以尝试使用这个:
SELECT
ColName = XC.value('local-name(.)', 'varchar(100)'),
ColValue = xc.value('(.)[1]', 'varchar(100)')
FROM
@MyXML.nodes('/*') AS XT(XC)
这会将在根下找到的每个 XML 元素(其名称和值)输出为列表:
当然,由于这是一种非常通用的方法,您无法真正为第二个列中的每一列定义正确的数据类型 xc.value()
- 您基本上将所有内容都作为字符串获取。
使用游标构建 SELECT 语句并 sp_executesql 执行它!
DECLARE @MyXML XML
DECLARE @FieldName VARCHAR(MAX)
DECLARE @SELECT_TEXT NVARCHAR(MAX)
SET @MyXML = (SELECT
CAST (
'<AllowAdd>N</AllowAdd>
<Allowed>NUMSEG</Allowed>
<AllSegmentsEqualValue>N</AllSegmentsEqualValue>
<ClusterLevelSA>Y</ClusterLevelSA>
<ClusterLevelPremium>Y</ClusterLevelPremium>
<AllowAssignedAndInTrust>N</AllowAssignedAndInTrust>
<MinSegments>1</MinSegments>
<MaxSegments>100</MaxSegments>
<DefaultSegments>10</DefaultSegments>
<RoundPremiumsTo>2</RoundPremiumsTo>
<TaxDeferredAllowance>0.05</TaxDeferredAllowance>
<HigherTaxValueBands>HTVB</HigherTaxValueBands>
<NumberYearsCalculationType>NONFIN</NumberYearsCalculationType>
<OnShore>POLICY</OnShore>
<OffShore>NONFIN</OffShore>
'
as XML) as x)
SET @SELECT_TEXT = 'SELECT '
DECLARE xml_cursor CURSOR
FOR SELECT Data.Col.value( 'fn:local-name(.)', 'VARCHAR(MAX)' ) FROM @MyXML.nodes('/*') AS Data(Col)
open xml_cursor
While 1 = 1
BEGIN
fetch next from xml_cursor into @FieldName
if @@fetch_status <> 0
begin
break
end
SET @SELECT_TEXT = @SELECT_TEXT + 'Data.Col.value(''(/' + @FieldName + ')[1]'',''Varchar(MAX)'') as [' + @FieldName + ']' + ', '
END
close xml_cursor
deallocate xml_cursor
SET @SELECT_TEXT = SUBSTRING( @SELECT_TEXT,0, LEN(@SELECT_TEXT) ) + 'FROM @MyXML.nodes(''/OffShore'') AS Data(Col)'
EXECUTE sp_executesql @SELECT_TEXT, N'@MyXML XML', @MyXML = @MyXML
正如之前在另一条评论中提到的,缺点是没有列类型,但它用于报表样式查询,因此字符串是可以的。
希望,这就是您所期待的:)
DECLARE @MyXML XML
SET @MyXML = (SELECT
CAST (
'<AllowAdd>N</AllowAdd>
<Allowed>NUMSEG</Allowed>
<AllSegmentsEqualValue>N</AllSegmentsEqualValue>
<ClusterLevelSA>Y</ClusterLevelSA>
<ClusterLevelPremium>Y</ClusterLevelPremium>
<AllowAssignedAndInTrust>N</AllowAssignedAndInTrust>
<MinSegments>1</MinSegments>
<MaxSegments>100</MaxSegments>
<DefaultSegments>10</DefaultSegments>
<RoundPremiumsTo>2</RoundPremiumsTo>
<TaxDeferredAllowance>0.05</TaxDeferredAllowance>
<HigherTaxValueBands>HTVB</HigherTaxValueBands>
<NumberYearsCalculationType>NONFIN</NumberYearsCalculationType>
<OnShore>POLICY</OnShore>
<OffShore>NONFIN</OffShore>'as XML) as x)
DECLARE @Output nvarchar(max) = N''
DECLARE @PivotList nvarchar(max)
SELECT
@PivotList = COALESCE(@PivotList + ', ', N'') + N'[' + XC.value('local-name(.)', 'varchar(100)') + N']'
FROM
@MyXML.nodes('/*') AS XT(XC)
SET @Output = N'SELECT
'+@PivotList+N'
FROM
(
SELECT
ColName = XC.value(''local-name(.)'', ''nvarchar(100)''),
ColValue = ISNULL(NULLIF(CONVERT(nvarchar(max),XC.query(''./*'')),''''),XC.value(''.'',''nvarchar(max)''))
FROM
@MyXML.nodes(''/*'') AS XT(XC)
) AS s
PIVOT
(
MAX(ColValue)
FOR ColName IN ('+@PivotList+N')
) AS t;'
EXEC sp_executesql @Output, N'@MyXml xml', @MyXML = @MyXML;
我正在对来自 XML 字符串的 select 节点执行以下操作,第一部分只是为了向您展示我 select 的来源。
问题是我想对各种不同的 XML 列执行此操作,并且我不想在我的 select 中为每个列指定节点名称,有没有办法到 select 所有节点自动作为列,甚至使用计数的游标?
DECLARE @MyXML XML
SET @MyXML = (SELECT
CAST (
'<AllowAdd>N</AllowAdd>
<Allowed>NUMSEG</Allowed>
<AllSegmentsEqualValue>N</AllSegmentsEqualValue>
<ClusterLevelSA>Y</ClusterLevelSA>
<ClusterLevelPremium>Y</ClusterLevelPremium>
<AllowAssignedAndInTrust>N</AllowAssignedAndInTrust>
<MinSegments>1</MinSegments>
<MaxSegments>100</MaxSegments>
<DefaultSegments>10</DefaultSegments>
<RoundPremiumsTo>2</RoundPremiumsTo>
<TaxDeferredAllowance>0.05</TaxDeferredAllowance>
<HigherTaxValueBands>HTVB</HigherTaxValueBands>
<NumberYearsCalculationType>NONFIN</NumberYearsCalculationType>
<OnShore>POLICY</OnShore>
<OffShore>NONFIN</OffShore>'as XML) as x)
SELECT
Data.Col.value('(/AllowAdd)[1]','Varchar(10)') as [Allow Addition of]
,Data.Col.value('(/Allowed)[1]','Varchar(10)') as [Allowed]
,Data.Col.value('(/MinSegments)[1]','Int') as [Min Segments]
,Data.Col.value('(/MaxSegments)[1]','Int') as [Max Segments]
,Data.Col.value('(/DefaultSegments)[1]','Int') as [Default Segments]
,Data.Col.value('(/RoundPremiumsTo)[1]','Int') as [Round Premiums To]
,Data.Col.value('(/AllSegmentsEqualValue)[1]','Varchar(10)') as [All Segments Equal Value]
--,Data.Col.value('(/TaxDeferredAllowance)[1]','Varchar(10)') as [Tax Deferred Allowance]
,Data.Col.value('(/HigherTaxValueBands)[1]','Varchar(10)') as [Higher Tax Value Bands]
,Data.Col.value('(/NumberYearsCalculationType)[1]','Varchar(10)') as [Number Years Calculation Type]
,Data.Col.value('(/OnShore)[1]','Varchar(10)') as [OnShore]
,Data.Col.value('(/OffShore)[1]','Varchar(10)') as [OffShore]
FROM @MyXML.nodes('/OffShore') AS Data(Col)
根据您的输入 XML,您可以尝试使用这个:
SELECT
ColName = XC.value('local-name(.)', 'varchar(100)'),
ColValue = xc.value('(.)[1]', 'varchar(100)')
FROM
@MyXML.nodes('/*') AS XT(XC)
这会将在根下找到的每个 XML 元素(其名称和值)输出为列表:
当然,由于这是一种非常通用的方法,您无法真正为第二个列中的每一列定义正确的数据类型 xc.value()
- 您基本上将所有内容都作为字符串获取。
使用游标构建 SELECT 语句并 sp_executesql 执行它!
DECLARE @MyXML XML
DECLARE @FieldName VARCHAR(MAX)
DECLARE @SELECT_TEXT NVARCHAR(MAX)
SET @MyXML = (SELECT
CAST (
'<AllowAdd>N</AllowAdd>
<Allowed>NUMSEG</Allowed>
<AllSegmentsEqualValue>N</AllSegmentsEqualValue>
<ClusterLevelSA>Y</ClusterLevelSA>
<ClusterLevelPremium>Y</ClusterLevelPremium>
<AllowAssignedAndInTrust>N</AllowAssignedAndInTrust>
<MinSegments>1</MinSegments>
<MaxSegments>100</MaxSegments>
<DefaultSegments>10</DefaultSegments>
<RoundPremiumsTo>2</RoundPremiumsTo>
<TaxDeferredAllowance>0.05</TaxDeferredAllowance>
<HigherTaxValueBands>HTVB</HigherTaxValueBands>
<NumberYearsCalculationType>NONFIN</NumberYearsCalculationType>
<OnShore>POLICY</OnShore>
<OffShore>NONFIN</OffShore>
'
as XML) as x)
SET @SELECT_TEXT = 'SELECT '
DECLARE xml_cursor CURSOR
FOR SELECT Data.Col.value( 'fn:local-name(.)', 'VARCHAR(MAX)' ) FROM @MyXML.nodes('/*') AS Data(Col)
open xml_cursor
While 1 = 1
BEGIN
fetch next from xml_cursor into @FieldName
if @@fetch_status <> 0
begin
break
end
SET @SELECT_TEXT = @SELECT_TEXT + 'Data.Col.value(''(/' + @FieldName + ')[1]'',''Varchar(MAX)'') as [' + @FieldName + ']' + ', '
END
close xml_cursor
deallocate xml_cursor
SET @SELECT_TEXT = SUBSTRING( @SELECT_TEXT,0, LEN(@SELECT_TEXT) ) + 'FROM @MyXML.nodes(''/OffShore'') AS Data(Col)'
EXECUTE sp_executesql @SELECT_TEXT, N'@MyXML XML', @MyXML = @MyXML
正如之前在另一条评论中提到的,缺点是没有列类型,但它用于报表样式查询,因此字符串是可以的。
希望,这就是您所期待的:)
DECLARE @MyXML XML
SET @MyXML = (SELECT
CAST (
'<AllowAdd>N</AllowAdd>
<Allowed>NUMSEG</Allowed>
<AllSegmentsEqualValue>N</AllSegmentsEqualValue>
<ClusterLevelSA>Y</ClusterLevelSA>
<ClusterLevelPremium>Y</ClusterLevelPremium>
<AllowAssignedAndInTrust>N</AllowAssignedAndInTrust>
<MinSegments>1</MinSegments>
<MaxSegments>100</MaxSegments>
<DefaultSegments>10</DefaultSegments>
<RoundPremiumsTo>2</RoundPremiumsTo>
<TaxDeferredAllowance>0.05</TaxDeferredAllowance>
<HigherTaxValueBands>HTVB</HigherTaxValueBands>
<NumberYearsCalculationType>NONFIN</NumberYearsCalculationType>
<OnShore>POLICY</OnShore>
<OffShore>NONFIN</OffShore>'as XML) as x)
DECLARE @Output nvarchar(max) = N''
DECLARE @PivotList nvarchar(max)
SELECT
@PivotList = COALESCE(@PivotList + ', ', N'') + N'[' + XC.value('local-name(.)', 'varchar(100)') + N']'
FROM
@MyXML.nodes('/*') AS XT(XC)
SET @Output = N'SELECT
'+@PivotList+N'
FROM
(
SELECT
ColName = XC.value(''local-name(.)'', ''nvarchar(100)''),
ColValue = ISNULL(NULLIF(CONVERT(nvarchar(max),XC.query(''./*'')),''''),XC.value(''.'',''nvarchar(max)''))
FROM
@MyXML.nodes(''/*'') AS XT(XC)
) AS s
PIVOT
(
MAX(ColValue)
FOR ColName IN ('+@PivotList+N')
) AS t;'
EXEC sp_executesql @Output, N'@MyXml xml', @MyXML = @MyXML;