在PostgreSQL中,如何生成行号:
SELECT
这是一些可以使用的示例数据,
CREATE TEMP TABLE foo AS
SELECT * FROM ( VALUES
('wgates', 'Gates', 'William' ),
('wgrant', 'Grant', 'Wallace' ),
('jjones', 'Jones', 'John' ),
('psmith', 'Smith', 'Paul' )
) AS t(name_id, last_name, first_name);
Run Code Online (Sandbox Code Playgroud)
所需的输出是:
row_number ? name_id ? last_name ? first_name
???????????????????????????????????????????????
1 ? wgates ? Gates ? William
2 ? wgrant ? Grant ? Wallace
3 ? jjones ? Jones ? John
4 ? psmith ? Smith ? Paul
Run Code Online (Sandbox Code Playgroud)
其中一些方法可能会变得棘手。请解释你的答案。我还可以想象两类有效的答案:
UNIQUE
或的数据PRIMARY KEY
(我们仍然可以name_id
在这里使用)UNIQUE
都没有。所有功能都在最新版本的 PostgreSQL 中。
最终,我需要一个没有 ID 的表上的唯一键,以便我可以根据自身的交叉连接更新它。我也是出于单纯的好奇而问的。
如果是您担心的性能,请使用row_number
withoutorder by
以避免排序。
row_number() over ()
Run Code Online (Sandbox Code Playgroud)
确定用于重复删除的良好技术PK
现在这是一个完全不同的问题,然后为row_number()
.
在 Postgres 中,您可以使用ctid
它。不需要窗口函数或缓慢且不可扩展的解决方法。
直接回答问题:
这可以在没有窗口函数的情况下完成,但这会非常慢:
select name_id, last_name, first_name,
(select count(*)
from the_table t2
where t2.name_id <= t1.name_id) as row_number
from the_table t1
order by name_id;
Run Code Online (Sandbox Code Playgroud)
以上等同于:
select name_id, last_name, first_name,
row_number() over (order by name_id) as row_number
from the_table
order by name_id;
Run Code Online (Sandbox Code Playgroud)
但随着窗函数的解决方案将是一个很大更快。如果您不需要任何订购,则使用
select name_id, last_name, first_name,
row_number() over () as row_number
from the_table
order by name_id;
Run Code Online (Sandbox Code Playgroud)
这样你不会得到一个“稳定”的行号,但它会是唯一的。
另一种可能的替代方法是创建一个序列,然后nextval()
在 select 语句中使用。
UNIQUE
必填栏目我发现的一种方法(在Leo Hsu 和 Regina Obe 的SIMULATING ROW NUMBER IN POSTGRESQL PRE 8.4中)被称为“The all in one WTF”。它略有改编,但令人惊叹。
\n\nSELECT row_number, name_id, last_name, first_name\nFROM people\nCROSS JOIN (\n SELECT array_agg(name_id ORDER BY last_name, first_name) AS id FROM people\n) AS oldids\nCROSS JOIN generate_series(1, (SELECT count(*) FROM people))\n AS gs(row_number)\nWHERE id[row_number] = people.name_id;\n
Run Code Online (Sandbox Code Playgroud)\n\n那么让我们进入兔子洞:
\n\n创建ARRAY[]
任意特定列的一个,不生成额外的行。
SELECT *\nFROM people\nCROSS JOIN (\n SELECT array_agg(name_id ORDER BY last_name, first_name) AS id\n FROM people\n) AS oldids;\n
Run Code Online (Sandbox Code Playgroud)\n\nSELECT row_number, name_id, last_name, first_name\nFROM people\nCROSS JOIN (\n SELECT array_agg(name_id ORDER BY last_name, first_name) AS id FROM people\n) AS oldids\nCROSS JOIN generate_series(1, (SELECT count(*) FROM people))\n AS gs(row_number)\nWHERE id[row_number] = people.name_id;\n
Run Code Online (Sandbox Code Playgroud)使用 . 创建笛卡尔积generate_series(1..last_row)
。为了获得最后一行,我们使用 进行子选择count()
。
SELECT *\n FROM people\n CROSS JOIN (\n SELECT array_agg(name_id ORDER BY last_name, first_name) AS id FROM people\n ) AS oldids\n CROSS JOIN generate_series(1, (SELECT count(*) FROM people))\n AS gs(row_number);\n
Run Code Online (Sandbox Code Playgroud)\n\nSELECT *\nFROM people\nCROSS JOIN (\n SELECT array_agg(name_id ORDER BY last_name, first_name) AS id\n FROM people\n) AS oldids;\n
Run Code Online (Sandbox Code Playgroud)现在魔法来了,我们使用行号作为我们创建的数组的索引。因为数组是以下函数的函数:(a) 列UNIQUE
和 (b) 集合中的顺序,我们可以减少笛卡尔积,并保留 row_number。我们所做的就是添加子句WHERE id[row_number] = people.name_id;
归档时间: |
|
查看次数: |
22348 次 |
最近记录: |