Je crée un document HL7 Continuity of Care (CCD) à l'aide d'instructions FOR XML dans SQL Server 2008 R2.
J'ai beaucoup utilisé cette méthode, mais c'est la première fois que je dois représenter une partie des données dans un tableau HTML, ce qui me pose problème.
Donc, j'ai les informations suivantes dans un tableau:
Problem | Onset | Status
---------------------------------
Ulcer | 01/01/2008 | Active
Edema | 02/02/2005 | Active
et j'essaie de rendre ce qui suit
<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>
J'utilise cette requête:
SELECT p.ProblemType AS "td"
, p.Onset AS "td"
, p.DiagnosisStatus AS "td"
FROM tblProblemList p
WHERE p.PatientUnitNumber = @PatientUnitNumber
FOR XML PATH('tr')
Et je continue à recevoir ce qui suit:
<tr>
<td>Ulcer2008-01-01Active</td>
</tr>
<tr>
<td>Edema2005-02-02Active</td>
</tr>
Quelqu'un a un conseil?
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')
Pour ajouter également l'en-tête, vous pouvez utiliser 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')
La réponse de Mikael fonctionne mais il en ira de même:
Plutôt que d'utiliser FOR XML PATH ('tr'), utilisez FOR XML RAW ('tr'), ELEMENTS. Ceci empêchera les valeurs d'être concaténées et vous donnera une sortie très propre. Votre requête ressemblerait à ceci:
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
Je préfère ajouter la ligne d'en-tête en utilisant du balisage pur afin d'avoir un peu plus de contrôle sur ce qui se passe. Le bloc de code complet ressemblerait à ceci:
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>'
Je voulais ajouter une valeur supplémentaire que j'ai trouvée en raison de la nécessité de formater le tableau de sortie.
L'alias "AS td" produira des éléments <td>value</td>
dans le balisage, mais pas parce qu'il comprend qu'une cellule de tableau est un td. Cette déconnexion nous permet de créer de faux éléments HTML pouvant être mis à jour ultérieurement une fois la requête exécutée. Par exemple, si je voulais que la valeur ProblemType soit centrée, je peux modifier le nom de l'élément pour permettre cela. Je ne peux pas ajouter de style ou de classe au nom de l'élément car il enfreint les conventions de dénomination des alias dans SQL, mais je peux créer un nouveau nom d'élément tel que tdc. Cela produira des éléments <tdc>value</tdc>
. Bien qu'il ne s'agisse en aucun cas d'un balisage valide, il est facile de gérer une instruction de remplacement.
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>')
Cela créera des éléments de cellule au format <td class="center">value</td>
. Un bloc rapide en haut de la chaîne et vous aurez des valeurs alignées au centre avec un simple Tweak.
Une autre situation que je devais résoudre était l'inclusion de liens dans le balisage. Tant que la valeur dans la cellule est la valeur dont vous avez besoin dans le href, c'est assez facile à résoudre. Je développerai l’exemple pour inclure un champ d’identification que je souhaite lier à une URL de détail.
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>')
Cet exemple ne tient pas compte de l'utilisation de la valeur dans la cellule à l'intérieur du texte du lien, mais il s'agit d'un problème pouvant être résolu avec certains travaux CHARINDEX.
Ma dernière implémentation de ce système consistait à envoyer des courriers électroniques HTML basés sur des requêtes SQL. Comme j'avais un besoin répété d'alignement de cellules et de types de liens communs, j'ai déplacé les fonctions de remplacement dans une fonction scalaire partagée en SQL afin de ne pas avoir à les inclure dans toutes mes procédures stockées envoyant un courrier électronique.
J'espère que cela ajoute de la valeur.
FUNCTION
sur XML
- base en utilisant FLWORCela transformera toute SELECT
en une table XHTML.
Cela fonctionne (testé) avec 2008R2 +, mais je suis à peu près sûr que cela fonctionnerait en 2008, voire même en 2005. Si quelqu'un veut vérifier cela, laissez s'il vous plaît un commentaire. THX
La fonction suivante remplace toutes les fonctions fournies précédemment (voir la version précédente si nécessaire)
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
Un tableau de maquette avec des valeurs
DECLARE @tbl TABLE(ID INT, [Message] VARCHAR(100));
INSERT INTO @tbl VALUES
(1,'Value 1')
,(2,'Value 2');
- L’appel doit inclure le SELECT ... FOR XML
entre parenthèses!
-- cliquez exécuter le fragment pour voir le résultat!
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>
Si votre table contient une colonne avec un nom vide, ou si vous souhaitez définir manuellement la légende d'une colonne (support de multi langugage!), Ou si vous souhaitez remplacer un CamelCaseName avec une légende non écrite, vous pouvez passer ceci comme attribut:
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>
Vous pouvez utiliser des attributs pour passer sur un lien ou une classe basée sur des lignes et même sur des valeurs pour marquer des colonnes et même des cellules pour un style 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>
Comme amélioration possible, vous pouvez passer un paramètre one-row-footer avec des valeurs agrégées en tant que paramètre supplémentaire et l'ajouter sous la forme <tfoot>
Toutes ces réponses fonctionnent bien, mais je me suis heurté récemment à un problème où je voulais avoir un formatage conditionnel sur le code HTML, par exemple. Je voulais que la propriété de style du td varie en fonction des données. Le format de base est similaire avec l’ajout du paramètre 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)
Pour ajouter une mise en forme conditionnelle à cela, vous devez simplement ajouter une instruction 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)
J'ai rencontré ce problème il y a quelque temps. Voici comment je l'ai résolu:
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')
je préfère faire ceci:
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
Il y a déjà une formidable réponse. Je voulais juste ajouter que vous pouvez également utiliser des styles dans votre requête, ce qui peut être un avantage en termes de conception.
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
Où someColumn
est votre attribut de votre table
Et someTable
est le nom de votre table
Et someCondition
est facultatif si vous utilisez WHERE
claus
Veuillez noter que la requête ne sélectionne que deux attributs, vous pouvez en ajouter autant que vous le souhaitez et vous pouvez également modifier les styles.
Bien sûr, vous pouvez utiliser les styles de différentes manières. En fait, il est toujours préférable d'utiliser un CSS externe, mais il est recommandé de savoir comment mettre des styles en ligne car vous pourriez en avoir besoin.
Essaye ça:
FOR XML raw, elements, root('tr')