web-dev-qa-db-ja.com

コンマ区切りの文字列の各値の行を作成する

私は現在、次のことを行うテーブルからビューを作成しようとしています:

Table A
╔═════════════╦═══════════════╗ 
║ PART NUMBER ║   FILE NAME   ║
╠═════════════╬═══════════════╣
║  PN0001-01  ║      FOO      ║
║  PN0002-01  ║      BAR      ║
║  PN0003-01  ║    FOO,BAR    ║
║  PN0004-01  ║  BAR,FOO,FOB  ║
╚═════════════╩═══════════════╝

作成するには

View B
╔═════════════╦═══════════════╗ 
║ PART NUMBER ║   FILE NAME   ║
╠═════════════╬═══════════════╣
║  PN0001-01  ║      FOO      ║
║  PN0002-01  ║      BAR      ║
║  PN0003-01  ║      FOO      ║
║  PN0003-01  ║      BAR      ║
║  PN0004-01  ║      BAR      ║
║  PN0004-01  ║      FOO      ║
║  PN0004-01  ║      FOB      ║
╚═════════════╩═══════════════╝

したがって、基本的には、テーブルAからレコードを取得してビューBに挿入する必要があります。AのレコードにLIKE '[、]'プロパティがある場合、そのフィールドは数に応じてBの複数のレコードに分割されます。多くの場合、「、」は存在し、各「、」の間のテキストにはビューBで独自のレコードが与えられます。

2
ErickM

まず、文字列分割関数を作成します。

_CREATE FUNCTION dbo.SplitString
(
    @List      nvarchar(max),
    @Delimiter nvarchar(10)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
  RETURN 
  (
    WITH x(x) AS 
    (
      SELECT 1 UNION ALL SELECT x+1 FROM x 
      WHERE x < (LEN(@List))
    )
    SELECT Item = SUBSTRING(@List, x, 
      CHARINDEX(@Delimiter, @List + @Delimiter, x) - x)
    FROM x WHERE x <= CONVERT(INT, LEN(@List))
      AND SUBSTRING(@Delimiter + @List, x, 1) = @Delimiter  );
GO
_

次に、ソースを関数とクロス適用するだけです:

_DECLARE @x TABLE(PartNumber nvarchar(255), FileName nvarchar(max));

INSERT @x(PartNumber, FileName) VALUES
('PN0001-01','FOO'),
('PN0002-01','BAR'),
('PN0003-01','FOO,BAR'),
('PN0004-01','BAR,FOO,FOB');

-- INSERT dbo.ViewName(col1,col2)
SELECT x.PartNumber, f.Item
FROM @x AS x
CROSS APPLY dbo.SplitString(x.FileName, N',') AS f;
_

SQL Server 2016では、ネイティブのSTRING_SPLIT()関数を使用できます。

6
Aaron Bertrand

SQL Server 2016では(元の投稿者から要求されたバージョンではありませんが)、 STRING_SPLIT 、@ Aaron Bertrandが彼の回答で提案したことを実行します::

SELECT 
    part_number, value AS file_name
FROM 
    parts CROSS APPLY STRING_SPLIT(file_name, ',') 
ORDER BY 
    part_number, file_name ;

...これが元のデータであると仮定

ALTER DATABASE my_database 
    SET COMPATIBILITY_LEVEL  = 130 ;

CREATE TABLE parts
(
    part_number varchar(100) PRIMARY KEY,
    file_name varchar(100)
) ;

INSERT INTO parts 
    (part_number, file_name)
VALUES 
    ('PN0001-01', 'FOO'),
    ('PN0002-01', 'BAR'),
    ('PN0003-01', 'FOO,BAR'),
    ('PN0004-01', 'BAR,FOO,FOB') ;

それが結果です:

part_number   file_name
PN0001-01     FOO
PN0002-01     BAR
PN0003-01     BAR
PN0003-01     FOO
PN0004-01     BAR
PN0004-01     FOB
PN0004-01     FOO
1
joanolo