SQL IF ELSE有2个变量和JOIN 3表

时间:2011-08-29 14:46:05

标签: sql

我是一名C#程序员,必须编写一些SQL存储过程,但我不擅长SQL。我有一个存储过程,它将根据具有两个变量的搜索条件返回SKU列表,如果用户没有选择其中一个搜索项,则变量可以为NULL。该列表将返回一个SKU行列表,其中包含搜索变量的匹配列以及链接表的名称。我已经构建了一个包含以下三个表的数据库,这应该更好地解释它:

CREATE TABLE [dbo].[SKU](
[SKU_ID] [int] IDENTITY(1,1) NOT NULL,
[CATEGORY_ID] [int] NULL,
[MANUFACTURER_ID] [int] NULL,
[SKU_NUMBER_CD] [varchar](100) NOT NULL,
[ACTIVE_IND] [bit] NOT NULL

CREATE TABLE [dbo].[CATEGORY](
[CATEGORY_ID] [int] IDENTITY(1,1) NOT NULL,
[CATEGORY_NUMBER_CD] [varchar](10) NULL,
[CATEGORY_NAME_TXT] [varchar](255) NULL,
[ACTIVE_IND] [bit] NOT NULL

CREATE TABLE [dbo].[MANUFACTURER](
[MANUFACTURER_ID] [int] IDENTITY(1,1) NOT NULL,
[MANUFACTURER_NAME_TXT] [varchar](50) NULL,
[ACTIVE_IND] [bit] NOT NULL

这是我尝试使用的存储过程。我想要做的是有4种不同的情况,因为当@CategoryID和@ManufacturerID中有一个值时,其中一个是NULL但另一个有值,当它们都是NULL时。在案例1中,我想仅返回具有匹配类别和匹配制造商的SKU,对于案例2,我想返回具有匹配类别但制造商无关紧要的SKU,依此类推。我遇到的问题是我仍然需要从制造商表中获取那些在案例2中返回的行的manufacturer_name_txt。但是我得到的每一行应该多次返回,每一行都有不同的制造商名称。< / p>

    ALTER PROCEDURE [dbo].[usp_SAL_GetSkuListFiltered]
    @CategoryID int,
    @ManufacturerID int
AS
BEGIN
    SET NOCOUNT ON;

    BEGIN
    --Get SKUs that have a matching Category and a matching Manufacturer
    IF @CategoryID IS NOT NULL AND @ManufacturerID IS NOT NULL
        SELECT k.*, c.CATEGORY_NAME_TXT, m.MANUFACTURER_NAME_TXT
        FROM SKU k, CATEGORY c, MANUFACTURER m
        WHERE k.CATEGORY_ID = @CategoryID 
            AND k.MANUFACTURER_ID = @ManufacturerID
            AND k.CATEGORY_ID = c.CATEGORY_ID
            AND k.MANUFACTURER_ID = m.MANUFACTURER_ID
            AND k.ACTIVE_IND = 1


    --Get SKUs that have a matching Category and any Manufacturer
    ELSE IF @CategoryID IS NOT NULL AND @ManufacturerID IS NULL
        SELECT k.*, c.CATEGORY_NAME_TXT, m.MANUFACTURER_NAME_TXT
        FROM SKU k, CATEGORY c, MANUFACTURER m
        WHERE k.CATEGORY_ID = @CategoryID
            AND k.CATEGORY_ID = c.CATEGORY_ID
            AND k.MANUFACTURER_ID = m.MANUFACTURER_ID
            AND k.ACTIVE_IND = 1


    --Get SKUs that have a matching Manufacturer and any Category
    ELSE IF @CategoryID IS NULL AND @ManufacturerID IS NOT NULL
        SELECT k.*, c.CATEGORY_NAME_TXT, m.MANUFACTURER_NAME_TXT
        FROM SKU k, CATEGORY c, MANUFACTURER m
        WHERE k.MANUFACTURER_ID = @ManufacturerID
            AND k.CATEGORY_ID = c.CATEGORY_ID
            AND k.MANUFACTURER_ID = m.MANUFACTURER_ID
            AND k.ACTIVE_IND = 1

    -- Get all SKUs
    ELSE
        SELECT k.*, c.CATEGORY_NAME_TXT, m.MANUFACTURER_NAME_TXT
        FROM SKU k, CATEGORY c, MANUFACTURER m
        WHERE k.CATEGORY_ID = c.CATEGORY_ID
            AND k.MANUFACTURER_ID = m.MANUFACTURER_ID
            AND k.ACTIVE_IND = 1
    END
END

以下是数据样本:

SKU_ID/CATEGORY_ID/MANUFACTURER_ID/SKU_NUMBER_CD/MANUAL_IND/ACTIVE_ID

1   1   1   BFG56789    False   True

2   1   2   YIR46578    False   True

3   1   3   WER22987    False   True

4   1   3   WXT87654    False   True

5   2   4   TYR44578    False   True

6   2   1   DRE44559    False   True

7   3   2   ZXX44455    False   True

8   4   3   BWE44590    False   True

9   4   2   HGT347474   False   True

12  NULL    NULL    12344   False   True

13  2   NULL    473489  False   True

14  3   NULL    437HHH8 False   True

15  NULL    1   YUXD678 False   True

16  NULL    3   WEW3334 False   True

作为一个例子,当我用这些变量执行存储过程时:

EXEC    @return_value = [dbo].[usp_SAL_GetSkuListFiltered]
    @CategoryID = 2,
    @ManufacturerID = NULL

我将返回两行,SKU_IDs 5和6,但不是SKU_ID 13,它在MANUFACTURER_ID字段中为NULL。但是,如果我从存储过程中删除一行,那么我有这个:

--Get SKUs that have a matching Category and any Manufacturer
ELSE IF @CategoryID IS NOT NULL AND @ManufacturerID IS NULL
    SELECT k.*, c.CATEGORY_NAME_TXT, m.MANUFACTURER_NAME_TXT
    FROM SKU k, CATEGORY c, MANUFACTURER m
    WHERE k.CATEGORY_ID = @CategoryID
        AND k.CATEGORY_ID = c.CATEGORY_ID
        AND k.ACTIVE_IND = 1

然后我返回12行 - SKU_ID 5四次,每个都有不同的制造商名称(我有4个在MANUFACTURER表中列出),然后是SKU_ID 6四次,SKU_ID 13四次。

通过浏览网站我知道使用WHERE语法可能不明确。我正在使用SQL 2005.我知道我需要使用LEFT或RIGHT JOIN,但我不理解它们。过去几天我尝试过很多不同的事情但没有结果。我只是不“得到”SQL查询。有人可以帮我弄清楚我的逻辑错在哪里吗?

2 个答案:

答案 0 :(得分:2)

你可以让整个事情像这样工作:

SELECT k.*, c.CATEGORY_NAME_TXT, m.MANUFACTURER_NAME_TXT
FROM SKU k
LEFT JOIN CATEGORY c
ON k.CATEGORY_ID = c.CATEGORY_ID
LEFT JOIN MANUFACTURER m
ON k.MANUFACTURER_ID = m.MANUFACTURER_ID
AND k.ACTIVE_IND = 1
WHERE k.CATEGORY_ID = ISNULL(@CategoryID, k.CATEGORY_ID)
AND k.MANUFACTURER_ID = ISNULL(@ManufacturerID, k.MANUFACTURER_ID)

答案 1 :(得分:0)

您使用的表示法是隐式联接,它们都是INNER JOIN。您的NULL行被遗漏了,因为条件指定了相等,而制造商左侧的ID为NULL。遗漏了一个标准后,你得到一个CROSS JOININNER JOIN TRUE),这就是为什么你会看到行的乘法。

尝试这样的事情(不需要多个IF语句):

SELECT k.*, c.CATEGORY_NAME_TXT, m.MANUFACTURER_NAME_TXT
FROM SKU k, CATEGORY c, MANUFACTURER m
WHERE (k.CATEGORY_ID = @CategoryID OR @CategoryID IS NULL)
    AND (k.MANUFACTURER_ID = @ManufacturerID OR @ManufacturerID IS NULL)
    AND (k.CATEGORY_ID = c.CATEGORY_ID OR k.CATEGORY_ID IS NULL)
    AND (k.MANUFACTURER_ID = m.MANUFACTURER_ID OR k.MANUFACTURER_ID IS NULL)
    AND k.ACTIVE_IND = 1

虽然,我建议getting away from implicit joins

我建议你看看有关SQL的更多信息,有learning questions here which recommend books

使用显式连接:

SELECT k.*, c.CATEGORY_NAME_TXT, m.MANUFACTURER_NAME_TXT
FROM SKU k
LEFT JOIN CATEGORY c -- A left join means a row in K has to exist, but c can be missing
    ON k.CATEGORY_ID = c.CATEGORY_ID
LEFT JOIN MANUFACTURER m
    ON k.MANUFACTURER_ID = m.MANUFACTURER_ID
WHERE (k.CATEGORY_ID = @CategoryID OR @CategoryID IS NULL)
    AND (k.MANUFACTURER_ID = @ManufacturerID OR @ManufacturerID IS NULL)
    AND k.ACTIVE_IND = 1

请注意,如果右侧存在多行,左连接仍然会导致类似交叉连接的乘法效果。