SQL Server 2008 R2でFOR XMLステートメントを使用して、HL7継続ケアドキュメント(CCD)を作成しています。
私はこの方法で多くのことをしましたが、HTMLテーブルでデータの一部を表す必要があるのはこれが初めてであり、これが問題を引き起こしています。
したがって、表には次の情報があります。
Problem | Onset | Status
---------------------------------
Ulcer | 01/01/2008 | Active
Edema | 02/02/2005 | Active
そして、私は次をレンダリングしようとしています
<tr>
<th>Problem</th>
<th>Onset</th>
<th>Status</th>
</tr>
<tr>
<td>Ulcer</td>
<td>01/01/2008</td>
<td>Active</td>
</tr>
<tr>
<td>Edema</td>
<td>02/02/2005</td>
<td>Active</td>
</tr>
私はこのクエリを使用しています:
SELECT p.ProblemType AS "td"
, p.Onset AS "td"
, p.DiagnosisStatus AS "td"
FROM tblProblemList p
WHERE p.PatientUnitNumber = @PatientUnitNumber
FOR XML PATH('tr')
そして、私は次を取得し続けます:
<tr>
<td>Ulcer2008-01-01Active</td>
</tr>
<tr>
<td>Edema2005-02-02Active</td>
</tr>
誰かアドバイスはありますか?
select
(select p.ProblemType as 'td' for xml path(''), type),
(select p.Onset as 'td' for xml path(''), type),
(select p.DiagnosisStatus as 'td' for xml path(''), type)
from tblProblemList p
where p.PatientUnitNumber = @PatientUnitNumber
for xml path('tr')
ヘッダーも追加するには、union all
を使用できます。
select
(select 'Problem' as th for xml path(''), type),
(select 'Onset' as th for xml path(''), type),
(select 'Status' as th for xml path(''), type)
union all
select
(select p.ProblemType as 'td' for xml path(''), type),
(select p.Onset as 'td' for xml path(''), type),
(select p.DiagnosisStatus as 'td' for xml path(''), type)
from tblProblemList p
where p.PatientUnitNumber = @PatientUnitNumber
for xml path('tr')
ミカエルの答えはうまくいきますが、これもそうです:
FOR XML PATH( 'tr')を使用するのではなく、FOR XML RAW( 'tr')、ELEMENTSを使用してください。これにより、値が連結されなくなり、非常にきれいな出力が得られます。クエリは次のようになります。
SELECT p.ProblemType AS td,
p.Onset AS td,
p.DiagnosisStatus AS td
FROM tblProblemList p
WHERE p.PatientUnitNumber = @PatientUnitNumber
FOR XML RAW('tr'), ELEMENTS
純粋なマークアップを使用してヘッダー行を追加することで、何が起こっているかをより適切に制御できるようになります。完全なコードブロックは次のようになります。
DECLARE @body NVARCHAR(MAX)
SET @body = N'<table>'
+ N'<tr><th>Problem</th><th>Onset</th><th>Status</th></tr>'
+ CAST((
SELECT p.ProblemType AS td,
p.Onset AS td,
p.DiagnosisStatus AS td
FROM tblProblemList p
WHERE p.PatientUnitNumber = @PatientUnitNumber
FOR XML RAW('tr'), ELEMENTS
) AS NVARCHAR(MAX))
+ N'</table>'
出力テーブルをフォーマットする必要性に基づいて思いついた追加の値を追加したかったのです。
「AS td」エイリアスは、マークアップに<td>value</td>
要素を生成しますが、テーブルセルがtdであることを理解しているためではありません。この切断により、クエリの実行後に後で更新できる偽のHTML要素を作成できます。たとえば、ProblemType値を中央揃えにしたい場合、要素名を微調整してこれを可能にすることができます。スタイル名またはクラスを要素名に追加できないのは、SQLのエイリアスの命名規則に違反するためですが、tdcなどの新しい要素名を作成できます。これにより、<tdc>value</tdc>
要素が生成されます。これは決して有効なマークアップではありませんが、replaceステートメントで簡単に処理できます。
DECLARE @body NVARCHAR(MAX)
SET @body = N'<table>'
+ N'<tr><th>Problem</th><th>Onset</th><th>Status</th></tr>'
+ CAST((
SELECT p.ProblemType AS tdc,
p.Onset AS td,
p.DiagnosisStatus AS td
FROM tblProblemList p
WHERE p.PatientUnitNumber = @PatientUnitNumber
FOR XML RAW('tr'), ELEMENTS
) AS NVARCHAR(MAX))
+ N'</table>'
SET @body = REPLACE(@body, '<tdc>', '<td class="center">')
SET @body = REPLACE(@body, '</tdc>', '</td>')
これにより、<td class="center">value</td>
という形式のセル要素が作成されます。文字列の上部にある簡単なブロックと、簡単な調整で値を中央揃えにします。
解決する必要がある別の状況は、マークアップにリンクを含めることでした。セルの値がhrefで必要な値である限り、これは簡単に解決できます。この例を拡張して、詳細URLにリンクするIDフィールドを含めます。
DECLARE @body NVARCHAR(MAX)
SET @body = N'<table>'
+ N'<tr><th>Problem</th><th>Onset</th><th>Status</th></tr>'
+ CAST((
SELECT p.ID as tda
p.ProblemType AS td,
p.Onset AS td,
p.DiagnosisStatus AS td
FROM tblProblemList p
WHERE p.PatientUnitNumber = @PatientUnitNumber
FOR XML RAW('tr'), ELEMENTS
) AS NVARCHAR(MAX))
+ N'</table>'
SET @body = REPLACE(@body, '<tda>', '<td><a href="http://mylinkgoeshere.com/id/')
SET @body = REPLACE(@body, '</tda>', '">click-me</a></td>')
この例では、リンクテキスト内のセルの値を使用することは考慮していませんが、CHARINDEXの一部の作業では解決可能な問題です。
このシステムの最終的な実装は、SQLクエリに基づいてHTMLメールを送信することでした。セルの配置と一般的なリンクタイプが繰り返し必要だったため、置換関数をSQLの共有スカラー関数に移動したため、電子メールを送信するすべてのストアドプロシージャにそれらを含める必要はありませんでした。
これが何らかの価値をもたらすことを願っています。
FUNCTION
- baseでXML
を使用する一般的なソリューションです。SELECT
をXHTMLテーブルに変換します。
2008R2 +で動作(テスト済み)していますが、これは2008年でも動作し、2005年でも動作するはずです。誰かがこれを確認したい場合は、コメントを残してください。 THX
次の関数は、以前に提供したさまざまな関数をすべて置き換えます(必要に応じて、以前のバージョンを参照してください)
CREATE FUNCTION dbo.CreateHTMLTable
(
@SelectForXmlPathRowElementsXsinil XML
,@tblClass VARCHAR(100) --NULL to omit this class
,@thClass VARCHAR(100) --same
,@tbClass VARCHAR(100) --same
)
RETURNS XML
AS
BEGIN
RETURN
(
SELECT @tblClass AS [@class]
,@thClass AS [thead/@class]
,@SelectForXmlPathRowElementsXsinil.query(
N'let $first:=/row[1]
return
<tr>
{
for $th in $first/*
return <th>{if(not(empty($th/@caption))) then xs:string($th/@caption) else local-name($th)}</th>
}
</tr>') AS thead
,@tbClass AS [tbody/@class]
,@SelectForXmlPathRowElementsXsinil.query(
N'for $tr in /row
return
<tr>{$tr/@class}
{
for $td in $tr/*
return
if(empty($td/@link))
then <td>{$td/@class}{string($td)}</td>
else <td>{$td/@class}<a href="{$td/@link}">{string($td)}</a></td>
}
</tr>') AS tbody
FOR XML PATH('table'),TYPE
)
END
GO
いくつかの値を持つモックアップテーブル
DECLARE @tbl TABLE(ID INT, [Message] VARCHAR(100));
INSERT INTO @tbl VALUES
(1,'Value 1')
,(2,'Value 2');
-呼び出しは、SELECT ... FOR XML
を括弧で囲む必要があります!
-スニペットの実行をクリックして結果を確認します!
SELECT dbo.CreateHTMLTable
(
(SELECT * FROM @tbl FOR XML PATH('row'),ELEMENTS XSINIL)
,NULL,NULL,NULL
);
<table>
<thead>
<tr>
<th>ID</th>
<th>Message</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Value 1</td>
</tr>
<tr>
<td>2</td>
<td>Value 2</td>
</tr>
</tbody>
</table>
テーブルに名前に空白を含む列が含まれている場合、または列のキャプションを手動で設定する場合(multi langugage support!)、または置換する場合CamelCaseNameにキャプションが記述されている場合、これを属性として渡すことができます。
DECLARE @tbl2 TABLE(ID INT, [With Blank] VARCHAR(100));
INSERT INTO @tbl2 VALUES
(1,'Value 1')
,(2,'Value 2');
SELECT dbo.CreateHTMLTable
(
(
SELECT ID
,'The new name' AS [SomeOtherName/@caption] --set a caption
,[With Blank] AS [SomeOtherName]
FROM @tbl2 FOR XML PATH('row'),ELEMENTS XSINIL
)
,NULL,NULL,NULL
);
<table>
<thead>
<tr>
<th>ID</th>
<th>The new name</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Value 1</td>
</tr>
<tr>
<td>2</td>
<td>Value 2</td>
</tr>
</tbody>
</table>
属性を使用してリンクまたは行ベース、さらには値ベースのクラスを渡して、CSSスタイリング用に列やセルをマークできます。
--a mock-up table with a row based condition and hyper-links
DECLARE @tbl3 TABLE(ID INT, [With blank] VARCHAR(100),Link VARCHAR(MAX),ShouldNotBeNull INT);
INSERT INTO @tbl3 VALUES
(1,'NoWarning',NULL,1)
,(2,'No Warning too','http://www.Link2.com',2)
,(3,'Warning','http://www.Link3.com',3)
,(4,NULL,NULL,NULL)
,(5,'Warning',NULL,5)
,(6,'One more warning','http://www.Link6.com',6);
--The query adds an attribute Link to an element (NULL if not defined)
SELECT dbo.CreateHTMLTable
(
(
SELECT
CASE WHEN LEFT([With blank],2) != 'No' THEN 'warning' ELSE NULL END AS [@class] --The first @class is the <tr>-class
,ID
,'center' AS [Dummy/@class] --a class within TestText (appeary always)
,Link AS [Dummy/@link] --a mark to pop up as link
,'New caption' AS [Dummy/@caption] --a different caption
,[With blank] AS [Dummy] --blanks in the column's name must be tricked away...
,CASE WHEN ShouldNotBeNull IS NULL THEN 'MarkRed' END AS [ShouldNotBeNull/@class] --a class within ShouldNotBeNull (appears only if needed)
,'Should not be null' AS [ShouldNotBeNull/@caption] --a caption for a CamelCase-ColumnName
,ShouldNotBeNull
FROM @tbl3 FOR XML PATH('row'),ELEMENTS XSINIL),'testTbl','testTh','testTb'
);
<style type="text/css" media="screen,print">
.center
{
text-align: center;
}
.warning
{
color: red;
}
.MarkRed
{
background-color: red;
}
table,th
{
border: 1px solid black;
}
</style>
<table class="testTbl">
<thead class="testTh">
<tr>
<th>ID</th>
<th>New caption</th>
<th>Should not be null</th>
</tr>
</thead>
<tbody class="testTb">
<tr>
<td>1</td>
<td class="center">NoWarning</td>
<td>1</td>
</tr>
<tr>
<td>2</td>
<td class="center">
<a href="http://www.Link2.com">No Warning too</a>
</td>
<td>2</td>
</tr>
<tr class="warning">
<td>3</td>
<td class="center">
<a href="http://www.Link3.com">Warning</a>
</td>
<td>3</td>
</tr>
<tr>
<td>4</td>
<td class="center" />
<td class="MarkRed" />
</tr>
<tr class="warning">
<td>5</td>
<td class="center">Warning</td>
<td>5</td>
</tr>
<tr class="warning">
<td>6</td>
<td class="center">
<a href="http://www.Link6.com">One more warning</a>
</td>
<td>6</td>
</tr>
</tbody>
</table>
可能な拡張機能として、追加のパラメーターとして集計値を含むone-row-footerを渡し、<tfoot>
として追加することができます
これらの答えはすべて正常に機能しますが、最近HTMLの条件付き書式を設定したいという問題に遭遇しました。 tdのスタイルプロパティがデータに基づいて変化することを望みました。基本的な形式は、設定td =を追加したものと似ています。
declare @body nvarchar(max)
set @body =
cast
(select
'color:red' as 'td/@style', td = p.ProblemType, '',
td = p.Onset, '',
td = p.DiagnosisStatus, ''
from tblProblemList p
where p.PatientUnitNumber = @PatientUnitNumber
for xml path('tr'), type)
as nvarchar(max)
これに条件付き書式を追加するには、caseステートメントを追加するだけです。
declare @body nvarchar(max)
set @body =
cast
select
cast (case
when p.ProblemType = 1 then 'color:#ff0000;'
else 'color:#000;'
end as nvarchar(30)) as 'td/@style',
td = p.ProblemType, '',
td = p.Onset, '',
td = p.DiagnosisStatus, ''
from tblProblemList p
where p.PatientUnitNumber = @PatientUnitNumber
for xml path('tr'), type)
as nvarchar(max)
私はしばらく前にこの問題に遭遇しました。ここに私がそれを解決した方法があります:
SELECT
p.ProblemType AS "td"
, '' AS "text()"
, p.Onset AS "td"
, '' AS "text()"
, p.DiagnosisStatus AS "td"
FROM tblProblemList p
WHERE p.PatientUnitNumber = @PatientUnitNumber
FOR XML PATH('tr')
私はこれを好む:
select
convert(xml,
(
select 'column1' as th,
'column2' as th
for xml raw('tr'),elements
)),
convert(xml,
(
select t1.column1 as td,
t1.column2 as td
from #t t1
for xml raw('tr'),elements
))
for xml raw('table'),elements
すでに途方もない答えがあります。クエリ内でデザインを使用するのに適したスタイルを使用することもできます。
BEGIN
SET NOCOUNT ON;
DECLARE @htmlOpenTable VARCHAR(200) =
'<table style="border-collapse: collapse; border: 1px solid #2c3e50; background-color: #f9fbfc;">'
DECLARE @htmlCloseTable VARCHAR(200) =
'</table>'
DECLARE @htmlTdTr VARCHAR(max) = (
SELECT
'border-top: 1px solid #2c3e50' as [td/@style], someColumn as td, '',
'border-top: 1px solid #2c3e50' as [td/@style], someColumn as td, ''
FROM someTable
WHERE someCondition
FOR XML PATH('tr')
)
SELECT @htmlOpenTable + @htmlTdTr + @htmlCloseTable
END
someColumn
はテーブルの属性です
someTable
はテーブル名です
someCondition
節を使用している場合、WHERE
はオプションです。
クエリは2つの属性のみを選択することに注意してください。必要な数だけ追加でき、スタイルを変更することもできます。
もちろん、他の方法でスタイルを使用できます。実際には、外部CSSを使用する方が常に優れていますが、インラインスタイルが必要になる可能性があるため、インラインスタイルの配置方法を知ることは良い習慣です。
これを試して:
FOR XML raw, elements, root('tr')