12

テーブルから区切られたリストを作成するために Google の助けを借りてこのクエリを作成しましたが、このクエリからは何も理解できませんでした。

何が起こっているのか誰か説明してくれませんか

 SELECT 
    E1.deptno, 
    allemp = Replace ((SELECT E2.ename AS 'data()' 
                       FROM emp AS e2 
                       WHERE e1.deptno = e2.DEPTNO 
                       FOR xml PATH('')), ' ', ', ') 
 FROM EMP AS e1 
 GROUP BY DEPTNO; 

私に結果を与える

10  CLARK, KING, MILLER
20  SMITH, JONES, SCOTT, ADAMS, FORD
30  ALLEN, WARD, MARTIN, BLAKE, TURNER, JAMES
4

4 に答える 4

38

これを説明する最も簡単な方法はFOR XML PATH、実際の XML でどのように機能するかを調べることです。簡単なテーブルを想像してくださいEmployee:

EmployeeID      Name
1               John Smith
2               Jane Doe

あなたが使用することができます

SELECT  EmployeeID, Name
FROM    emp.Employee
FOR XML PATH ('Employee')

これにより、次のような XML が作成されます。

<Employee>
    <EmployeeID>1</EmployeeID>
    <Name>John Smith</Name>
</Employee>
<Employee>
    <EmployeeID>2</EmployeeID>
    <Name>Jane Doe</Name>
</Employee>

から「従業員」をPATH削除すると、外側の xml タグが削除されるため、次のクエリは次のようになります。

SELECT  Name
FROM    Employee
FOR XML PATH ('')

作成します

    <Name>John Smith</Name>
    <Name>Jane Doe</Name>

次に行っていることは理想的ではありません。列名 'data()' は、正当なタグではない xml タグを作成しようとしているため、SQL エラーを強制するため、次のエラーが生成されます。

列名 'Data()' には、FOR XML で必要な無効な XML 識別子が含まれています。'('(0x0028) は、障害のある最初の文字です。

相関サブクエリはこのエラーを隠し、タグなしで XML を生成するだけです。

SELECT  Name AS [Data()]
FROM    Employee
FOR XML PATH ('')

作成します

John Smith Jane Doe

次に、スペースをコンマに置き換えています。かなり自明です...

私があなただったら、クエリを少し変更します。

SELECT  E1.deptno, 
        STUFF(( SELECT  ', ' + E2.ename 
                FROM    emp AS e2 
                WHERE   e1.deptno = e2.DEPTNO 
                FOR XML PATH('')
            ), 1, 2, '') 
FROM    EMP AS e1 
GROUP BY DEPTNO; 

列エイリアスがないということは、xml タグが作成されないことを意味し、選択クエリ内にカンマを追加すると、名前にスペースが含まれていてもエラーが発生せずSTUFF、最初のカンマとスペースが削除されることを意味します。

補遺

KMがコメントで述べたことを詳しく説明すると、これはさらにいくつかのビューを取得しているように見えるため、XML文字をエスケープする正しい方法は.value次のように使用することです:

SELECT  E1.deptno, 
        STUFF(( SELECT  ', ' + E2.ename 
                FROM    emp AS e2 
                WHERE   e1.deptno = e2.DEPTNO 
                FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)'), 1, 2, '') 
FROM    EMP AS e1 
GROUP BY DEPTNO; 
于 2012-04-30T10:15:37.247 に答える
6

それを段階的に分解します-裏返しに。

ステップ1:

最も内側のクエリを実行して、何が生成されるかを確認します。

SELECT E2.ename AS 'data()' 
FROM emp AS e2 
WHERE e2.DEPTNO = 10
FOR XML PATH('')

次のような出力が得られるはずです。

CLARK KING MILLER

ステップ2:

REPLACEスペースを-に置き換えるだけで,、出力が次のようになります。

CLARK, KING, MILLER

ステップ3:

外側のクエリはdeptno値(および内側のクエリからの結果)を取得し、最終結果を生成します。

于 2012-04-30T09:49:39.723 に答える
1

SQL Server 2017では、新しいSTRING_AGG. 最近、この投稿に出会い、新しい文字列関数を使用するようにSTUFF/FOR XML戦略を切り替えました。また、追加の JOIN/SUBQUERY を実行する必要がなくなり、FOR XML のオーバーヘッド (および奇妙なエンコーディングの問題) や、SQL の解釈が困難になります。

SELECT  E1.deptno, 
        STRING_AGG(E1.ename, ', ') AS allemp
FROM    EMP AS e1 
GROUP BY DEPTNO; 

: SQL で区切られたデータの操作をより簡単にするために、対応するものも確認してください。STRING_SPLIT

于 2017-09-30T11:41:09.253 に答える
0

外側のクエリは部門番号のリストを取得し、各部門番号に対してサブクエリを実行して、その部門に属するすべての名前を返します。サブクエリは、FOR XML ステートメントを使用して、出力を単一行のコンマ区切りリストにフォーマットします。

于 2012-04-30T09:45:32.810 に答える