2011-08-29 53 views
0

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

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,依此类推。我遇到的问题是我仍然需要从制造商表中为制造商表中的制造商名称__txt获取在情况2中返回的那些行。但是我得到应该多次返回的每一行,每行都在该列中具有不同的制造商名称。

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_ID 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) ,然后是SKU_ID 6四次,SKU_ID 13四次。

我从环顾网站了解到,使用WHERE语法可能不明确。我正在使用SQL 2005.我知道我需要使用LEFT或RIGHT JOIN,但我不理解它们。过去几天我尝试了许多不同的东西,但没有结果。我只是不“获取”SQL查询。有人能帮我弄清楚我的逻辑错误吗?

回答

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 

注意,左连接仍然会导致交叉联接般的倍增效应,如果右边存在多个行。

+0

感谢您的快速响应。我尝试了一下这段代码,当我尝试用CategoryID = 2和ManufacturerID = NULL执行它时,我找回了两个SKU类别和制造商ID中的值,但我获得了4行返回SKU制造商ID列中的NULL。也许我的想法存在缺陷?理想情况下,我想返回三行,第三个SKU在MANUFACTURER_NAME_TXT列中有NULL值......感谢您的链接,我将不得不查看这些SQL书籍。 –

+0

@ Bill Tanner我想这是隐式连接的东西 - 我可能没有直接思考 - 我会发布一个带有显式连接的版本。 –

+0

哦,这太棒了,谢谢! LEFT JOIN的作用与我所想的相反,我将不得不研究这一点。再次感谢您的帮助。 –

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) 
+0

感谢您的快速回复。当我尝试这些代码时,我只会得到SKU返回,它们在CATEGORY_ID和MANUFACTURER_ID都有值。如果其中一列有NULL,则该行不会返回。我认为这是因为最后两行在比较两个表时不允许使用NULL值? –