sql查询生成xml输出

时间:2012-02-03 20:47:21

标签: .net sql xml sql-server-2008

我有这些表

表1 tbl1_site [facilityId] [name]

表2 tbl2_applicant [pvid] [facilityId] [npi] [firstname]

FK加入密钥:tbl1_site.facilityId = tbl2_applicant.facilityId

表3 tbl3_abstraction [pvid] [patientnumber] [diabetesdiagnosis] [dateofbirth]

FK加入密钥:tbl2_applicant.pvId = tbl3_abstraction.pvId

我有问题创建一个sql查询来重现这个xml输出。

感谢

<account>
    <metadata />
    <practice-sites>
        <practice-site>
            <metadata>
                <data-element id="name">
                    <value>My Own Diabetes Medical Center</value>
                </data-element>
            </metadata>
            <applicants>
                <metadata />
                <applicant>
                    <metadata>
                        <data-element id="npi">
                            <value>1234567890</value>
                        </data-element>
                        <data-element id="firstname">
                            <value>Joseph</value>
                        </data-element>
                    </metadata>
                    <clinical-abstractions>                           
                        <clinical-abstraction>
                            <data-element id="diabetesdiagnosis">
                                <value>Backward</value>
                            </data-element>
                            <data-element id="dateofbirth">
                                <value>02/01/2009</value>
                            </data-element>
                            <data-element id="patientnumber">
                                <value>1</value>
                            </data-element>
                        </clinical-abstraction>
                    </clinical-abstractions>
                </applicant>
            </applicants>
        </practice-site>
    </practice-sites>
</account>

6 个答案:

答案 0 :(得分:5)

你真的需要所有这些标签吗? 我的意思是“元数据”和“数据元素”

尝试此查询,它会显示所需格式的数据:

select  t1.name as PracticeSite,
        (SELECT t2.npi as NPI, 
                t2.firstname,
                (SELECT t3.patientnumber, 
                        t3.diabetesdiagnosis, 
                        t3.dateofbirth
                        FROM tbl3_abstraction t3
                        WHERE t3.pvId=t2.pvId
                        FOR XML PATH('clinical-abstraction'), TYPE
                        ) as 'clinical-abstractions'
                FROM tbl2_applicant t2
                WHERE t1.[facilityId]=t2.[facilityId]
                FOR XML PATH('Applicant'), TYPE
        ) AS 'Applicants'
from tbl1_site t1
FOR XML path('PracticeSites'), root('account'), ELEMENTS;

答案 1 :(得分:4)

我认为最简单的方法是使用“SELECT [...] FROM AS AS XML”来创建SQL语句,以将数据作为默认的SQL Server生成的XML。完成后,使用XSLT将其转换为所需的XML格式。这可以通过SQL Server函数或.NET应用程序中的函数来完成。

答案 2 :(得分:2)

以下内容将生成您想要的确切输出。它不是有史以来最易维护的代码,但它应该给你你想要的东西。我冒昧地创建表并用数据填充它们以证明此解决方案可行。我已经猜到了各种数据类型并插入了CONVERT语句,以便在我将XML连接在一起时将它们重新转换为字符串。

注意:在SQL Server Management Studio中,您需要将输出切换为Text而不是Grid输出(快捷键为Ctrl-T),以便查询输出表示为一堆文本

SET NOCOUNT ON
-- Create some tables to work with (you should have these already)
CREATE TABLE tbl1_site ([facilityId] INT, [name] VARCHAR(100))
CREATE TABLE tbl2_applicant([pvid] INT, [facilityId] INT, [npi] BIGINT, [firstname] VARCHAR(100))
CREATE TABLE tbl3_abstraction([pvid] INT, [patientnumber] INT, [diabetesdiagnosis] VARCHAR(100), [dateofbirth] DATETIME)

-- Add some basic data
INSERT INTO tbl1_site SELECT 100, 'My Own Diabetes Medical Center'
INSERT INTO tbl2_applicant SELECT 10, 100, 1234567890, 'Joseph'
INSERT INTO tbl3_abstraction SELECT 10, 1, 'Backward', '02/01/2009' 

-- For testing (here's some more data - uncomment if desired)
--INSERT INTO tbl3_abstraction SELECT 10, 2, 'Forward', '03/04/2009' 
--INSERT INTO tbl1_site SELECT 200, 'My Other Diabetes Medical Center'
--INSERT INTO tbl2_applicant SELECT 10, 200, 9876543210, 'Conrad'
--INSERT INTO tbl3_abstraction SELECT 10, 3, 'Up', '02/01/2009' 
--INSERT INTO tbl3_abstraction SELECT 10, 4, 'Down', '03/04/2009' 

-- Declare some table variables and populate them with the required information from the base tables
-- We will use these to loop through
DECLARE @tbl1_site TABLE (tbl1Id INT IDENTITY(1, 1) PRIMARY KEY, [facilityId] INT, [name] VARCHAR(100))
INSERT INTO @tbl1_site(facilityId, name)
SELECT facilityId, name FROM tbl1_site

DECLARE @tbl2_applicant TABLE (tbl2Id INT IDENTITY(1, 1) PRIMARY KEY, [pvid] INT, [facilityId] INT, [npi] BIGINT, [firstname] VARCHAR(100))
INSERT INTO @tbl2_applicant([pvid], [facilityId], [npi], [firstname])
SELECT [pvid], [facilityId], [npi], [firstname] FROM tbl2_applicant

DECLARE @tbl3_abstraction TABLE (tbl3Id INT IDENTITY(1, 1) PRIMARY KEY, [pvid] INT, [patientnumber] INT, [diabetesdiagnosis] VARCHAR(100), [dateofbirth] DATETIME)
INSERT INTO @tbl3_abstraction([pvid], [patientnumber], [diabetesdiagnosis], [dateofbirth])
SELECT [pvid], [patientnumber], [diabetesdiagnosis], [dateofbirth] FROM tbl3_abstraction

-- Additional variables to track rows and field values
DECLARE @Maxtbl1Id INT
DECLARE @Curtbl1Id INT
DECLARE @facilityId INT

DECLARE @Maxtbl2Id INT
DECLARE @Curtbl2Id INT
DECLARE @pvid INT

DECLARE @Maxtbl3Id INT
DECLARE @Curtbl3Id INT

-- Declare an output table to hold everything in
DECLARE @OutputTable TABLE (OutputTableId INT IDENTITY(1, 1) PRIMARY KEY, XmlElement VARCHAR(8000))

-- Here is the top of the XML
INSERT INTO @OutputTable(XmlElement)
SELECT '<account>
<metadata />
<practice-sites>'

-- Loop through all the practice sites
SELECT @Maxtbl1Id = MAX(t.tbl1Id), @Curtbl1Id = MIN(t.tbl1Id) FROM @tbl1_site t

WHILE (@Maxtbl1Id >= @Curtbl1Id)
BEGIN
    INSERT INTO @OutputTable(XmlElement)
    SELECT '        <practice-site>
        <metadata>
            <data-element id="name">
                <value>' + t.name + '</value>
            </data-element>
        </metadata>'
      FROM @tbl1_site t
     WHERE tbl1Id = @Curtbl1Id

    SELECT @facilityId = t.facilityId
      FROM @tbl1_site t
     WHERE tbl1Id = @Curtbl1Id

    INSERT INTO @OutputTable (XmlElement)
    SELECT '            <applicants>
            <metadata />'

    -- Loop through all the applicants
    SELECT @Maxtbl2Id = MAX(t.tbl2Id), @Curtbl2Id = MIN(t.tbl2Id) FROM @tbl2_applicant t WHERE t.facilityId = @facilityId

    WHILE (@Maxtbl2Id >= @Curtbl2Id)
    BEGIN
        INSERT INTO @OutputTable(XmlElement)
        SELECT '                <applicant>
                <metadata>
                    <data-element id="npi">
                        <value>' + CONVERT(VARCHAR(100), t.npi) + '</value>
                    </data-element>
                    <data-element id="firstname">
                        <value>' + t.firstname + '</value>
                    </data-element>
                </metadata>'
          FROM @tbl2_applicant t
         WHERE tbl2Id = @Curtbl2Id

        SELECT @pvid = t.pvid
          FROM @tbl2_applicant t
         WHERE tbl2Id = @Curtbl2Id

        -- Loop through all the abstractions
        INSERT INTO @OutputTable(XmlElement)
        SELECT '                    <clinical-abstractions>                           
                    <clinical-abstraction>
                        <data-element id="diabetesdiagnosis">
                            <value>' + diabetesdiagnosis + '</value>
                        </data-element>
                        <data-element id="dateofbirth">
                            <value>' + CONVERT(VARCHAR(10), dateofbirth, 1) + '</value>
                        </data-element>    
                        <data-element id="patientnumber">
                            <value>' + CONVERT(VARCHAR(10), patientnumber) + '</value>
                        </data-element>
                    </clinical-abstraction>
                </clinical-abstractions>'
        FROM tbl3_abstraction t
        WHERE t.pvid = @pvid

        INSERT INTO @OutputTable(XmlElement)
        SELECT '                </applicant>
        </applicants>'

        -- Increment our counter
        SET @Curtbl2Id = @Curtbl2Id + 1
    END

    INSERT INTO @OutputTable(XmlElement)
    SELECT '        </practice-site>
</practice-sites>'

    -- Increment our counter
    SET @Curtbl1Id = @Curtbl1Id + 1
END

-- Close off XML
INSERT INTO @OutputTable(XmlElement)
SELECT '</account>'

-- Return our result set
SELECT t.XmlElement
  FROM @OutputTable t
 ORDER BY t.OutputTableId ASC

答案 3 :(得分:1)

我不建议尝试使用直接SQL来执行此操作,因为存在将SQL查询转换为XML的工具。尝试在select语句中使用FOR XML。查看Microsoft的doc,看看这是否适合您。

答案 4 :(得分:0)

这看起来不像SQL应该做的那样。这太复杂了。那个xml过于深沉,有许多空元素。请记住,XML是层次结构,而如果您正在使用SQL Server,那么这是一个关系数据库,两者完全不同。根据 @Bernard 评论背后的可能暗示,什么消耗了xml,因此这是一个更好的转换位置?

如果您可以切换到更简单的xml架构,那么 @Diego 建议的方法可以为您提供最简单的结构。

使用 FOR XML PATH 来获取您在问题中指定的xml,将您带入一组嵌套的select语句,这些语句很难维护(一次写入,从不读取)。所以只是为了表明它是可能的 - 我真的不会建议 - 下面是使用 FOR XML EXPLICIT 的示例。这至少稍微容易理解,但如果必须添加元素,则需要在每个部分进行更改。

使用 FOR XML EXPLICIT 时,您有两个要求:
1.指定所涉及的元素/属性(通常是第一个SQL部分)
2.在适当的位置指定元素之间的关系以及值。

select 1 as tag,
       null as parent,
       null as [account!1],
       null as [metadata!2],
       null as [practice-sites!3],
       null as [practice-site!4],
       null as [metadata!5],
       null as [data-element!6!id],
       null as [data-element!6!value!ELEMENT],
       null as [applicants!7],
       null as [metadata!8],
       null as [applicant!9],
       null as [metadata!10],
       null as [data-element!11!id],
       null as [data-element!11!value!ELEMENT],
       null as [data-element!12!id],
       null as [data-element!12!value!ELEMENT],
       null as [clinical-abstractions!13],
       null as [clinical-abstraction!14],
       null as [data-element!15!id],
       null as [data-element!15!value!ELEMENT],
       null as [data-element!16!id],
       null as [data-element!16!value!ELEMENT],
       null as [data-element!17!id],
       null as [data-element!17!value!ELEMENT]

union all
select 2,
       1,
       null, null, null, null, null, null, null, null, null, null, null, null,
       null, null, null, null, null, null, null, null, null, null, null

union all
select 3,
       1,
       null, null, null, null, null, null, null, null, null, null, null, null,
       null, null, null, null, null, null, null, null, null, null, null       

union all
select 4,
       3,
       null, null, null, null, null, null, null, null, null, null, null, null,
       null, null, null, null, null, null, null, null, null, null, null

union all
select 5,
       4,
       null, null, null, null, null, null, null, null, null, null, null, null,
       null, null, null, null, null, null, null, null, null, null, null

union all
select 6,
       5,
       null,
       null,
       null,
       null,
       null,
       'name',
       s.name,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null   
from dbo.tbl1_Site s
where s.facilityID = @facilityID

union all
select 7,
       4,
       null, null, null, null, null, null, null, null, null, null, null, null,
       null, null, null, null, null, null, null, null, null, null, null

union all
select 8,
       7,
       null, null, null, null, null, null, null, null, null, null, null, null,
       null, null, null, null, null, null, null, null, null, null, null

union all
select 9,
       7,
       null, null, null, null, null, null, null, null, null, null, null, null,
       null, null, null, null, null, null, null, null, null, null, null

union all
select 10,
       9,
       null, null, null, null, null, null, null, null, null, null, null, null,
       null, null, null, null, null, null, null, null, null, null, null

union all
select 11,
       10,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       'npi',
       ap.npi,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null
from dbo.tbl2_Applicant ap
where ap.pvid = @pvid

union all
select 12,
       10,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       'firstname',
       ap.firstname,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null
from dbo.tbl2_Applicant ap
where ap.pvid = @pvid

union all
select 13,
       9,
       null, null, null, null, null, null, null, null, null, null, null, null,
       null, null, null, null, null, null, null, null, null, null, null

union all
select 14,
       13,
       null, null, null, null, null, null, null, null, null, null, null, null,
       null, null, null, null, null, null, null, null, null, null, null

union all
select 15,
       14,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       'diabetesdiagnosis',
       a.diabetesdiagnosis,
       null,
       null,
       null,
       null
from dbo.tbl3_Abstraction a
where a.patientnumber = @patientnumber

union all
select 16,
       14,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       'dateofbirth',
       convert(varchar(10), a.dateofbirth, 101),
       null,
       null
from dbo.tbl3_Abstraction a
where a.patientnumber = @patientnumber

union all
select 17,
       14,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       null,
       'patientnumber',
       a.patientnumber
from dbo.tbl3_Abstraction a
where a.patientnumber = @patientnumber

for xml explicit

注意我通常会将每个属性/元素保存在SQL中的一个单独的行中,但是考虑到空元素的数量,我将空包装只是为了整理(一点点)。 有可能略微减少这一点,但坦率地说,没有意义。它已经证明这不是正确的方法。

答案 5 :(得分:0)

为什么必须在DB中创建XML?为什么不在BL中生成它?维护和维护更容易我认为就性能而言,它将比SQL更高效。