CMo*_*ney 3 sql postgresql join greatest-n-per-group sql-limit
鉴于这些表格:
TABLE Stores (
store_id INT,
store_name VARCHAR,
etc
);
TABLE Employees (
employee_id INT,
store_id INT,
employee_name VARCHAR,
currently_employed BOOLEAN,
etc
);
Run Code Online (Sandbox Code Playgroud)
我想为每家商店列出15名雇员最长的员工(假设15 employee_id名员工最低),或者如果有15名员工,则列出所有员工currently_employed='t'.我想用join子句来做.
我发现很多人这样做的例子只有 1行,通常是最小或最大(单个最长雇用的员工),但我想基本上结合一个ORDER BY和一个LIMIT内部的联接.其中一些例子可以在这里找到:
我也找到了很好的例子来做这个商店(我没有,我有大约5000家商店):
我也看到你可以使用TOP而不是ORDER BY和LIMIT,而不是PostgreSQL.
我认为这两个表之间的连接子句不是唯一(或者甚至是最好的方法),如果它可以只store_id在employees表的内部工作,那么我会对其他方法持开放态度.之后可以随时加入.
由于我对SQL很陌生,我想要任何理论背景或其他解释可以帮助我理解工作原理.
row_number()获取每组前n行的一般解决方案是使用窗口函数row_number():
SELECT *
FROM (
SELECT *, row_number() OVER (PARTITION BY store_id ORDER BY employee_id) AS rn
FROM employees
WHERE currently_employed
) e
JOIN stores s USING (store_id)
WHERE rn <= 15
ORDER BY store_id, e.rn;
Run Code Online (Sandbox Code Playgroud)
PARTITION BY应该使用store_id,保证是唯一的(相对于store_name).
首先识别行中的行employees,然后加入stores,这样便宜.
要获得15行row_number()不使用rank()(将是错误的工具).只要employee_id是独一无二的,差异就不会显示出来.
LATERALPostgres 9.3+的替代方案,通常与匹配索引结合使用效果更好,尤其是在从大表中检索小选项时.
SELECT s.store_name, e.*
FROM stores s
, LATERAL (
SELECT * -- or just needed columns
FROM employees
WHERE store_id = s.store_id
AND currently_employed
ORDER BY employee_id
LIMIT 15
) e
-- WHERE ... possibly select only a few stores
ORDER BY s.store_name, e.store_id, e.employee_id
Run Code Online (Sandbox Code Playgroud)
完美索引将是这样的部分多列索引:
CREATE INDEX ON employees (store_id, employee_id) WHERE currently_employed
Run Code Online (Sandbox Code Playgroud)
详细信息取决于问题中缺少的详细信息.相关示例:
两个版本都不包括没有当前员工的商 如果你需要它,有办法解决这个问题......
| 归档时间: |
|
| 查看次数: |
1495 次 |
| 最近记录: |