1

好的,所以我在产品表中有一些数据,其中包含一个类别 id 列,该列仅包含类别列表表中使用的 4 个可用字符中的 2 个。

示例:产品的类别 ID 为“AA”,但可能来自台式机 (AAA) 或服务器 (AAB) 类别。

在类别表中,我们有 3 列包含帮助我们的信息:include、atrID 和 valID。valID 列包含一个以逗号分隔的值列表(例如,“K01819”或“K00846,K00851”),这些值可能只包含一个或多个 ID。atrID 列包含一个类似的字符串(例如“A00432”)。包含列是 1 或 0,这取决于很久以前来过的程序员所做的一些工作。

基本上,他浏览了各种表,发现对于某些类别(例如 AA),我们可以从类别表中加入另一个表,并使用 atrID 和 valID 列表将其全部绑定。

例子:

产品“a”的 catID 为 AA,是台式机。这属于“AAA”类别,其中包含 0,atrI​​D 为“A00432”,valID 为“K01819”。

获取类别信息的示例 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 ININ服务器 (AAB) 的包含值为 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')

我使用INandNOT IN因为某些类别在 valID 列中有多个值。

我的问题是,如果我想在事先不知道的情况下获取特定产品的类别,这是否可能?(未能从您认为它所在的类别中获取所有产品的列表并将其匹配到一个或另一个列表中)。我一直在告诉我的老板我这几天都想不通,而且我什么也没有。任何帮助将不胜感激。

编辑:

我想要做的是获取任何产品的类别。我以上述 SQL 为例,说明了如何获取桌面和服务器类别的产品列表。

我想要反过来,即当我只有产品表中的两个字母类别时,从类别表中获取 3 个字母类别。

编辑2:

产品表列:
prodID varchar(40)
catID char(2)

示例行:
“S101010”、“AA”(桌面)
“S202020”、“AA”(服务器)
“S303030”、“ED”(激光打印机)
“S404040”、“ED”(喷墨打印机)

类别表列:
catID varchar(4)
description varchar(50)
include bit(实际上是一个 tinyint,应该显示我每天处理的内容 =P)
atrID varchar(6)
valID varchar(250)

示例行:
'AAA'、'Desktops'、0、'A00432'、'K01819'、
'AAB'、'Servers'、1、'A00432'、'K01819'、
'EDA'、'Laser Printers'、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 的结果,看看哪个不是空的,那将是我的类别,但我无法弄清楚连接。如果它甚至是可能的。而且它没有考虑具有两个以上变体的类别。

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

我首先会说您的数据模型非常糟糕。您不应该有一个逗号列表,您需要在其中进行拆分和匹配。应该是表关系。但我离题了...

因此,如果唯一的区别是您是否使用INvsNOT IN基于的值,include那么如果我将其完全写在服务器上,我会这样做:

首先,为自己准备一个不错的 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))

很难确保我上面的语法是准确的,因为我没有完整的工作模型。但总体思路是:您的 UDFinline_split_me将记录拆分为一个“表”,然后您可以加入该表。通过使用 LEFT JOIN,如果表之间不匹配atr,则 ism.Value 将为空。这可以用来做NOT IN。反过来,IN模拟也是如此。

编辑 1:根据您的反馈,这是我想出的测试平台。我没有完整的数据视图,但我认为这就是您正在寻找的(或至少接近)。评论,我会调整。

鉴于您的示例数据,我在我的 tempdb 中运行了它。由于我没有 EDB 的属性记录,因此我无法确定我是否要取回我应该取回的东西。我还取回了两条记录 S303030,一条用于 Attribute 表中的每个 valID。如果您只想在 ProdID + Category.CatID 中寻找唯一性,或者如果有一块我不明白的难题,请告诉我,我会调整我的答案,您可以使用 DISTINCT 只取回一个。这适用于除 Ink Jets 之外的所有内容,因为您的示例数据在 #Category 表中没有喷墨记录。如果我用 say 伪造一个,UNION SELECT 'S404040', 'ED', 'A00172', 'K00845'那么它似乎有效。

--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 回答