如何订购已经订购的子查询

时间:2015-10-20 12:14:57

标签: sql sql-server

创建此表:

CREATE TABLE #Test (id int, name char(10), list int, priority int)

INSERT INTO #Test VALUES (1, 'One', 1, 1)
INSERT INTO #Test VALUES (2, 'Two', 2, 1)
INSERT INTO #Test VALUES (3, 'Three', 3, 2)
INSERT INTO #Test VALUES (4, 'Four', 4, 1)
INSERT INTO #Test VALUES (5, 'THREE', 3, 1)

并按列表和优先顺序排序:

SELECT * FROM #Test ORDER BY list, priority

 1 | One   | 1 | 1
 2 | Two   | 2 | 1
 5 | THREE | 3 | 1
 3 | Three | 3 | 2
 4 | Four  | 4 | 1

但是我想逐行逐行选择按优先级排序的每个列表的顶部行,并在结束时重新开始。

例如,使用这个更简单的表:

 1 | One   | 1 | 1
 2 | Two   | 2 | 1
 3 | Three | 3 | 1
 4 | Four  | 4 | 1

和这个查询:

SELECT TOP 1 * FROM #Test ORDER BY (CASE WHEN list>@PreviousList THEN 1 ELSE 2 END)

如果@PreviousList是我前一行的list,那么这将选择下一行,并在我选择最后一行时优雅地跳到顶部。

但有些行list只有priority排序 - 就像我的第一个例子:

 1 | One   | 1 | 1
 2 | Two   | 2 | 1
 5 | THREE | 3 | 1
 3 | Three | 3 | 2
 4 | Four  | 4 | 1

此处id=3应跳过,因为id=5具有相同的列表排序和更高的优先级。我能想到这样做的唯一方法就是首先按列表和优先级排序整个列表,然后按顺序运行顺序逐行遍历行,如下所示:

SELECT TOP 1 * FROM (
    SELECT * FROM #Test ORDER BY list, priority
) ORDER BY (CASE WHEN list>@PreviousList THEN 1 ELSE 2 END)

但是我当然不能通过已经排序的子查询来命令并得到错误:

The ORDER BY clause is invalid in views, inline functions, derived tables,
subqueries, and common table expressions, unless TOP or FOR XML is also
specified.

是否有任何方法可以解决此问题或将查询下载到单个查询并按顺序排序?

4 个答案:

答案 0 :(得分:1)

  

我想逐行逐行选择每一行的顶行   列表按优先级排序,并在我结束时重新开始。

您可以使用为OVER(PARTITION BY name ORDER BY priority)这些方案设计的内置ROW_NUMBER功能直接执行此操作:

WITH CTE
AS
(
  SELECT *, ROW_NUMBER() OVER(PARTITION BY name ORDER BY priority) AS RN
  FROM #Test
)
SELECT * 
FROM CTE 
WHERE RN = 1;

rn生成的排名编号ROW_NUMBER() OVER(PARTITION BY name ORDER BY priority)会对按name排序的priority相同的每一行进行排名,然后按WHERE rn = 1进行过滤它将删除所有具有相同名称的副本,并只保留第一个优先级。

答案 1 :(得分:1)

另一种可能的解决方案是使用子查询来选择按列表分组的最小优先级,并将其连接回表以获取其余详细信息

SELECT T2.*
FROM (SELECT MIN(priority) as priority, list
      FROM #Test 
      GROUP BY list) AS T1
INNER JOIN #Test T2 ON T1.list = T2.list AND T1.priority = T2.priority
ORDER BY T1.list, T1.priority

答案 2 :(得分:0)

SELECT TOP 1 * FROM (
        SELECT * FROM #Test 
    ) ORDER BY (CASE WHEN list>@PreviousList THEN 1 ELSE 2 END)

试试这个,因为CTE中不允许Order By

答案 3 :(得分:0)

也许我错过了使这比我意识到的更难的要求,但是为列表选择最高优先级的简单连接又是什么呢。要进行扩展,性能需要列表中的索引。

PASSWORD