1

わかりましたので、カテゴリ リスト テーブルで使用される 4 つの使用可能な文字のうち 2 つだけを含むカテゴリ ID 列を含む製品テーブルにいくつかのデータがあります。

例: 製品のカテゴリ ID は「AA」ですが、デスクトップ (AAA) またはサーバー (AAB) カテゴリの製品である可能性があります。

カテゴリ テーブルには、役立つ情報を含む 3 つの列があります: include、atrID、および valID。valID 列には、コンマで区切られた値のリスト (「K01819」または「K00846,K00851」など) が含まれ、1 つ以上の ID のみを含む場合があります。atrID 列には、同様の文字列が含まれています (たとえば、'A00432')。include 列は、かなり前に行ったり来たりしたプログラマーによって行われた作業に基づいて、1 または 0 のいずれかです。

基本的に、彼はさまざまなテーブルを調べて、特定のカテゴリ (AA など) について、カテゴリ テーブルから別のテーブルを結合し、atrID と valID のリストを使用してすべてを結び付けることができることを発見しました。

例:

製品「a」の catID は AA で、デスクトップ マシンです。これは、include が 0、atrID が 'A00432'、valID が 'K01819' のカテゴリ 'AAA' に属します。

カテゴリ情報を取得するための SQL の例:

SELECT cat.atrID, cat.valID, cat.[include]
FROM db.dbo.cat AS cat
WHERE cat.catID = 'AAA'

次に、これらの変数を .Net コードに保存し、include の値に応じて SQL を構築します。また、valID を分割し、これを個々のパラメーターとして渡し、SQL サーバーで次のコードが実行されるようにします。

SELECT DISTINCT prod.prodID
FROM db.dbo.prod AS prod
INNER JOIN db.dbo.atr AS atr ON atr.prodID = prod.prodID
WHERE prod.catID = 'AA'
AND atr.atrID = 'A00432'
AND atr.valID NOT IN('K01819')

サーバーでこれを変更するNOT INにはIN、サーバー (AAB) の include 値が 1 であるため、 を に変更します。例:

SELECT DISTINCT prod.prodID
FROM db.dbo.prod AS prod
INNER JOIN db.dbo.atr AS atr ON atr.prodID = prod.prodID
WHERE prod.catID = 'AA'
AND atr.atrID = 'A00432'
AND atr.valID IN('K01819')

一部のカテゴリでは、valID 列に複数の値が含まれているため、INandを使用します。NOT IN

私の質問は、事前に知らずに特定の製品のカテゴリを取得したい場合、それは可能ですか? (あると思われるカテゴリからすべての製品のリストを取得できず、いずれかのリストで一致する)。私は上司に何日もそれを理解できないと言っていて、どこにも行きません. どんな助けでも大歓迎です。

編集:

私がやろうとしているのは、任意の製品のカテゴリを取得することです。上記の SQL は、デスクトップ カテゴリとサーバー カテゴリの製品リストを取得する方法の例として含めました。

逆に、つまり、製品テーブルから 2 文字のカテゴリしかないときに、カテゴリ テーブルから 3 文字のカテゴリを取得したい。

編集2:

商品テーブルの列:
prodID varchar(40)
catID char(2)

サンプル行:
'S101010'、'AA' (デスクトップ)
'S202020'、'AA' (サーバー)
'S303030'、'ED' (レーザー プリンター)
'S404040'、'ED' (インクジェット プリンター)

カテゴリ テーブルの列:
catID varchar(4)
説明 varchar(50)
インクルード ビット (実際には、私が毎日何を扱っているかを示す tinyint =P)
atrID varchar(6)
valID varchar(250)

サンプル行:
「AAA」、「デスクトップ」、0、「A00432」、「K01819」、
「AAB」、「サーバー」、1、「A00432」、「K01819」、
「EDA」、「レーザープリンター」、1、「A00172」 ', 'K00846,K00851'
'EDB', 'インクジェットプリンター', 1, 'A00172', 'K00845'

属性テーブルの列:
prodID varchar(40)
catID char(2)
atrID varchar(10)
valID varchar(10)

サンプル行:
「S101010」、「AA」、「A00432」、「K01817」、「
S202020」、「AA」、「A00432」、「K01819」、「
S303030」、「ED」、「A00172」、「K00846」、「S303030
」 '、'ED'、'A00172'、'K00851'、'
S404040'、'ED'、'A00172'、'K00845'

上記に含めたのは、category.catID を知っている場合に製品のリストを取得する方法です。私が欲しいのは、product.prodID と product.catID しかないときにカテゴリを取得できるようにすることです。

私はこのようなものを求めていますが、不完全であり、そのままでは機能しません。次に、catIn.catID と catNotIn.catID の結果をチェックして、どちらが null ではないかを確認します。それが私のカテゴリになりますが、結合がわかりません。それさえ可能なら。また、3 つ以上のバリアントを持つカテゴリは考慮されません。

SELECT prod.prodID, catIn.catID, catNotIn.catID
FROM product AS prod
INNER JOIN attributes AS atr ON atr.prodID = prod.prodID
LEFT OUTER JOIN category AS catIn ON LEFT(catIn.catID, 2) = prod.catID AND catIn.atrID = atr.atrID --more conditions needed here
LEFT OUTER JOIN category AS catNotIn ON LEFT(catNotIn.catID, 2) = prod.catID AND catIn.atrID = atr.atrID --more conditions needed here

これが私が何を求めているのかをもう少しよく説明してくれることを願っています。

4

1 に答える 1

0

あなたのデータモデルはかなり悪いと言って始めましょう。分割して照合する必要がある値のコンマリストは使用しないでください。テーブル関係である必要があります。しかし、私は脱線します...

したがって、唯一の違いがの値に基づいてINvsを使用するかどうかである場合、これを完全にサーバーに書き込むとしたら、次のようにします。NOT INinclude

まず、適切な CSV 分割 UDF を取得します。 単一のステートメントでCSVデータを分割して新しいテーブルに挿入する方法は? これは良い例です。素晴らしくシンプルです。

次に、クエリ (ストアド プロシージャに変換します) は次のようになります。

CREATE PROCEDURE SprocNameHere
@prodID INT
AS

-- I'm making assumptions about the data types here.  Fix them accordingly
DECLARE @atrID INT
DECLARE @valID varchar(MAX)
DECLARE @include BIT
DECLARE @catID varchar(50)

-- given the passed in product ID, look up @catID
SELECT @catID = catID FROM prod WHERE prodID = @prodID

SELECT @atrID = cat.atrID, @valID = cat.valID, @include = cat.[include]
FROM db.dbo.cat AS cat
WHERE cat.catID = @catID


SELECT DISTINCT prod.prodID
FROM db.dbo.prod AS prod
INNER JOIN db.dbo.atr AS atr ON atr.prodID = prod.prodID
LEFT JOIN dbo.inline_split_me(',', @valID) ism ON ism.Value = atr.valID
WHERE prod.catID = 'AA' -- is this hardcoded or should this come from the query above??  How do you convertt 'AAA' to 'AA'?  What Table/relationship/concept does this?
AND atr.atrID = @atrID
AND ((@include = 0 AND ism.Value IS NULL) OR (@include = 1 AND ism.Value IS NOT NULL))

完全に機能するモデルがないため、上記の構文が正確であることを確認するのは非常に困難です。ただし、一般的な考え方は次のとおりですinline_split_me。UDF はレコードを「テーブル」に分割し、それに対して結合することができます。LEFT JOIN を使用すると、atrテーブル間に一致がない場合、ism.Value は null になります。これは、 を行うために使用できますNOT IN。その逆は、INシミュレーションにも当てはまります。

EDIT 1: あなたのフィードバックに基づいて、これが私が思いついたテスト ベッドです。私はデータの完全なビューを持っていませんが、これはあなたが探しているものだと思います (または少なくとも近づいています)。コメントいただければ調整します。

サンプル データを使用して、これを tempdb で実行しました。私は EDB の属性レコードを持っていなかったので、返すべきものを返しているかどうか確信が持てません。また、属性テーブルの valID ごとに 1 つずつ、2 つのレコード S303030 が返されます。ProdID + Category.CatID 全体で一意性のみを探している場合、または理解できないパズルのピースがある場合は、DISTINCT を使用して 1 つだけを取得できます。答えを微調整します。これは、サンプル データの #Category テーブルにインクジェット レコードがないため、Ink Jets 以外のすべてで機能します。私が言うUNION SELECT 'S404040', 'ED', 'A00172', 'K00845'ことで1つを偽造すると、うまくいくようです。

--DROP TABLE #Product
--DROP TABLE #Category
--DROP TABLE #Attribute

--DROP FUNCTION inline_split_me

GO
CREATE FUNCTION inline_split_me (@SplitOn char(1),@String nvarchar(max))
RETURNS @results TABLE(Part NVARCHAR(MAX))
AS
BEGIN

    IF (CHARINDEX(@SplitOn,@String)-1<= 0)
        INSERT INTO @results
        SELECT @string AS Part
    ELSE
        WITH SplitSting AS
            (
            SELECT
                LEFT(@String,CHARINDEX(@SplitOn,@String)-1) AS Part
                    , CASE WHEN LEN(@String)-CHARINDEX(@SplitOn,@String) > 0 THEN RIGHT(@String,LEN(@String)-CHARINDEX(@SplitOn,@String)) ELSE NULL END AS Remainder
                WHERE @String IS NOT NULL AND CHARINDEX(@SplitOn,@String)-1>0
            UNION ALL
            SELECT
                LEFT(Remainder,CHARINDEX(@SplitOn,Remainder)-1)
                    ,RIGHT(Remainder,LEN(Remainder)-CHARINDEX(@SplitOn,Remainder))
                FROM SplitSting
                WHERE Remainder IS NOT NULL AND CHARINDEX(@SplitOn,Remainder)-1>0
            UNION ALL
            SELECT
                Remainder,null
                FROM SplitSting
                WHERE Remainder IS NOT NULL AND CHARINDEX(@SplitOn,Remainder)=0
            )
            INSERT INTO @results
            SELECT Part FROM SplitSting

RETURN
END

GO


CREATE TABLE #Product
(
    prodID varchar(40)
    , catID char(2)
)

CREATE TABLE #Category
(
    catID varchar(4)
    , description varchar(50)
    , include bit --(actually a tinyint which should go to show what I deal with on a daily basis =P)
    , atrID varchar(6)
    , valID varchar(250)
)

CREATE TABLE #Attribute
(
    prodID varchar(40)
    , catID char(2)
    , atrID varchar(10)
    , valID varchar(10)
)

INSERT INTO #Product
SELECT 'S101010', 'AA'
UNION SELECT 'S202020', 'AA'
UNION SELECT 'S303030', 'ED'
UNION SELECT 'S404040', 'ED'

INSERT INTO #Category
SELECT 'AAA', 'Desktops', 0, 'A00432', 'K01819'
UNION SELECT 'AAB', 'Servers', 1, 'A00432', 'K01819'
UNION SELECT 'EDA', 'Laser Printers', 1, 'A00172', 'K00846,K00851'
UNION SELECT 'EDB', 'Inkjet Printers', 1, 'A00172', 'K00845'

INSERT INTO #Attribute
SELECT 'S101010', 'AA', 'A00432', 'K01817'
UNION SELECT 'S202020', 'AA', 'A00432', 'K01819'
UNION SELECT 'S303030', 'ED', 'A00172', 'K00846'
UNION SELECT 'S303030', 'ED', 'A00172', 'K00851'

-- make sure it works with just one parameter
SELECT * FROM dbo.inline_split_me(',', 'K00846')

-- so you can see the split
SELECT * FROM dbo.inline_split_me(',', 'K00846,K00851')

-- so you can see the split in reference to the category
SELECT c.*, Part
FROM #Category c
OUTER  APPLY dbo.inline_split_me(',', c.valID) split

SELECT p.*, a.*, c.*
FROM #Product p
INNER JOIN #Attribute a ON a.prodID = p.prodID AND a.catID = p.catID
INNER JOIN #Category c ON c.atrID = a.atrID
    AND (
            (c.include = 0 AND a.valID NOT IN (SELECT Part FROM dbo.inline_split_me(',', c.valID)))
            OR (c.include = 1 AND a.valID IN (SELECT Part FROM dbo.inline_split_me(',', c.valID)))
        )
ORDER BY a.ProdID, a.atrID--, c.catID

DROP TABLE #Product
DROP TABLE #Category
DROP TABLE #Attribute

DROP FUNCTION inline_split_me
于 2012-11-09T15:39:27.570 に答える