【问题标题】:Sorting in SQL Server query with Case Statement使用 Case 语句在 SQL Server 查询中排序
【发布时间】:2017-03-10 23:46:49
【问题描述】:

我有如下 SQL 查询:

SELECT t.range  AS [Order Amount Range],
       Count(*) AS [Total Orders]
FROM   (SELECT CASE
                 WHEN totalamount BETWEEN 0 AND 49 THEN ' 0 - 49'
                 WHEN totalamount BETWEEN 50 AND 99 THEN ' 50 - 99'
                 WHEN totalamount BETWEEN 100 AND 149 THEN ' 100 - 149'
                 WHEN totalamount BETWEEN 150 AND 199 THEN ' 150 - 199'
                 WHEN totalamount BETWEEN 200 AND 249 THEN ' 200 - 249'
                 WHEN totalamount BETWEEN 250 AND 299 THEN ' 250 - 299'
                 WHEN totalamount BETWEEN 300 AND 349 THEN ' 300 - 349'
                 WHEN totalamount BETWEEN 350 AND 399 THEN ' 350 - 399'
                 WHEN totalamount BETWEEN 400 AND 449 THEN ' 400 - 449'
                 ELSE 'Above 500'
               END AS range
        FROM   [order]) t
GROUP  BY t.range
ORDER  BY t.range  

现在的问题是排序不起作用,结果以任何特定方式出现。所以第一行可能包含“0-49”范围,第二行包含“200-249”。

如何得到正常的序列?

【问题讨论】:

    标签: sql sql-server tsql sorting


    【解决方案1】:

    您可以使用以下查询获得正常序列。

     select t.range as [Order Amount Range], count(*) as [Total Orders] from(  
        select case                                                             
          when totalamount between 0 and 49    then ' 0 - 49'                  
          when totalamount between 50 and 99   then ' 50 - 99'                  
          when totalamount between 100 and 149 then ' 100 - 149'                  
          when totalamount between 150 and 199 then ' 150 - 199'                  
          when totalamount between 200 and 249 then ' 200 - 249'                  
          when totalamount between 250 and 299 then ' 250 - 299'                  
          when totalamount between 300 and 349 then ' 300 - 349'                  
          when totalamount between 350 and 399 then ' 350 - 399'                  
          when totalamount between 400 and 449 then ' 400 - 449'                  
          else 'Above 500' end as range  from [totalamount]) t 
          group by t.range
    

    【讨论】:

      【解决方案2】:

      列范围是 varchar,SQL Server 被排序为字符串。字符 1 是,在第五个之前

      尝试将列的值而不是 0-49 放入 00-049,而不是 50-99 stavtiti 050-099,...

      select t.range as [Order Amount Range], count(*) as [Total Orders] from
      (  
      select case                                                             
      when totalamount between 0 and 49    then ' 000 - 049'                  
      when totalamount between 50 and 99   then ' 050 - 099'                  
      when totalamount between 100 and 149 then ' 100 - 149'                  
      when totalamount between 150 and 199 then ' 150 - 199'                  
      when totalamount between 200 and 249 then ' 200 - 249'                  
      when totalamount between 250 and 299 then ' 250 - 299'                  
      when totalamount between 300 and 349 then ' 300 - 349'                  
      when totalamount between 350 and 399 then ' 350 - 399'                  
      when totalamount between 400 and 449 then ' 400 - 449'                  
      else ' Above 500' end as range  from [order]) t 
      group by t.range order by t.range 
      

      【讨论】:

        【解决方案3】:

        你可以再加入一个如下:

        SELECT
            A.*
        FROM
        (   select t.range as [Order Amount Range], count(*) as [Total Orders] from
            (  
                select case                                                             
                when totalamount between 0 and 49    then '0 - 49'                  
                when totalamount between 50 and 99   then '50 - 99'                  
                when totalamount between 100 and 149 then '100 - 149'                  
                when totalamount between 150 and 199 then '150 - 199'                  
                when totalamount between 200 and 249 then '200 - 249'                  
                when totalamount between 250 and 299 then '250 - 299'                  
                when totalamount between 300 and 349 then '300 - 349'                  
                when totalamount between 350 and 399 then '350 - 399'                  
                when totalamount between 400 and 449 then '400 - 449'                  
                else 'Above 500' end as range  from [order]
            ) t 
            group by t.range
        ) A INNER JOIN 
        (VALUES 
            (1, '0 - 49')   ,
            (2, '50 - 99')  ,
            (3, '100 - 149'),
            (4, '150 - 199'),
            (5, '200 - 249'),
            (6, '250 - 299'),
            (7, '300 - 349'),
            (8, '350 - 399'),
            (9, '400 - 449'),
            (10, 'Above 500')
        ) b(RowID, Title) ON A.[Order Amount Range] = b.Title
        
        ORDER by b.RowID
        

        【讨论】:

        • 您不能使用 RowID 按子句排序,因为它既不用于 group by 子句也不用于聚合函数。
        • t.[range] = b.RowID 怎么可能? range 是 varchar,rowid 是 int 类型
        • @MansiChaudhari 我的错,JOIN 操作将在 group by 之后进行。
        • 最后也可以使用 group by。
        • @MansiChaudhari 为什么?
        【解决方案4】:

        试试这个它会为你工作。

        SELECT t.[range]  AS [Order Amount Range],
           Count(*) AS [Total Orders] 
           FROM(SELECT CASE
                     WHEN totalamount BETWEEN 0 AND 49 THEN ' 0 - 49'
                     WHEN totalamount BETWEEN 50 AND 99 THEN ' 50 - 99'
                     WHEN totalamount BETWEEN 100 AND 149 THEN ' 100 - 149'
                     WHEN totalamount BETWEEN 150 AND 199 THEN ' 150 - 199'
                     WHEN totalamount BETWEEN 200 AND 249 THEN ' 200 - 249'
                     WHEN totalamount BETWEEN 250 AND 299 THEN ' 250 - 299'
                     WHEN totalamount BETWEEN 300 AND 349 THEN ' 300 - 349'
                     WHEN totalamount BETWEEN 350 AND 399 THEN ' 350 - 399'
                     WHEN totalamount BETWEEN 400 AND 449 THEN ' 400 - 449'
                     ELSE 'Above 500'
                   END AS [range]
            FROM   [order]) t INNER JOIN 
            (VALUES(1,' 0 - 49'),
                   (2,' 50 - 99'),
                   (3,' 100 - 149'),
                   (4,' 150 - 199'),
                   (5,' 200 - 249'),
                   (6,' 250 - 299'),
                   (7,' 300 - 349'),
                   (8,' 350 - 399'),
                   (9,' 400 - 449'),
                   (10,'Above 500')
            )B (id,NewRange) on t.range=B.newrange
        GROUP  BY t.[range],id
        ORDER BY id
        

        【讨论】:

          【解决方案5】:

          通过一些编程而不是复制粘贴:

          ;with cteSource as
          (
              select top 1000 row_number() over(order by (select 1)) as totalamount
              from master.dbo.spt_values v1
              cross join master.dbo.spt_values v2
          ),
          cteSrcRanged as
          (
              select
                  src.totalamount,
                  floor(src.totalamount / 50) amount_range
              from cteSource src
          )
          select
              src.totalamount,
              src.amount_range,
              case
                  when src.amount_range >= 10
                  then 'Above 500'
                  else cast(src.amount_range * 50 as varchar(10)) + ' - ' + cast((src.amount_range + 1) * 50 - 1 as varchar(10))
              end range_name
          from cteSrcRanged src
          

          【讨论】:

            【解决方案6】:

            您可以将[Order Amount Range] 拆分为CROSS APPLY 以在整个声明中使用。

            对于排序,最简单的选择是使用[order].[totalamout],它在数值上已经很有用,并且与您的范围的顺序正确匹配。

            SELECT
                [range].[Order Amount Range],
                Count(*) AS [Total Orders]
            
            FROM [order]
            
            CROSS APPLY (
                SELECT
                    CASE
                        WHEN [order].[totalamount] BETWEEN 0 AND 49 THEN ' 0 - 49'
                        WHEN [order].[totalamount] BETWEEN 50 AND 99 THEN ' 50 - 99'
                        WHEN [order].[totalamount] BETWEEN 100 AND 149 THEN ' 100 - 149'
                        WHEN [order].[totalamount] BETWEEN 150 AND 199 THEN ' 150 - 199'
                        WHEN [order].[totalamount] BETWEEN 200 AND 249 THEN ' 200 - 249'
                        WHEN [order].[totalamount] BETWEEN 250 AND 299 THEN ' 250 - 299'
                        WHEN [order].[totalamount] BETWEEN 300 AND 349 THEN ' 300 - 349'
                        WHEN [order].[totalamount] BETWEEN 350 AND 399 THEN ' 350 - 399'
                        WHEN [order].[totalamount] BETWEEN 400 AND 449 THEN ' 400 - 449'
                        ELSE 'Above 500'
                    END AS [Order Amount Range]
                ) as [range]
            
            GROUP  [range].[Order Amount Range]
            
            ORDER  BY [order].[totalamount]
            

            【讨论】:

              【解决方案7】:

              这真的很简单。

              你只需要替换

              ORDER  BY t.range
              

              与:

              ORDER  BY CONVERT(INT,t.range)
              

              就是这样。

              希望对您有所帮助。 :)

              【讨论】:

              • @Dheeraj Sharma 您不能像这样将 varchar 转换为 int。
              • @MansiChaudhari 因为它只包含整数值,所以转换不会有问题,因为我已经尝试过然后发布。 :)
              • t.range 具有300 - 349 等值,convert 将失败。
              • NP @DheerajSharma :-) 如果您必须像这样处理文本,假设空格前的第一个文本始终是有效数字,则可以使用 convert(int,substring(t.range,0,charindex(' ',t.range)))
              猜你喜欢
              • 2011-02-14
              • 1970-01-01
              • 2018-09-13
              • 1970-01-01
              • 2018-07-23
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多