1

これは非常にトリッキーです...

Products表 -> 製品には複数の色があります..

特定の色の製品を戻すストアド プロシージャが必要です。

たとえば、サンタの帽子には「緑」と「赤」があります.「緑」と「赤」を含むすべての製品が必要です.「緑」または「赤」だけでなく、両方..

これは私がこれまでに持っているものです...

問題

  1. 両方ではなく、どちらかまたはいずれかの色を持つ製品を復活させます..
  2. 重複レコード..

コード:

DECLARE @COLORS VARCHAR(MAX) = 'Red, Green'

SELECT * 
FROM Products p
LEFT JOIN Product_Colors_Bridge b ON b.ProductID = p.ProductID
LEFT JOIN Product_Colors c on c.ID = b.ColorID
CROSS JOIN dbo.SplitString(@COLORS, ',', NULL)
WHERE CHARINDEX(token, Color) <> 0

これの写真...

4

3 に答える 3

0

SQL-Server 2008 以降を使用していると仮定すると、SQL で区切られた文字列を使用しないようにすることをお勧めします。複数の値をパラメーターとして渡したい場合は、テーブル値パラメーターを使用します。

したがって、型に複数の色を格納することから始めます (再利用できるように一般的な名前を付けます)。

CREATE TYPE dbo.StringList AS TABLE (Value NVARCHAR(MAX));

これにより、パラメーターを作成するのにそれほど労力がかかることはありませんが、コストのかかる (手続き型の) 分割メソッドを回避できます。クエリは次のようになります。

DECLARE @Colors dbo.StringList;
INSERT @Colors VALUES ('Red'), ('Green');

SELECT  p.ProductID, p.ProductName
FROM    Products p
        INNER JOIN Product_Colors_Bridge b 
            ON b.ProductID = p.ProductID
        INNER JOIN Product_Colors c 
            ON c.ID = b.ColorID
        INNER JOIN @colors co
            ON co.Value = c.Color
GROUP BY p.ProductID, p.ProductName
HAVING  COUNT(DISTINCT c.Color) = (SELECT COUNT(DISTINCT Value) FROM @Colors);

-- HAVING IS KEY HERE, STATING THAT THE COUNT OF DIFFERENT COLOURS ASSOCIATED 
-- WITH THE PRODUCT IS THE SAME AS THE NUMBER OF DIFFERENT COLOURS PASSED TO
-- THE QUERY IN THE PARAMETER
于 2013-06-14T16:22:57.987 に答える
0

これは、set-within-sets サブクエリの例です。集計を使用してこれらを解決するのが好きです。ここでは、色を文字列でリストしているため、コードは少し複雑になります。

select pcp.ProductId, p.ProductName
from Product p join
     Product_Colors_Bridge pcb
     on p.id = pcb.ProductId join
     Product_Colors pc
     on pcb.ColorId = pc.Id
group by pcp.ProductId, p.ProductName
having count(distinct (case when charindex(pc.Color, @Colors) > 1 then pc.Color end)) =
       (1 + len(@Colors) - len(replace(@Colors, ',', '')))

キーはhaving句です。最初の部分は、リストにある製品の色の数を数えます。2 番目は、コンマなしの文字列の長さの差をとって、色の総数をカウントします。

case必要に応じて、条件を -- の前に移動することもできますが、group by他の色は気にしないことを前提としています。

select pcp.ProductId, p.ProductName
from Product p join
     Product_Colors_Bridge pcb
     on p.id = pcb.ProductId join
     Product_Colors pc
     on pcb.ColorId = pc.Id join
     dbo.SplitString(@COLORS, ',', NULL) ssc
     on ssc.token = pc.Color
group by pcp.ProductId, p.ProductName
having count(*) =
       (1 + len(@Colors) - len(replace(@Colors, ',', '')))
于 2013-06-14T16:12:28.933 に答える
0

を使用してこれを行う簡単な方法を次に示しますlike

declare @colors varchar(max) = 'Red,Green'; 

select p.ProductID, p.ProductName
from Products p
    join Product_Colors_Bridge b on b.ProductID = p.ProductID
    join Product_Colors c on c.ID = b.ColorID
where ',' + @colors + ',' like '%,' + c.Color + ',%'
group by p.ProductID, p.ProductName
having count(*) = len(@colors) - len(replace(@colors, ',', '')) + 1;

/*
  ProductID ProductName
----------- --------------
          2 Santa Hat
*/

これにより、少なくとも検索文字列のすべての色を含むすべての製品が取得されます。

検索文字列からスペースを削除し、"Blue" を検索して "BabyBlue" に一致する可能性を排除するために (クエリ自体に) カンマを追加していることに注意してください。また、テーブルまたは検索文字列に重複した色や色の割り当てがないことも前提としています。

分割に UDF を使用したり、別の方法 (XML、テーブル値パラメーター) でパラメーターを渡したりするよりも、この手法が高速かどうかを確認するために、ご使用の環境でテストする必要があります。とは言っても、私は通常、区切り文字列をデータベースに格納することは避け (ここではそれらを格納していませんが、それはどこにもうまくいきません)、むしろ TVP を使用するか、アプリケーションでクエリを動的に作成します (パラメーターを使用するのではなく、パラメーターを使用します)。可能な場合は動的 SQL) (インデックスを利用する可能性があります)。

于 2013-06-14T16:44:22.143 に答える