结果集中行自动编号的纯 SQL 技术
Posted
技术标签:
【中文标题】结果集中行自动编号的纯 SQL 技术【英文标题】:Pure-SQL Technique for Auto-Numbering Rows in Result Set 【发布时间】:2008-10-14 18:20:51 【问题描述】:我正在寻找一种对结果集(不是表格)中的行进行顺序编号的方法。本质上,我从如下查询开始:
SELECT id, name FROM people WHERE name = 'Spiewak'
id
s 显然不是一个真实的序列(例如1, 2, 3, 4
)。我需要的是结果集中包含这些自动编号的另一列。如果必须,我愿意使用 SQL 函数,但我宁愿在不使用 ANSI 规范的扩展的情况下这样做。
平台是 mysql,但如果可能,该技术应该是跨平台的(因此希望避免非标准扩展)。
【问题讨论】:
【参考方案1】:要获得有意义的行号,您需要对结果进行排序。然后你可以这样做:
SELECT id, name
, (SELECT COUNT(*) FROM people p2 WHERE name='Spiewak' AND p2.id <= p1.id) AS RowNumber
FROM people p1
WHERE name = 'Spiewak'
ORDER BY id
注意,子查询的 WHERE 子句需要匹配 WHERE 子句或主查询的主键和主查询的 ORDER BY。
SQL Server 有 ROW_NUMBER() OVER 结构来简化这一点,但我不知道 MySQL 是否有什么特殊的解决方法。
由于我在这里的帖子被接受为答案,我还想指出 Dan Goldstein 的回复,这在方法上非常相似,但使用 JOIN 而不是子查询,并且通常会表现更好
【讨论】:
这很聪明,但性能一定很糟糕。并不是说有更好的答案,只是对它的 O(n^2) 感到不寒而栗。 哇!这很聪明。我什至不知道您可以使用子查询以这种方式定义 res 字段。 同意性能可能会更好,但如果你仅限于 ansi,那就是你必须做的。有时人们会预先计算这些结果以加快速度。 哦,如果您的 id 列(在这种情况下)排列在聚集索引上,它可能不会那么不好。至少,SQL Server 2000 足够智能,可以缓存和构建以前的结果。 这个解决方案是 ANSI 并且可以执行 - 但是 - 这是一个潜在的维护噩梦问题,订购必须严格并且可能与标准更改不同步。【参考方案2】:AFAIK,没有“标准”方式。
MS SQL Server 有 row_number(),而 MySQL 没有。
在 MySQL 中最简单的方法是
SELECT a.*, @num := @num + 1 b from test a, (SELECT @num := 0) d;
来源:http://www.xaprb.com/blog/2006/12/02/how-to-number-rows-in-mysql/中的cmets
【讨论】:
【参考方案3】:一个非常低效但 ANSI SQL 的想法是计算具有较小 id 匹配相同条件的行数。我还没有测试过这个 SQL,它可能不会工作,但类似:
SELECT id, name, sub.lcount
FROM people outer
JOIN (SELECT id, COUNT(id) lcount FROM people WHERE name = 'Spiewak' AND id < outer.id GROUP BY id) sub on outer.id = sub.id
WHERE name = 'Spiewak'
【讨论】:
和我发的基本一样,但是在大多数情况下JOIN可能会比子查询快。 哦,您仍然需要在外部查询中明确排序,否则返回的结果可能与查询的排序不同。【参考方案4】:据我所知,没有 ANSI 标准的方法可以做到这一点。
在 SQL Server 中有一个可以使用的 ROW_NUMBER() 函数,而在 Oracle 中,有一个 ROWNUM 伪列。
在 MySQL 中,有this technique
【讨论】:
为此,他可能更喜欢 ROW_NUMBER() 而不是 RANK(),但由于他使用的是 MySQL/Ansi,所以这是一个有争议的问题。【参考方案5】:SELECT @i:=@i+1 AS iterator, t.*
FROM tablename t,(SELECT @i:=0) foo
【讨论】:
【参考方案6】:在 oracle 中,我知道您想要做的唯一数据库是对数据进行子选择
即
select rownum, id , blah, blah
from (
select id, name FROM people WHERE name = 'Spiewak'
)
基本概念是 rownum 将根据内部选择返回的结果集进行评估。
我希望这可以为您指明一个可以使用的解决方案。
【讨论】:
【参考方案7】:这个页面应该给你一个标准的 SQL 方法:
https://www.sqlteam.com/articles/returning-a-row-number-in-a-query
希望这会有所帮助。
【讨论】:
【参考方案8】:我知道这是一个旧线程,但我刚刚在寻找这个答案。我在 MySQL 中尝试了 Dan Goldstein 的查询,但它并没有像写的那样工作,因为 'outer' 是一个保留字。然后,我注意到它仍然在使用子查询。
所以,我想出了一个使用 JOIN 的版本,但没有子查询:
SELECT SUM(IF(p1.id > p2.id, 0, 1)) AS `row`, p2.id, p2.name
FROM people p1 JOIN people p2 ON p1.name = p2.name
WHERE p1.name = 'Spiewak'
GROUP BY p2.id
这在 MySQL 5.1 中对我有用。对于 MySQL,GROUP BY p2.id 似乎就足够了。可以将明确的 ORDER BY p2.id 添加到查询的末尾,但无论哪种方式,我都得到了相同的结果。
【讨论】:
【参考方案9】:最近对问题的回答,但我相信窗口函数现在是 ANSI SQL 的标准,或者至少是大多数当前 SQL 风格的标准。因此,请使用 ROW_NUMBER() 函数。
SELECT
p.ROW_NUMBER() over (order by id) as 'row_id',
p.id as 'id',
p.name as 'name'
FROM
people p
WHERE
p.name = 'Spiewak'
【讨论】:
确实,窗口函数是在 2003 年引入 ANSI SQL 的。MySQL 从 v8.0(2018 年发布)开始支持窗口函数。 SQLite 自 v3.25.0 起(也来自 2018 年)。 “从 2009 年到 2017 年的近八年时间里,PostgreSQL 是唯一支持 SQL 窗口函数的主要免费开源产品。仅仅一年后,到 2018 年 9 月,所有开源竞争对手都赶上了……甚至有些超越。 " -- 来源:modern-sql.com/blog/2019-02/postgresql-11以上是关于结果集中行自动编号的纯 SQL 技术的主要内容,如果未能解决你的问题,请参考以下文章
SqlServerSqlServer编程语言T-SQL的游标使用
合并查询结果集UNION(去重), UNION ALL(不去重),INTERSECT(交集),MINUS(差集,第一个结果集减去第二个结果集,第一个结果集中不在第二个结果集中的记录行)