在 Microsoft SQL Server 的 CASE 中使用别名 - 存储过程

问题描述 投票:0回答:2

我有 SQL Server 存储过程:

Select 
    A.Id, A.Title, A.BriefText, 
    I.ArticleView, U.DisplayName AS Author, 
    U.Avatar,
    (SELECT COUNT(*) FROM Articles_Like WHERE ArticleId = A.Id) AS Likes,
    (SELECT COUNT(*) FROM Articles_Comment WHERE ArticleId = A.Id) AS Comments,
    CASE 
        WHEN EXISTS (SELECT Id FROM Articles_Like 
                     WHERE ArticleId = A.Id AND UserId = @UserId) 
            THEN 1 
            ELSE 0 
    END AS IsLiked,
    CASE 
        WHEN EXISTS (SELECT Id FROM Articles_Bookmark 
                     WHERE ArticleId = A.Id AND UserId = @UserId)
            THEN 1 
            ELSE 0 
    END AS IsBookmarked
FROM 
    Articles A
LEFT OUTER JOIN 
    Articles_Info I ON I.ArticleId = A.Id 
LEFT OUTER JOIN 
    Users_Info U ON U.UserId = A.UserId
GROUP BY 
    A.Title, A.BriefText, A.Id, I.ArticleView, 
    U.DisplayName, U.Avatar, U.UserId 
ORDER BY 
    CASE WHEN @orderby = 1 THEN A.Id END DESC,
    CASE WHEN @orderby = 2 THEN I.ArticleView END DESC,
    END DESC
    CASE WHEN @orderby = 3 THEN Likes END DESC

最后一行

 CASE WHEN @orderby = 3 THEN Likes END DESC

我收到错误:

列名无效

当我使用

CASE
别名时不再起作用,我该如何解决这个问题?

我可以使用:

CASE WHEN @orderby = 3 THEN (SELECT COUNT(*) FROM Articles_Like WHERE ArticleId = A.Id) END DESC

像这样:

Select A.Id, A.Title,  A.BriefText, I.ArticleView, U.DisplayName AS Author, U.Avatar,
    (SELECT COUNT(*) FROM Articles_Like WHERE ArticleId=A.Id) AS Likes,
    (SELECT COUNT(*) FROM Articles_Comment WHERE ArticleId=A.Id) AS Comments,
    CASE WHEN EXISTS (SELECT Id FROM Articles_Like WHERE ArticleId=A.Id AND UserId=@UserId) 
         THEN 1 ELSE 0 END AS IsLiked,
    CASE WHEN EXISTS (SELECT Id FROM Articles_Bookmark WHERE ArticleId=A.Id AND UserId=@UserId)
         THEN 1 ELSE 0 END AS IsBookmarked
FROM Articles A
LEFT OUTER JOIN Articles_Info I ON I.ArticleId = A.Id 
LEFT OUTER JOIN Users_Info U ON U.UserId = A.UserId
GROUP BY A.Title, A.BriefText, A.Id, I.ArticleView, U.DisplayName, U.Avatar, U.UserId 
ORDER BY 
    CASE WHEN @orderby=1 THEN A.Id END DESC,
    CASE WHEN @orderby=2 THEN I.ArticleView END DESC,
    CASE WHEN @orderby=3 THEN (SELECT COUNT(*) FROM Articles_Like WHERE ArticleId=A.Id) END DESC

它有效,但我在存储过程的顶部使用了这段代码,这不是两次使用代码的正确方法。

我正在使用 SQL Server 2022

sql sql-server stored-procedures alias
2个回答
4
投票

我在存储过程的顶部使用了此代码,这不是使用代码两次的正确方法

对于过程语言来说确实如此,但不幸的是对于 SQL 来说,为了获得最佳结果,有时您确实需要重复复杂的表达式。一般来说,查询引擎足够聪明,不会重复工作,只会执行一次表达式。

同样,由于 SQL 足够智能,不会重复工作,因此您可能会重新考虑如何定义

IsLiked
列,因此它会重新使用相同的表达式,并在结果 > 0 时返回正确的值。


3
投票

来自 sql server 文档


如果 ORDER BY 子句引用选择列表中的列别名,则该列别名必须单独使用,而不能作为 ORDER BY 子句中某些表达式的一部分,例如:

Copy
SELECT SCHEMA_NAME(schema_id) AS SchemaName
FROM sys.objects
ORDER BY SchemaName; -- correct

SELECT SCHEMA_NAME(schema_id) AS SchemaName
FROM sys.objects
ORDER BY SchemaName + ''; -- wrong

您可以在以下工作/非工作示例中看到您遇到的相同情况:

CREATE TABLE test (id int, f1 varchar(20));
INSERT INTO test VALUES (1, 'foo');
INSERT INTO test VALUES (2, 'bar');

/*runs fine*/
SELECT id, (SELECT count(*) FROM test) as total_count
FROM test
ORDER BY total_count

/*errors*/
SELECT id, (SELECT count(*) FROM test) as total_count
FROM test
ORDER BY CASE WHEN 1=1 THEN total_count END

dbfiddle here 正在执行此操作。


为了避免代码重复,请考虑将不带 ORDER BY 的查询放入子查询中,然后在主查询中排序:

SELECT * 
FROM 
  (
    Select A.Id, A.Title,  A.BriefText, I.ArticleView, U.DisplayName AS Author, U.Avatar,
        (SELECT COUNT(*) FROM Articles_Like WHERE ArticleId=A.Id) AS Likes,
        (SELECT COUNT(*) FROM Articles_Comment WHERE ArticleId=A.Id) AS Comments,
        CASE WHEN EXISTS (SELECT Id FROM Articles_Like WHERE ArticleId=A.Id AND UserId=@UserId) 
             THEN 1 ELSE 0 END AS IsLiked,
        CASE WHEN EXISTS (SELECT Id FROM Articles_Bookmark WHERE ArticleId=A.Id AND UserId=@UserId)
             THEN 1 ELSE 0 END AS IsBookmarked
    FROM Articles A
    LEFT OUTER JOIN Articles_Info I ON I.ArticleId = A.Id 
    LEFT OUTER JOIN Users_Info U ON U.UserId = A.UserId
    GROUP BY A.Title, A.BriefText, A.Id, I.ArticleView, U.DisplayName, U.Avatar, U.UserId 
  ) dt
ORDER BY 
        CASE WHEN @orderby=1 THEN Id END DESC,
        CASE WHEN @orderby=2 THEN ArticleView END DESC,
        CASE WHEN @orderby=3 THEN Likes END DESC
© www.soinside.com 2019 - 2024. All rights reserved.