1. ホーム
  2. sql-server

[解決済み】カンマで区切られた文字列を個別の行に変換する方法

2022-04-02 09:47:50

質問

このようなSQLテーブルがあります。

| SomeID         | OtherID     | Data
+----------------+-------------+-------------------
| abcdef-.....   | cdef123-... | 18,20,22
| abcdef-.....   | 4554a24-... | 17,19
| 987654-.....   | 12324a2-... | 13,19,20

のようなクエリを実行することはできますか? SELECT OtherID, SplitData WHERE SomeID = 'abcdef-.......' というように、個別の行を返すようにします。

| OtherID     | SplitData
+-------------+-------------------
| cdef123-... | 18
| cdef123-... | 20
| cdef123-... | 22
| 4554a24-... | 17
| 4554a24-... | 19

基本的には、カンマの位置でデータを個々の行に分割するのですか?

を保存することは承知しています。 comma-separated の文字列をリレーショナルデータベースに格納するのは馬鹿らしく聞こえますが、コンシューマアプリケーションでの通常の使用例では、これは本当に便利なことなのです。

ページングが必要なので、アプリケーション内で分割を行うことはしたくないので、アプリ全体をリファクタリングする前に選択肢を探したいと思いました。

それは SQL Server 2008 (非R2)です。

解決方法は?

SQL Server の素晴らしい再帰的関数を使用することができます。


サンプルテーブルです。

CREATE TABLE Testdata
(
    SomeID INT,
    OtherID INT,
    String VARCHAR(MAX)
);

INSERT Testdata SELECT 1,  9, '18,20,22';
INSERT Testdata SELECT 2,  8, '17,19';
INSERT Testdata SELECT 3,  7, '13,19,20';
INSERT Testdata SELECT 4,  6, '';
INSERT Testdata SELECT 9, 11, '1,2,3,4';


クエリ

WITH tmp(SomeID, OtherID, DataItem, String) AS
(
    SELECT
        SomeID,
        OtherID,
        LEFT(String, CHARINDEX(',', String + ',') - 1),
        STUFF(String, 1, CHARINDEX(',', String + ','), '')
    FROM Testdata
    UNION all

    SELECT
        SomeID,
        OtherID,
        LEFT(String, CHARINDEX(',', String + ',') - 1),
        STUFF(String, 1, CHARINDEX(',', String + ','), '')
    FROM tmp
    WHERE
        String > ''
)
SELECT
    SomeID,
    OtherID,
    DataItem
FROM tmp
ORDER BY SomeID;
-- OPTION (maxrecursion 0)
-- normally recursion is limited to 100. If you know you have very long
-- strings, uncomment the option


出力

 SomeID | OtherID | DataItem 
--------+---------+----------
 1      | 9       | 18       
 1      | 9       | 20       
 1      | 9       | 22       
 2      | 8       | 17       
 2      | 8       | 19       
 3      | 7       | 13       
 3      | 7       | 19       
 3      | 7       | 20       
 4      | 6       |          
 9      | 11      | 1        
 9      | 11      | 2        
 9      | 11      | 3        
 9      | 11      | 4