我需要从SQL Server 2005 XML列中提取访问数据,并在ASP.NET数据网格中以动态方式显示它。我想编写一个存储过程来处理转换。 XML结构非常简单(只有一个级别),但字段名称因访问类型而异。我一次只会在数据网格中显示一种访问类型,但我需要为每个数据网格选择多次访问(行)。
访问表:
CREATE TABLE Visits
(
VisitID UNIQUIDENTIFIER,
VisitType VARCHAR(10),
VisitXML XML
)
示例数据:
VisitID VisitType VisitXML
------- --------- -----------
1 Type1 (see below)
2 Type1 (see below)
3 Type2 (see below)
4 Type3 (see below)
示例VisitXML列:
记录1:
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<visit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Patient Number>100</Patient Number>
<Blood Pressure>120/84</Blood Pressure>
<Cholesterol>100</cholesterol>
</visit>
记录2:
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<visit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Patient Number>200</Patient Number>
<Blood Pressure>140/70</Blood Pressure>
<Cholesterol>204</cholesterol>
</visit>
记录3:
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<visit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Patient Number>100</Patient Number>
<Height>71 inches</Height>
</visit>
记录4:
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<visit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Patient Number>100</Patient Number>
<Sex>F</Sex>
<Weight>133.5 lbs</Height>
<BirthDate>6/19/1946</BirthDate>
<SmokingStatus>Non-Smoker</SmokingStatus>
</visit>
我希望能够动态查询某个VisitType并在网格中显示该数据,而无需引用XML字段名称。例如,我的Type1数据网格将使用自动生成的列,如下所示:
VisitID VisitType Patient Number Blood Pressure Cholesterol
------- --------- -------------- -------------- -----------
1 Type1 100 120/84 100
2 Type1 200 140/70 204
这可能吗?我需要有关存储过程的帮助。
答案 0 :(得分:0)
我能够通过阅读另一篇文章Query XML creating field names whithout knowing node names
找到使用动态SQL的解决方案我最终也使用了光标。我从来没有这样做过,但这似乎很实用。
如果有人有兴趣,请查看我的存储过程。
CREATE PROC [dbo].[myproc]
@VisitType UNIQUEIDENTIFIER
AS
/*************************************************************
THIS PROCEDURE RETURNS ALL OF THE XML FIELDS FOR EACH VISIT
IN A PARTICULAR VISIT SET.
EXAMPLE:
SourceID FacilityID AccountNumber LanguageResp Ethnicity
--------- ---------- ------------- ------------ ---------
AGH AGH V0000001 ENG NON
AGH AGH V0000099 ENG NON
**************************************************************/
/***********************************************
A GLOBAL TEMP TABLE STORES THE XML DATA AS WE
PULL IT OUT OF THE XML COLUMN, RECORD BY RECORD
(VISIT BY VISIT)
***********************************************/
BEGIN
IF (SELECT object_id('tempdb..##TempAudit')) IS NOT NULL
BEGIN
DROP TABLE ##TempAudit
END
/***********************************************
@FooTable WILL CONTAIN THE IDs and XML
COLUMN FOR THE RECORDS THAT WE WANT TO WORK
WITH.
SINCE ONE VISIT CAN HAVE MULTIPLE RECORDS
IN THIS TABLE WE CAN'T USE VISIT ID FOR OUR ID; WE HAVE TO USE
RECORD ID
***********************************************/
declare @FooTable table
(
ID_FIELD INT,
XML_FIELD xml
)
/***********************************************
WE NEED TO FIGURE OUT THE XML STRUCTURE (FIELD
NAMES) FOR THE VISIT TYPE WE ARE WORKING WITH.
EVERY XML FIELD WILL HAVE THE SAME STRUCTURE FOR
A GIVEN VISIT TYPE, SO WE JUST NEED TO LOOK AT THE
FIRST VISIT FOR THAT VISIT TYPE.
************************************************/
declare @FirstRecordID INT --@FirstVisitID VARCHAR(30)
SET @FirstRecordID = (SELECT TOP 1 RecordID FROM VisitTable WHERE VisitType = @VisitType)
/***********************************************
POPULATE @FooTable
***********************************************/
insert into @FooTable
(
ID_FIELD
,XML_FIELD
)
SELECT
RecordID
,VisitDataXML
FROM
dbo.VisitTable
WHERE
VisitType = @VisitType
and RecordID = @FirstRecordID --and VisitID = @FirstVisitID
declare @KnownName varchar(100)
SET @KnownName = 'visit'
/***********************************************
FIND THAT FIRST XLM VALUE/DOCUMENT
***********************************************/
declare @ID INT --varchar(30)
SET @ID = @FirstRecordID -- @FirstVisitID
-- Variable to hold the XML to process
declare @XML xml
select @XML = XML_FIELD
from @FooTable
where ID_FIELD = @ID
/***********************************************
WE NEED TO USE DYNAMIC SQL IN ORDER TO CONSTRUCT
OUR SELECT STATEMENT BECAUSE AT DESIGN TIME
WE DO NOT KNOW THE NAMES OF THE XLM ATTRIBUTES;
THEY ARE DIFFERENT FOR EACH VISIT TYPE
************************************************/
-- Variable for dynamic SQL
declare @SQL nvarchar(max)
-- Build the query
select @SQL = 'select '+stuff(
(
select ',T.N.value('''+T.N.value('local-name(.)', 'sysname')+'[1]'', ''varchar(max)'') as '+T.N.value('local-name(.)', 'sysname')
from @XML.nodes('/root/*[local-name(.)=sql:variable("@KnownName")]/*') as T(N)
for xml path(''), type
).value('.', 'nvarchar(max)'), 1, 1, '')+
' from @XML.nodes(''/root/*[local-name(.)=sql:variable("@KnownName")]'') as T(N)'
/***********************************************
WE ALSO NEED TO USE DYNAMIC SQL TO BUILD THE
THE TEMP TABLE FOR STORING THE RESULTS OF
WHEN WE RUN THE DYNAMIC QUERY
************************************************/
--Build the temp table:
declare @SQL2 nvarchar(max)
select @SQL2 =
'CREATE TABLE ##TempAudit (' + stuff(
(select ' ' + T.N.value('local-name(.)', 'sysname') + ' VARCHAR(MAX),'
from @XML.nodes('/root/*[local-name(.)=sql:variable("@KnownName")]/*') as T(N)
for xml path(''), type
).value('.', 'nvarchar(max)'), 1, 1, '')
--TRIM THE LAST COMMA OFF THE END OF THE TABLE STATEMENT:
SELECT @SQL2 = LEFT(@SQL2,LEN(@SQL2)-1)
--ADD A CLOSING ')' TO THE TABLE STATEMENT
SELECT @SQL2 = @SQL2 + ')'
/**************************************************************
CREATE THE TEMP TABLE BY EXECUTING THE DYMANIC SQL STATEMENT
**************************************************************/
exec sp_executesql @SQL2
--DECLARE @VisitID VARCHAR(30)
DECLARE @RecordID INT
/**************************************************************
USE A CURSOR TO EXECUTE THE XML RETRIEVAL FOR EACH RECORD
IN THE AUDIT
**************************************************************/
DECLARE the_cursor CURSOR FAST_FORWARD
FOR SELECT RecordID --VisitID
FROM dbo.VisitTable
WHERE VisitType = @VisitType
OPEN the_cursor
FETCH NEXT FROM the_cursor INTO @RecordID --@VisitID
WHILE @@FETCH_STATUS = 0
BEGIN
SELECT @XML = VisitDataXML FROM dbo.VisitTable WHERE VistType = @VisitType and RecordID = @RecordID --VisitID = @VisitID
/**************************************************************
RUN OUR DYNAMIC SQL TO PARSE THE XML FIELD
**************************************************************/
INSERT ##TempAudit
exec sp_executesql @SQL,
N'@XML xml, @KnownName varchar(100)',
@XML = @XML,
@KnownName = @KnownName
FETCH NEXT FROM the_cursor INTO @RecordID --@VisitID
END
CLOSE the_cursor
DEALLOCATE the_cursor
/**************************************************************
PERFORM THE FINAL SELECT
*************************************************************/
SELECT * FROM ##TempAudit
END