ORDER BY和CASE

时间:2015-05-20 03:47:38

标签: sql-server sql-order-by case

我在SQL中有以下脚本:

ALTER PROC [dbo].[getRequests]
@SortBy             VARCHAR(50) = 'Date'
AS
SELECT  [ReqDate], [RequestorOrg], [RequestCategory],
        [ReqDescription], [OrgCountVote]
ORDER BY 
        CASE WHEN @SortBy = 'Date (oldest first)'   THEN [ReqDate]          END ASC, [OrgCountVote] DESC,
        CASE WHEN @SortBy = 'Date (newest first)'   THEN [ReqDate]          END DESC, [OrgCountVote] ,
        CASE WHEN @SortBy = 'Number of Votes'       THEN [OrgCountVote]     END DESC, reqdate,
        CASE WHEN @SortBy = 'Organisation'          THEN [RequestorOrg]     END,
        CASE WHEN @SortBy = 'Category'              THEN [RequestCategory]  END;

ORDER BY中的前两个案例有多个要排序的列。

当我尝试保存脚本时,它会给我以下消息:

  

Msg 169,Level 15,State 1,Procedure getRequests,Line 8
  已按列表顺序多次指定列。按列表排列的列必须是唯一的。

如何确保列是唯一的?

5 个答案:

答案 0 :(得分:4)

我建议你使用这种类型的存储过程:

ALTER PROC [dbo].[getRequests]
@SortBy             VARCHAR(50) = 'Date'
AS
BEGIN
DECLARE @sql varchar(max) 

SET @sql = 'SELECT  [ReqDate], [RequestorOrg], [RequestCategory], [ReqDescription], [OrgCountVote] ' +
           'ORDER BY ' +
                CASE @SortBy
                    WHEN 'Date (oldest first)' THEN '[ReqDate] ASC, [OrgCountVote] DESC'
                    WHEN 'Date (newest first)' THEN '[ReqDate] DESC, [OrgCountVote] '
                    WHEN 'Number of Votes'     THEN '[OrgCountVote] DESC, reqdate'
                    WHEN 'Organisation'        THEN '[RequestorOrg]'
                    WHEN 'Category'            THEN '[RequestCategory]'
                END
EXEC(@sql)
END

答案 1 :(得分:1)

问题是OrgCountVote字段。 CASE语句中包含的字段很好......至少,它在我的测试系统(Sql Server 2008 R2)上运行良好。即便如此,我建议为每个案例条件添加一个默认的ELSE子句,你也应该知道这可能导致一些非常糟糕的查询计划(性能不佳)。对于这种情况,您可以在客户端代码中获得更多更好的性能。

那就是说,你可以像这样完成你需要的东西:

ORDER BY
  --first level
    CASE WHEN @SortBy = 'Date (oldest first)' THEN [ReqDate]
         WHEN @SortBy = 'Date (newest first)' THEN CAST(CAST([ReqDate]-'1970-01-01' AS decimal(38,10))*-24*60*60*1000+0.5 as bigint)
         WHEN @SortBy = 'Number of Votes'     THEN [OrgCountVote] * -1 
         WHEN @SortBy = 'Organisation'        THEN [RequestorOrg]
         WHEN @SortBy = 'Category'            THEN [RequestCategory]  END, 
  --second level
    CASE WHEN @SortBy = 'Date (oldest first)' THEN [OrgCountVote] * -1
         WHEN @SortBy = 'Date (newest first)' THEN [OrgCountVote]
         WHEN @SortBy = 'Number of Votes'     THEN reqdate
         ELSE NULL END

我需要暂时解释Date (newest first)条目。如果你只是做一个简单的约会,你最终会溢出整数类型。该长表达式的所有其余部分只是将日期字段转换为可以乘以-1的数字,从而反转排序顺序。相信这个链接是如何做到的:

  

https://social.msdn.microsoft.com/Forums/sqlserver/en-US/51cfea50-f915-4bac-bf7d-d053329086cd/difference-of-dates-in-millisecond?forum=transactsql

如果你不需要毫秒粒度(即:你只存储日期值,时间组件中全为零)或者你不关心它在这里和那里都不完美(几乎同时记录)如果你的数据非常罕见,那么可能会出现故障,那么你可以大大简化那个表达式,然后只考虑自unix时代以来的秒数或者自上次以来的分钟数或天数。 Sql Server时代。

答案 2 :(得分:0)

您应该将逻辑从使用复杂的ORDER BY列列表更改为使用IF子句并指定多个select语句和ORDER BY

像:

If @SortBy = 'Date....' then
Begin
    -- SQL with the single order by group...
End
Else if @SortBy =... Then...
Begin

End

答案 3 :(得分:0)

如果您必须使用案例,这可能会给您类似的结果:

ALTER PROC [dbo].[getRequests]
@SortBy             VARCHAR(50) = 'Date'
AS
SELECT  [ReqDate], [RequestorOrg], [RequestCategory],
    [ReqDescription], [OrgCountVote]
FROM requests
ORDER BY 
CASE 
WHEN @SortBy = 'Date (oldest first)' THEN Datediff(day, '2010-1-1', [ReqDate]) 
WHEN @SortBy = 'Date (newest first)'   THEN [ReqDate]          
WHEN @SortBy = 'Number of Votes'       THEN [RequestorOrg]     
WHEN @SortBy = 'Category'              THEN [RequestCategory]  
END DESC, 
CASE WHEN @SortBy = 'Date (newest first)'    THEN OrgCountVote
WHEN @SortBy = 'Number of Votes'       THEN [OrgCountVote] 
ELSE '' END

同样,你可能不想这样做。并且可以实现性能。

答案 4 :(得分:0)

我想出了一个动态的ORDER BY方式。在我下面的例子中,我可以添加尽可能多的WHEN,它只是单步执行它们并获取相关的语句。

~s({"start_usage":"0","left_operand":"2"})
|> Poison.Parser.parse!
|> Map.get("left_operand")
|> String.to_integer()

我不必担心ELSE,因为参数具有分配给它的默认值,因此将始终具有以下语句之一:

ORDER BY   
CASE WHEN @SortBy = 'Date (oldest first)'   THEN [ReqDateTime]      END ASC,  
CASE WHEN @SortBy = 'Date (oldest first)'   THEN [OrgCountVote]     END DESC,  
CASE WHEN @SortBy = 'Date (newest first)'   THEN [ReqDateTime]      END DESC,  
CASE WHEN @SortBy = 'Date (newest first)'   THEN [OrgCountVote]     END DESC,  
CASE WHEN @SortBy = 'Number of Votes'       THEN [OrgCountVote]     END DESC,   
CASE WHEN @SortBy = 'Number of Votes'       THEN [ReqDateTime]      END DESC,  
CASE WHEN @SortBy = 'Organisation'          THEN [RequestorOrg]     END,  
CASE WHEN @SortBy = 'Status'                THEN ReqStatus          END,  
CASE WHEN @SortBy = 'Category'              THEN [RequestCategory]  END;