環境: SQL Server 2008
コンマ区切りの値を含む列の行があります。
そのcsvに単一の製品が存在する場合でも、行を取得するもの。
これは私ができる方法ですが、それを書く別の方法があるかどうか疑問に思っていましたか?
SELECT * FROM REWARDS
WHERE ProductCsv like '%banana%'
or ProductCsv like '%strawberry%'
or ProductCsv like '%orange%'
環境: SQL Server 2008
コンマ区切りの値を含む列の行があります。
そのcsvに単一の製品が存在する場合でも、行を取得するもの。
これは私ができる方法ですが、それを書く別の方法があるかどうか疑問に思っていましたか?
SELECT * FROM REWARDS
WHERE ProductCsv like '%banana%'
or ProductCsv like '%strawberry%'
or ProductCsv like '%orange%'
現在のクエリは、必要な結果を正確にキャプチャしていないようです。次のような行があるとします。
bananaberry cream pie,strawberry shortcake,orange juice
これはクエリに一致するかどうか。これはより正確だと思います:
WHERE ',' + ProductCsv + ',' LIKE '%,banana,%'
OR ',' + ProductCsv + ',' LIKE '%,strawberry,%'
OR ',' + ProductCsv + ',' LIKE '%,orange,%'
1 つのアイテムを見つけようとしているだけの場合は、おそらくこれがはるかに効率的です。
WHERE ',' + ProductCsv + ',' LIKE '%,banana,%'
おそらく、分割機能を使用する必要があります。例えば:
CREATE FUNCTION dbo.SplitStrings_XML
(
@List NVARCHAR(MAX),
@Delim NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
SELECT Item = y.i.value('(./text())[1]', 'nvarchar(4000)')
FROM
(
SELECT x = CONVERT(XML, '<i>' + REPLACE(@List, @Delim, '</i><i>')
+ '</i>').query('.')
) AS a CROSS APPLY x.nodes('i') AS y(i)
);
GO
だから今、あなたは言うことができます:
SELECT * FROM dbo.REWARDS AS r
WHERE EXISTS
(
SELECT 1 FROM dbo.REWARDS AS r2
CROSS APPLY dbo.SplitStrings_XML(r2.ProductCsv, ',') AS x
WHERE x.Item IN ('orange','strawberry','banana')
AND r2.[key] = r.[key]
);
またはもっと簡単に:
SELECT DISTINCT r.ProductCsv --, other columns
FROM dbo.REWARDS AS r
CROSS APPLY dbo.SplitStrings_XML(r.ProductCsv, ',') AS x
WHERE x.Item IN ('orange','strawberry','banana');
XML アプローチは、テーブルに格納できる文字列の種類によっては少し脆弱ですが、多くの代替手段があります (リストまたは個別の値としてではなく、TVP を介してセットを渡すことを含む)。分割関数のより深い背景については、次のブログ投稿を参照してください。
http://www.sqlperformance.com/2012/07/t-sql-queries/split-strings
http://www.sqlperformance.com/2012/08/t-sql-queries/splitting-strings-follow-up
http://www.sqlperformance.com/2012/08/t-sql-queries/splitting-strings-now-with-less-t-sql
とはいえ、これがあなたが今持っているものよりも優れているかどうかはわかりません.
比較するすべての値をテーブルに保存できます
DECLARE @Product_list TABLE(
products VARCHAR(50)
)
Insert into @Product_list values
('banana'),
('strawberry'),
('orange')
SELECT * FROM REWARDS
join @Product_list
on ProductCsv like '%'+products+'%'
XML を使用した次の例を見てください。
DECLARE @Table TABLE(
CommaList VARCHAR(MAX)
)
INSERT INTO @Table SELECT 'banana,test,hello'
INSERT INTO @Table SELECT 'homer,banana,test,hello'
INSERT INTO @Table SELECT 'homer,banana'
INSERT INTO @Table SELECT '1,2,3'
;WITH XMLValues AS (
SELECT *,
CAST('<d>' + REPLACE(CommaList, ',', '</d><d>') + '</d>' AS XML) XMLValue
FROM @Table t
)
, SplitValues AS (
SELECT xv.*,
T2.Loc.value('.','VARCHAR(MAX)') SplitValue
FROM XMLValues xv
CROSS APPLY XMLValue.nodes('/d') as T2(Loc)
)
SELECT DISTINCT
CommaList
FROM SplitValues
WHERE SplitValue = 'banana'
分割関数 (Web 上には多くの関数があります) を使用して、ProductsCsv を個々の要素に分割し、それをバナナやイチゴなどと比較できます。
理想的には、CSV データを列に格納するのではなく、別のテーブルを用意します。