-1

次のようなデータセットがあります。

   Gender | Age | Name
    Male  | 30  | Bill
  Female  | 27  | Jenny
  Female  | 27  | Debby 
   Male   | 44  | Frank

そして、これを特別にフォーマットされた HTML コードとして表示しようとしています:

    <ul>
      <li>Male
        <ul>
          <li>30
            <ul>
              <li>Bill</li>
            </ul>
          </li>
          <li>44
            <ul>
              <li>Frank</li>
            </ul>
          </li>
        </ul>  
      </li>
    </ul>

    <ul>
      <li>Female
        <ul>
          <li>27
            <ul>
              <li>Jenny</li>
              <li>Debby</li>
            </ul>
          </li>
        </ul>  
      </li>
    </ul>

使用してみFOR XMLましたが、探していた結果が得られませんでした。Gender返された倍数とAgeフィールドは削除されませんでした。この HTML を見るとわかるように、すべてが複合されており、最後のノードでのみ複製が作成されています。

このようなことを SQL Server でどのように実現するのでしょうか?

4

2 に答える 2

5

これは、HTML を手動で作成する非常に醜い方法です。これが SQL Server に属さないのには十分な理由があります。XML の第一人者がやってきて、もっと簡単な方法で私を当惑させることは間違いありません (私はSimon Sabin のソリューションを試してみましたが、それをあなたの要件に変換することはできませんでした)。

DECLARE @x TABLE(Gender VARCHAR(6), Age INT, Name VARCHAR(32));

INSERT @x VALUES  ('Male',   30, 'Bill'),  ('Female', 27, 'Jenny'),
                  ('Female', 27, 'Debby'), ('Male',   44, 'Frank');

DECLARE @html NVARCHAR(MAX) = N'';

;WITH x AS ( SELECT x.Age, x.Gender, x.Name,
    dr = DENSE_RANK() OVER (PARTITION BY x.Gender ORDER BY x.Age),
    gn = ROW_NUMBER() OVER (PARTITION BY x.Gender ORDER BY x.Age),
    rn = ROW_NUMBER() OVER (ORDER BY x.Gender DESC, x.Age)
  FROM @x AS x ) SELECT @html +=
    CHAR(13) + CHAR(10) + CASE WHEN c1.gn = 1 THEN 
        CASE WHEN c1.rn > 1 THEN '</li></ul></li></ul>' ELSE '' END + '<ul><li>' 
        + c1.Gender ELSE '' END + CHAR(13) + CHAR(10) + CHAR(9) 
        + CASE WHEN c1.gn = 1 OR c1.Age <> c3.Age THEN 
        CASE WHEN c1.gn > 1 THEN '</li>' ELSE '<ul>' END + '<li>' 
        + CONVERT(VARCHAR(32), c1.Age) ELSE '' END + CHAR(13) + CHAR(10) + CHAR(9) 
        + CHAR(9) + CASE WHEN (c1.gn = 1 OR c1.Age <> c3.Age) THEN '<ul>' ELSE '' END 
        + '<li>' + c1.Name + '</li>' + CASE WHEN c1.Age <> c2.Age OR c1.dr <> c2.dr 
        THEN '</ul>' ELSE '' END
FROM x AS c1 
LEFT OUTER JOIN x AS c2
ON c1.rn = c2.rn - 1
LEFT OUTER JOIN x AS c3
ON c1.rn = c3.rn + 1
ORDER BY c1.Gender DESC, c1.Age;

SELECT @html += '</ul></li></ul></li></ul>';

PRINT @html; -- note you will need to deal with this 
             -- in another way if the string is large

結果 - 空白に関して要求したものとは正確には異なりますが、同一の HTML レンダリング:

<ul><li>Male
    <ul><li>30
        <ul><li>Bill</li></ul>

    </li><li>44
        <ul><li>Frank</li></ul>
</li></ul></li></ul><ul><li>Female
    <ul><li>27
        <ul><li>Jenny</li>


        <li>Debby</li></ul></li></ul></li></ul>

EDITよりクリーンなソリューション、および多くのドラマと、@ ZeeTeeがStackOverflowで最も迷惑なユーザーである理由の良いデモンストレーションについては、フォローアップの質問に対するMikaelのソリューションを参照してください。

Select ステートメントをフォーマットされた HTML として返す (SQL 2005)

于 2012-04-24T01:04:37.230 に答える
0

注:に置き換えfor $g in ("Male", "Female")ましたfor $g in distinct-values(//root /row/@Gender)

注: 2性別ごとに重複する年齢を削除しました (デモはこちら)。

また、これは XQuery を使用して行うことができます。

DECLARE @x XML = 
(
    SELECT  *
    FROM    @Test t
    FOR XML RAW, ROOT
);
SELECT @x AS [Source];
SELECT @x.query('
    for $g in distinct-values(//root/row/@Gender) (: or for $g in ("Male", "Female") :)
    return
    <ul>
        <li>
            {data($g)}
            <ul>
            {
                for $a in distinct-values(//root/row[@Gender=$g]/@Age)
                return <li>{data($a)}
                <ul>
                {
                    for $n in //root/row
                    where $n/@Gender=$g and $n/@Age = $a
                        return <li>{data($n/@Name)}</li>
                }</ul></li>
            }
            </ul> 
        </li>
    </ul>
') AS Result;

結果:

Source
----------------------------------------------------
<root>
  <row Gender="Male" Age="30" Name="Bill" />
  <row Gender="Female" Age="27" Name="Jenny" />
  <row Gender="Female" Age="27" Name="Debby" />
  <row Gender="Male" Age="44" Name="Frank" />
</root>

Result
----------------------------------------------------
<ul><li>Female<ul><li>27<ul><li>Jenny</li><li>Debby</li></ul></li></ul></li></ul>
<ul><li>Male<ul><li>30<ul><li>Bill</li></ul></li><li>44<ul><li>Frank</li></ul></li></ul></li></ul>
于 2012-04-24T06:34:11.440 に答える