Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 限制联接中每个组的行数(不限于1行)_Sql_Postgresql_Join_Greatest N Per Group_Sql Limit - Fatal编程技术网

Sql 限制联接中每个组的行数(不限于1行)

Sql 限制联接中每个组的行数(不限于1行),sql,postgresql,join,greatest-n-per-group,sql-limit,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 ); 我想列出每家商店雇佣时间最长的15名员工,比如说15名员工id最低的员工,或者如果有15名员工目前正在工作,那么列出一家商店的所有员工。我

鉴于这些表格:

TABLE Stores (
 store_id INT,
 store_name VARCHAR,
 etc
);

TABLE Employees (
 employee_id INT,
 store_id INT,
 employee_name VARCHAR,
 currently_employed BOOLEAN,
 etc
);
我想列出每家商店雇佣时间最长的15名员工,比如说15名员工id最低的员工,或者如果有15名员工目前正在工作,那么列出一家商店的所有员工。我想用join子句来完成它

我发现很多人只在一行中这样做的例子,通常是一个最小或最大的单个最长雇佣员工,但我想基本上结合ORDER BY和联接内部的限制。以下是其中一些例子:

我还找到了一个很好的例子,可以一家一家地做这件事。我没有,我有大约5000家店铺:

我还看到,您可以使用TOP而不是orderby和LIMIT,但PostgreSQL不能

我认为这两个表之间的join子句并不是实现这一点的唯一方法,甚至不一定是最好的方法,如果可以只在employees表中使用不同的store_id,那么我愿意接受其他方法。以后可以随时加入


由于我对SQL非常陌生,我希望有任何理论背景或其他解释可以帮助我理解工作原理。

一种经典的方法是使用A,例如排名:

获取每组前n行的一般解决方案是使用窗口函数row_number:

完美的索引应该是这样的部分多列索引:

CREATE INDEX ON employees (store_id, employee_id) WHERE  currently_employed
细节取决于问题中缺少的细节。相关示例:

这两个版本都不包括没有当前员工的商店。如果你需要的话,有很多方法可以解决这个问题

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;
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
CREATE INDEX ON employees (store_id, employee_id) WHERE  currently_employed