按列而非行排序结果

6

在SQL中,是否可以按列而不是行进行排序?我不需要基本的ORDER BY语句,我知道它们是如何工作的(例如:按列1、列2等排序)。

基本上是想要对这样的内容进行排序:

column 1    column 2    column 3
   1            0           3 

尝试对此进行排序:
column 3    column 1    column 2
   3           1           0 

这在SQL中是否可能?最好使用T-SQL或任何可在SQL Server 2005上运行的内容。

我已经在网上搜索了几个小时,甚至似乎没有人想要提出这个问题,或者是我不擅长搜索。

   ; with numbered as
   (
     select SUM(OrderReceived) as c1, SUM(OrderOnHold) as c2, SUM(OrderConfirmed) as     c3,
     row_number() over (order by employee) RecordNumber
     from( SELECT 


e.FirstName+' '+e.LastName AS Employee
,CASE WHEN oim.MilestoneID = 10 THEN 1 ELSE 0 END as OrderReceived
,CASE WHEN oim.MilestoneID = 15 THEN 1 ELSE 0 END as OrderOnHold
,CASE WHEN oim.MilestoneID = 20 THEN 1 ELSE 0 END as OrderConfirmed
FROM OrderItems oi
    JOIN Orders o on o.orderid = oi.orderid
    JOIN OrderItemMilestones oim on oim.orderid = oi.orderid and oim.orderitemid     =     oi.orderitemid
    JOIN Milestones m on m.milestoneid = oim.milestoneid
    JOIN Employees e on e.username = oim.recordedbyuser
    JOIN Clients cl on cl.clientid = o.clientid
WHERE oim.MilestoneDate Between '2012-08-01' and '2012-08-05'
    and e.terminationdate is null
),

ordered as
(
 select SUM(OrderReceived) as c1, SUM(OrderOnHold) as c2, SUM(OrderConfirmed) as c3,
         row_number() over (partition by RecordNumber
                           order by employee desc) rn
    from numbered

  unpivot (v for c in (c1, c2, c3)) u
)
select RecordNumber,
     [1] c1,
     [2] c2,
     [3] c3
 from 
 (
 select RecordNumber,
         v,
         Rn
    from ordered
  ) o
 pivot (min(employee) for Rn in ([1], [2], [3])) p

3
你是在谈论列重排吗?如果你的回答是 ,那么你是在谈论每行的列重排,这样每行根据其值具有不同的列顺序吗? - Robert Koritnik
1
当你的SQL返回多行时会发生什么?你期望什么? - Adriano Carneiro
抱歉回复晚了,整天被困在桌子前,没法经常检查。 - wondergoat77
3个回答

6
这是一个相对简单的按列排序方法。如果您首先将数据进行反向旋转(unpivot),再对其进行排序并旋转(pivot),就可以得到排序后的列。 这里有一个带有示例的Sql Fiddle。
-- Assign arbitrary numbers to records
-- You might skip this part if you have unique column
-- in which case you should replace RecordNumber with this ID
; with numbered as
(
  select *,
         row_number() over (order by (select null)) RecordNumber
    from test
),
-- Generate order by
-- For all the columns in record.
-- Rn will always be in range
-- 1..NumberOfColumns
-- Order is done on unpivoted data
ordered as
(
  select *,
         row_number() over (partition by RecordNumber
                            order by v desc) rn
    from numbered
 -- list all the columns here
 -- v is for value
 -- c is for column
 unpivot (v for c in (c1, c2, c3)) u
)
-- Finally return the data in original layout
select RecordNumber,
       [1] c1,
       [2] c2,
       [3] c3
  from 
  (
    -- Only the columns needed by the query
    -- Pivot will not play nice even if you
    -- Select only subset of columns in
    -- outer query
    select RecordNumber,
           v,
           Rn
      from ordered
  ) o
 -- Get value for row numbers 1..NumberOfColumns
 pivot (min(v) for Rn in ([1], [2], [3])) p

您可能想要添加标题行,以便您知道哪个值来自哪一列。为此,我会添加一个标识标题/行的列,使用 union all 连接到 o 获取相应的标题,并按顺序排序,以确保这两行在一起:

  (
    select RecordNumber,
           v,
           Rn,
           1 HdrRow
      from ordered
     union all
    select RecordNumber,
           c,    -- Column name is in c
           Rn,
           0 HdrRow
      from ordered
  ) o
    ...
  order by RecordNumber, HdrRow

1
@wondergoat77请将c1、c2和c3替换为您的列,并将选择列表添加到内部和外部查询中的“最后返回...”部分。除了实际表名之外,这应该是全部内容。 - Nikola Markovinović
@NikolaMarkovinović 感谢您的帮助,我将在今天下午尝试在工作中实现它,看看能否让它正常工作。 - wondergoat77
我认为我已经接近解决了,但是出现了语法错误(在“,”附近的语法不正确),指的是按部分排序的括号。 - wondergoat77
1
@wondergoat77 请查看这个Sql Fiddle。我已经将员工添加到了选择/分组列表中。由于RecordNumber仅用作行的ID,而员工可以起到相同的作用,因此我已删除了RecordNumber并使用了员工。我还在ordered中修复了选择列表和排序方式。 - Nikola Markovinović
1
@wondergoat77 请查看这个Sql Fiddle。您会注意到HdrRow列和o中的union all。通过选择c,这为每一行添加了标题。 HdrRow用于区分标题行和数据行。我已经使用它来确保两行保持在一起(请参见order by)。由于union all,我不得不将您的数字转换为varchars; 希望这不会成为问题。 - Nikola Markovinović
显示剩余16条评论

5

你是否在使用 SELECT *?如果是的话,请停止使用。如果你知道你想要它们以那种方式列出来,那么请写成:

SELECT [column 3], [column 1], [column 2] FROM dbo.table;

如果您是希望在这些列内进行排序,我不确定这么做是否有意义。但我猜您可以尝试以下操作:

DECLARE @x TABLE(c1 INT, c2 INT, c3 INT);

INSERT @x(c1,c2,c3) SELECT 2,1,3
UNION ALL SELECT 3,4,5
UNION ALL SELECT 5,4,3
UNION ALL SELECT 3,1,2
UNION ALL SELECT 3,3,3
UNION ALL SELECT 3,4,3
UNION ALL SELECT 4,3,4;

SELECT c1 = CASE
  WHEN c1 >= c2 AND c1 >= c3 THEN c1
  WHEN c2 >= c1 AND c2 >= c3 THEN c2
  ELSE c3 END,
c2 = CASE 
  WHEN c1 >= c2 AND c1 >= c3 THEN 
    CASE WHEN c2 >= c3 THEN c2 ELSE c3 END
  WHEN c2 >= c1 AND c2 >= c3 THEN
    CASE WHEN c1 >= c3 THEN c1 ELSE c3 END
  ELSE
    CASE WHEN c1 >= c2 THEN c1 ELSE c2 END
  END,
c3 = CASE
  WHEN c1 <= c2 AND c1 <= c3 THEN c1
  WHEN c2 <= c1 AND c2 <= c3 THEN c2
  ELSE c3 END
FROM @x;

结果:

c1   c2   c3
---- ---- ----
3    2    1
5    4    3
5    4    3
3    2    1
3    3    3
4    3    3
4    4    3

1
我想这对于原帖的提问者来说可能太过简单,我几乎可以确定他们不是在寻求这个...但即使结果查询只返回一行记录,也无法满足他们的要求,因为他们想按照值的顺序排序,而不是作为静态定义的列列表,这个列表总是相同的。无论你如何在查询中排序它们,它们都会按照那个顺序返回,而不考虑它们的值。 - Robert Koritnik
1
@RobertKoritnik,你可能是对的,也可能不是。谁知道呢?OP没有费心澄清。同时,我会选择简单的方法。如果你想提出另一个答案,那就去吧。 - Aaron Bertrand
嗨,这对我需要的东西不起作用,我不能像这样定义列,我需要它们按数字顺序填充,而无需手动定义列。请告诉我我可以提供什么其他信息,抱歉回复较慢,我现在正在工作中,也在尝试解决其他问题。感谢您的所有帮助。 - wondergoat77
谢谢提供这个例子,我对 SQL 还有点新,所以需要尝试一下,看看能否让它按照我的需求工作,但这确实让我找到了正确的方向,非常感谢。 - wondergoat77
1
当然,如果你添加第四列,复杂度会呈指数级增长。最好在存储数据之前,例如在应用程序代码中对其进行排序。 - Aaron Bertrand
显示剩余4条评论

0

使用动态查询进行双重查询

如果您的查询只返回一行数据,那么您可以通过执行两次查询来解决这个问题:

  1. 查询您的数据以获取列的值
    a) 并且根据结果中的值生成具有列顺序的动态SQL
  2. 执行动态查询

如果您的查询应该返回多行数据,我想我们需要更多信息来了解您尝试实现什么,以便提出可行的解决方案或至少更好的建议如何缓解您的问题。


抱歉如果我没有解释清楚,我需要返回超过1行的结果。我认为在SQL中可能有一个简单的解释,我还不知道。我基本上正在尝试总结员工的生产力。我让查询返回员工姓名的列1,每个其他列都是我们内部系统中的状态,然后对每个员工计算每个状态的数量并获得结果。结果类似于我的第一个示例。您应该知道,这些列是通过使用CASE和SUM()来定义和计算每个状态来创建的。这可能是... - wondergoat77
我遇到的问题是,由于我的列已经全部定义好了,它们可能无法重新排列。希望这足够提供信息,如果需要更多,请告诉我。 - wondergoat77
1
它确实为手头的问题提供了一些启示...但还不够。如果您能提供我们表格的几行(虚构),然后根据这些数据提供结果,那就太好了...我不确定您是想要 a 保留第一列(名称)并总结所有其他列的值,还是 b 保留第一列,总结所有其他列并将行转置为列,使每个列都有一个人的姓名和值,该值是所有状态的总和。 - Robert Koritnik
我会尽力而为,但我在SQL和论坛方面还是个新手,请耐心等待。我会在下一条评论中提供更多信息。 - wondergoat77
我开始使用一张数据表,从中取出一列显示员工处理订单时我们系统中更新的内容。每一行返回订单号、用户和用户放置订单的状态。这是我要提取的主要表格,如果可以的话,我会将其粘贴在这里,很抱歉我不知道怎样操作。 然后,我正在创建一个case语句来计算每个状态的数量,然后将每个case都汇总到自己定义的列中,使用一个派生表格来排列所有已经总结的列。但我不确定如何根据它们返回的值对它们进行重新排序。 - wondergoat77
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接