如何使用分组行对 SQL 查询进行排序

Posted

技术标签:

【中文标题】如何使用分组行对 SQL 查询进行排序【英文标题】:How to Order a SQL Query with grouped rows 【发布时间】:2008-12-22 11:05:49 【问题描述】:

我在 MS Access 中有表 (Product_Id, category priority, atribute1, atribute2...),我正在尝试对按 Category 分组并按最高优先级排序的数据进行排序。优先级可以为 Null,所以应该放在最后。 例子: 表格

1, 100, 2, atr1, atr2
2, 300,  , atr1, atr2
3, 100, 5, atr1, atr2
4, 200, 9, atr1, atr2
5, 100,  , atr1, atr2
6, 200, 1, atr1, atr2

查询中的预期结果:

6, 200, 1, atr1, atr2
4, 200, 9, atr1, atr2
1, 100, 2, atr1, atr2
3, 100, 5, atr1, atr2
5, 100,  , atr1, atr2
2, 300,  , atr1, atr2

【问题讨论】:

【参考方案1】:

在 Jet SQL 中,这可能适合:

SELECT t2.MinOfPriority, tn.Field2, Nz([tn.Field3],999) AS Priority, 
       tn.Field4, tn.Field5
FROM tn 
INNER JOIN (SELECT Min(Nz(tn.Field3,999)) AS MinOfPriority, tn.Field2
            FROM  tn GROUP BY tn.Field2) AS t2 ON tn.Field2 = t2.Field2
ORDER BY t2.MinOfPriority, tn.Field2, Nz([Field3],999);

【讨论】:

呸,你刚刚打败了我 :) 在内连接中质疑你的“表”比我使用的示例要复杂得多。我不确定它是否需要。 我正在使用 ZLS 而不是来自剪切和粘贴的 Null 字段 :(。我已更正它。 “在 Jet SQL 中,这可能适合” - 不,因为 Jet SQL 不支持 NZ() 函数。您应该说“在 MS Access 中...”或类似的说法,因为 NZ() 函数是由 MS Access 接口提供的。在 MS Access 接口之外的 Jet 中,您的 SQL 错误:表达式中未定义函数“NZ”。 确实如此。 “Jet 与 Access 一起使用”也许? IIF([Field3] IS NULL, 999, [Field3]) 更好,因为它可以在 Jet 和 MS Access 中工作,并避免使用 NZ() 进行数据输入(影响排序)的已知问题.其他原因,请参阅allenbrowne.com/QueryPerfIssue.html【参考方案2】:

最简单的解决方案(在某些情况下不一定是最好的)是在排序表达式中使用列号:

SELECT t2.MinOfPriority, 
       tn.Field2, 
       Nz([tn.Field3],999) AS Priority,        
       tn.Field4, 
       tn.Field5

ORDER BY 1,2,3

【讨论】:

【参考方案3】:

您需要对类别进行加权(我用一些适当大的值加权 null):

select  t1.* 
from    myTable t1 
join 
( 

    select  category, min(coalesce(priority, 1000)) weight
    from    myTable 
    group by category
) t2 
on t1. category = t2. category
order by t2.weight, coalesce(t1. priority, 1000)   

【讨论】:

MS Jet 不会理解这一点。 实际上你需要“order by t2.weight desc”并使用“isnull(t1.priority,0)”和max() - 或者我如何理解原始问题:) Jet 不支持 COALESCE 或 ISNULL。 ISNULL 可以用 Jet SQL 中的 Nz() 代替,不是吗?我不相信 Jet SQL 中有任何用于 COALESCE 的命令。 实际上,不,NZ() 不是原生 Jet SQL 语法。 NZ() 由 MS Access 对象模型提供,因此仅在通过 MS Access 接口的查询中可用。原生 Jet 将使用 IIF,FWIW Allen Browne 认为无论如何都要优于 NZ() (allenbrowne.com/QueryPerfIssue.html)【参考方案4】:

据我所知,Jet 总是在使用显式 ORDER BY 时将 NULL 排序到结果集的末尾。

见:ADO Provider Properties and Settings

"NULL Collat​​ion Order:一个 Long 值(只读),它指定 Null 值在哪里进行排序(排序)。对于 Microsoft Jet 提供程序,该值始终为 4,这表示空值在低端排序列表。”

属性 NULL Collat​​ion Order 对提供者来说是只读的,这一事实强烈表明 Jet 引擎只有一个 NULL 排序规则,而且对您来说很高兴,它就是您想要的。

【讨论】:

如果“空值排序在列表的低端”,那么空值将首先出现在列表中。这与 null “应该放在最后”的问题相反。 Ron,您似乎误解了“列表低端”的含义。这里的关键词是“结束”。考虑一个记录集:NULL 将被排序到最接近 EOF(文件的end)的位置。你用 Jet 测试过吗?试试看,我想你会同意 NULL 不会首先出现。【参考方案5】:

ApparentlyNZ(Value, ValueToReturnIfNull) 可以在 MSAccess 上用作 ISNULL 的替代品,所以 ...

SELECT a.*
FROM this_table AS a 
    INNER JOIN 
    (
        SELECT category,min(NZ(priority,999999)) as min_priority_in_cat 
        FROM this_table group by category
    ) AS b ON a.category = b.category
ORDER BY  b.min_priority_in_cat, a.category, NZ(a.priority,999999)

【讨论】:

非常感谢 Ron,但它还不能完全工作。如果定义了优先级,它会完美运行。只要有多个类别没有优先级,那么这些类别就不会被分组。 我不确定我是否遵循。以上应该导致任何类别只有一个 NULL 优先级沉到底部。如果您想对这些类别(仅以 NULL 作为优先级的类别)进行排序,请在 ORDER BY 子句的末尾添加一个 a.category。告诉我,我会更新。 再次感谢 Ron,就是这样,我在 b.min_priority_in_cat 之后添加了 a.category 并且效果很好。我是从 Remou (tn.Field2) 那里找到的。感谢您的帮助! “NZ(Value, ValueToReturnIfNull) 可以在 jet 上用作 ISNULL 的替代品” - Ron,Jet 没有 NZ() 函数。不过,MS Access 确实如此。

以上是关于如何使用分组行对 SQL 查询进行排序的主要内容,如果未能解决你的问题,请参考以下文章

如何编写 sql 查询对数据集进行排序或分组

使用 SQL 查询对新列进行分组和扩展?

如何从命令行对 OpenOffice/LibreOffice 电子表格运行 sql 查询?

sql 分组排序

如何按行对数据进行排序? [MYSQL]

如何编写oracle SQL查询以特定顺序获取匹配和不匹配的行对(基于键列)