我有一个存储过程需要不同的if条件才能正常工作。
该过程有2个参数,即@CategoryID和@ClassID,它们基本上来自UI树视图功能。 @CategoryID对应于父节点,而@ClassID对应于子节点。
基于以上参数,我需要从具有CategoryID和ClassID作为列的表中进行选择(列代码)。
现在有两种情况:
情景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
最后一个部分实际上是一个'OR',它给了我CategoryID和ClassID的代码的联合,不管给定的ClassID是否是给定CategoryID的子代。
我在这里的问题是,如何编写实现这两种情况的条件。
最新样本数据:
情景1
@ CategoryId = 2,5,@ ClassID = 10(这里10是孩子,2是父,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
我想我的问题非常明确,如果不是,那么人们可以让我编辑它。我很乐意这样做。我敦促专家帮我解决这个问题。任何指针也将非常感激。
此致
阿努拉格
答案 0 :(得分: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是孩子,2是父,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
答案 1 :(得分: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
答案 2 :(得分: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)
答案 3 :(得分:0)
删除字符串更新
如果您有逗号分隔的字符串,那么最好使用CLR函数来创建表,但您可以使用SQL函数。使用Google搜索很容易找到如何执行此操作的示例...但是这里有一篇关于此主题的好文章 - > http://www.sqlperformance.com/2012/07/t-sql-queries/split-strings我希望在某些时候在大多数平台上都会有原生支持。
假设您有一个函数返回一个类型为int的列(名为ID)的表,或者在空输入上返回一个空表。注意:您可能必须让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
逻辑与以下相同。因为如果值不为null,则连接将改变值,我们必须使用不同的技巧。这里我们使用标记值(在本例中为-1)来表示空值。任何不会出现在逗号分隔列表中的值都将作为此标记值使用,请记住它必须属于同一类型。
这里不需要动态SQL,如果不使用动态SQL,你会发现SQL服务器更擅长优化。实际上,您甚至不需要if语句如果您可以确定输入始终为null,则可以执行以下操作:
SELECT Code
FROM ClassToCategoryMapping
WHERE
如何运作
此查询检查CategoryID和ClassID列是否与传入参数匹配,但是当它们为null时通过检查列自身来“忽略”输入。这是一个方便的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()
......在这种情况下,他们会做同样的事情。