0

我有一个存储过程,它需要不同的 if 条件才能正常工作。

该过程有两个参数,即@CategoryID 和@ClassID,它们基本上来自UI 树视图功能。@CategoryID 对应父节点,@ClassID 对应子节点。

基于上述参数,我需要从具有 CategoryID 和 ClassID 作为列的表中进行选择(列代码)。

现在有2个场景:

方案 1

@CategoryID:A

@ClassID:B(CategoryID A 的子节点)

需要的结果:只对应ClassID B的代码,基本上就是交集

方案 2

@CategoryID:A

@ClassID: C(不是 CategoryID A 的子节点)

需要的结果:CategoryID A 和 ClassID B 对应的代码,基本上是一个并集

我编写的程序为我提供了第二种情况的正确答案,但第一种情况它失败了。以下是我的程序:

ALTER PROCEDURE [dbo].[uspGetCodes]
@CategoryID varchar(50),
@ClassID varchar(50)
AS
BEGIN
BEGIN TRY
DECLARE @SQLQuery NVARCHAR(MAX)

SET @SQLQuery=N'SELECT Code FROM dbo.ClassToCategoryMapping WHERE '
IF (@CategoryID IS NULL OR @CategoryID='')
    BEGIN
    SET @SQLQuery=@SQLQuery + 'ClassId IN ('+@ClassID+')'
    PRINT(@SQLQuery)
    EXEC(@SQLQuery)
    END

ELSE IF (@ClassID IS NULL OR @ClassID='')
    BEGIN
    SET @SQLQuery=@SQLQuery+'CategoryID IN ('+@CategoryID+')'
    PRINT(@SQLQuery)
    EXEC(@SQLQuery)
    END

ELSE 
    BEGIN
    SET @SQLQuery=@SQLQuery+'(CategoryID IN ('+@CategoryID+') OR ClassId IN ('+@ClassID+') )'
    PRINT(@SQLQuery)
    EXEC(@SQLQuery)
    END
END TRY

BEGIN CATCH
SELECT ERROR_NUMBER() AS 'ErrorNumber', ERROR_MESSAGE() AS 'ErrorMessage', ERROR_SEVERITY() AS 'ErrorSeverity', ERROR_STATE() AS 'ErrorState', ERROR_LINE() AS 'ErrorLine'
RETURN ERROR_NUMBER()
END CATCH

END

Last Else 部分实际上做了一个“或”,它为我提供了 CategoryID 和 ClassID 的代码的联合,而不管给定的 ClassID 是否是给定 CategoryID 的子代。

我在这里的问题是,如何编写条件来实现这两种情况。

最新样本数据:

方案 1

@CategoryId=2,5, @ClassID=10 (这里10是child,2是parent,CategoryID 2对应ClassID的10,11,12)

预期结果:10、26、27(26 和 27 对应 CategoryID 5)

方案 2

@CategoryID=2, @ClassID=13,15(13和15是不同父级的子级,CategoryID 2对应ClassID的10, 11 ,12)

预期结果:10、11、12、13、15

表 dbo.ClasstoCategoryMapping 中的数据将如下所示:

CategoryID  ClassID  Code
2           10       200
2           11       201
2           12       202
5           26       501
5           27       502
6           15       601
6           16       602
6           17       603
7           20       701
7           21       702
7           22       703

我想我已经把我的问题说得很清楚了,如果没有,人们可以要求我编辑它。我很乐意这样做。我敦促专家帮助我解决这个问题。任何指针也将不胜感激。

问候

阿努拉格

4

4 回答 4

1

这是可以实现您的目标的示例查询,这是您想要的吗?

DECLARE @SAMPLE TABLE
(
ID INT IDENTITY(1,1),
CategoryId INT,
ClassID INT
)

INSERT INTO @sample
VALUES(2,10)
INSERT INTO @sample
VALUES(2,11)
INSERT INTO @sample
VALUES(2,12)
INSERT INTO @sample
VALUES(3,13)

DECLARE @CategoryID INT
DECLARE @ClassID Int

--在此处播放您的参数

SET @CategoryID = 2
SET @ClassID = 13

--Snenario 1

--@CategoryId=2, @ClassID=10(这里10是child,2是parent,CategoryID 2对应ClassID的10,11,12)

--预期结果:10

IF EXISTS(SELECT * FROM @SAMPLE WHERE CategoryId = @CategoryID AND ClassID = @ClassID)
SELECT ClassID FROM @SAMPLE WHERE CategoryId = @CategoryID AND ClassID = @ClassID

--场景2

--@CategoryID=2,@ClassID=13(13是不同父级的子级,CategoryID 2对应ClassID的10, 11 ,12)

--预期结果:10、11、12、13

ELSE

SELECT ClassID FROM @SAMPLE WHERE ClassID = @ClassID OR CategoryId = @CategoryID
于 2013-10-04T06:24:35.210 回答
1

如果我正确理解了这个问题,那么您在结果集中需要的是:

(所有提供的 classid) + (所有提供的 categoryid 的 classid,没有匹配的提供的 classid)

这将转化为以下内容:

CREATE PROCEDURE [dbo].[uspGetCodes]
(
    @CategoryID varchar(50),
    @ClassID varchar(50)
)
AS
BEGIN
    SELECT  COALESCE(CM.CategoryID, CM2.CategoryID) AS CategoryID, 
            COALESCE(CM.ClassID, CM2.ClassID) AS ClassID, 
            COALESCE(CM.Code, CM2.Code) AS Code
    --Matched classIDs: 
    FROM    dbo.udfSplitCommaSeparatedIntList(@ClassID) CLAS
    JOIN    dbo.ClassToCategoryMapping CM
            ON  CM.ClassId = CLAS.Value
    --Unmatched CategoryIDs:
    FULL
    OUTER
    JOIN    dbo.udfSplitCommaSeparatedIntList(@CategoryID) CAT
            ON  CM.CategoryID = CAT.Value
    LEFT
    JOIN    dbo.ClassToCategoryMapping CM2
            ON  CM.CategoryID IS NULL
            AND CM2.CategoryID = CAT.Value
END

我在结果中包含了类别、类和代码,因为它更容易看到发生了什么,但是我猜你只需要代码

这利用以下函数来拆分提供的逗号分隔字符串:

CREATE FUNCTION [dbo].[udfSplitCommaSeparatedIntList]
(
    @Values varchar(50)
)
RETURNS @Result TABLE
(
    Value int
)
AS
BEGIN
    DECLARE @LengthValues int
    SELECT @LengthValues = COALESCE(LEN(@Values), 0)

    IF (@LengthValues = 0)
        RETURN

    DECLARE @StartIndex int
    SELECT @StartIndex = 1

    DECLARE @CommaIndex int
    SELECT @CommaIndex = CHARINDEX(',', @Values, @StartIndex)
    DECLARE @Value varchar(50);

    WHILE (@CommaIndex > 0)
    BEGIN
        SELECT @Value = SUBSTRING(@Values, @StartIndex, @CommaIndex - @StartIndex)
        INSERT @Result VALUES (@Value)

        SELECT @StartIndex = @CommaIndex + 1
        SELECT @CommaIndex = CHARINDEX(',', @Values, @StartIndex)
    END

    SELECT @Value = SUBSTRING(@Values, @StartIndex, LEN(@Values) - @StartIndex + 1)
    INSERT @Result VALUES (@Value)

    RETURN
END
于 2013-10-06T11:01:57.163 回答
0

分隔字符串的更新

如果你有一个逗号分隔的字符串,那么最好使用 CLR 函数来创建表,但你可以使用 SQL 函数。如何做到这一点的例子很容易通过谷歌搜索找到......但这里有一篇关于这个主题的好文章供参考-> http://www.sqlperformance.com/2012/07/t-sql-queries/我希望 在某些时候在大多数平台上都会有本机支持。

假设您有一个函数返回 int 类型的一列(名为 ID)的表,或者在 null 输入上返回一个空表。注意:您可能必须让 null 返回一个表,其中一行包含无效值(一个永远不会连接的值),例如 -1。

代码很简单:

SELECT Code
FROM ClassToCategoryMapping
LEFT JOIN MakeTableFromCVS(@CategoryID) AS CatTable 
       ON CatTable.ID = CategoryID
LEFT JOIN MakeTableFromCVS(@ClassID) AS ClassTable 
       ON ClassTable.ID = ClassID
WHERE 
   CASE 
     WHEN @CatgoryID IS NULL THEN -1 ELSE CatTable.ID 
   END = ISNULL(CatTable.ID,-1) 
AND
   CASE
     WHEN @ClassID IS NULL THEN -1 ELSE ClassTable.ID
   END = ISNULL(ClassTable.ID,-1) 
AND
   COALESCE(CatTable.ID,ClassTable.ID,-1) != -1

逻辑与下面相同。因为如果连接不为空,连接将改变值,我们必须使用不同的技巧。这里我们使用一个标记值(在本例中为 -1)来表示空值。任何不会出现在逗号分隔列表中的值都将用作此标记值,记住它必须是相同的类型。


您在这里不需要动态 SQL,如果您不使用动态 SQL,您会发现 SQL Server 更擅长优化。实际上,您甚至不需要 if 语句 如果您可以确定输入始终为空,您可以这样做:

SELECT Code
FROM ClassToCategoryMapping
WHERE 

这是如何工作的

此查询检查 CategoryID 和 ClassID 列是否与传入参数匹配,但在它们为空时通过检查列自身来“忽略”输入。这是一个方便的 SQL 技巧。

请注意,如果您确实需要检查空字符串,那么这将几乎一样快

DECLARE @myCatID varchar(max)
DECLARE @myClassID varchar(max)

SET @myCatID = @CategoryID
SET @myClassID = @ClassID

IF LTRIM(RTRIM(@CategoryID) = '' THEN SET @myCatID = NULL
IF LTRIM(RTRIM(@ClassID) = '' THEN SET @myClassID = NULL

SELECT Code
FROM ClassToCategoryMapping
WHERE CatgoryID = ISNULL(@myCatID,CategoryID) 
  AND ClassID = ISNULL(@myClassID,ClassID)

如果你愿意,你可以替换ISNULL()COALESCE()......在这种情况下他们会做同样的事情。

于 2013-10-06T07:10:55.077 回答
0

尝试这个

select * from yourtable 
where CategoryId = @CategoryID and ClassID = @ClassID
union
select * from 
(
    select * from yourtable where ClassID = @ClassID 
    union
    select * from yourtable where CategoryId = @CategoryID
) v
where not exists (select * from yourtable where CategoryId = @CategoryID and ClassID = @ClassID)
于 2013-10-04T07:29:45.380 回答