Sql 查询以检查列值是否多次出现

Sql 查询以检查列值是否多次出现,sql,postgresql,Sql,Postgresql,我有一个PostgreSQL查询: SELECT DISTINCT ON ("contract"."contract_id") "contract"."id" FROM "contract_versions" "contract" WHERE "contract"."client_id" = 1 GROUP BY "contract"."contract_id", "contract"."id" ORDER BY "contract"."contract_id", "contract"."c

我有一个PostgreSQL查询:

SELECT DISTINCT ON ("contract"."contract_id") "contract"."id"
FROM "contract_versions" "contract"
WHERE "contract"."client_id" = 1 
GROUP BY "contract"."contract_id", "contract"."id" 
ORDER BY "contract"."contract_id", "contract"."change_effective_date" DESC
我想添加一些东西,比如如果合同id出现不止一次,那么更改生效日期>=现在

数据集:

 id  | contract_id | client_id | change_effective_date 
-----+-------------+-----------+-----------------------
 100 |          10 |         1 | 2020-05-17 00:00:00
 200 |          10 |         1 | 2020-05-16 00:00:00
 300 |          10 |         1 | 2020-05-14 00:00:00
 400 |          20 |         1 | 2020-05-17 00:00:00
 500 |          30 |         1 | 2020-05-13 00:00:00
 600 |          30 |         1 | 2020-05-14 00:00:00
预期结果:

 id  | contract_id | client_id | change_effective_date 
-----+-------------+-----------+-----------------------
 200 |          10 |         1 | 2020-05-16 00:00:00
 400 |          20 |         1 | 2020-05-17 00:00:00
 600 |          30 |         1 | 2020-05-14 00:00:00
如果合同id的计数大于1,我希望更改生效日期小于或等于今天的行

我尝试使用:

SELECT DISTINCT ON ("contract"."contract_id") "contract"."id", 
      COUNT("contract"."contract_id") AS cnt 
FROM "contract_versions" "contract" 
WHERE "contract"."client_id" = 1 AND 
CASE WHEN "cnt" > 1 THEN "contract"."change_effective_date" <= now() END 
GROUP BY "contract"."contract_id", "contract"."id" 
ORDER BY "contract"."contract_id", "contract"."change_effective_date" DESC
但其抛出的错误列cnt不存在


谢谢

您的查询中有两个问题:

在第一个查询中,您有: 错误:列contract.change\u effective\u date必须出现在 GROUP BY子句或在聚合函数中使用

在第二种情况下,您不能在查询中直接引用列别名cnt:您可以在另一个查询中这样做,该查询必须将原始查询作为派生表或内联视图引用。 以下是一个可能的解决方案:

select * from contract_versions;
 id  | contract_id | client_id | change_effective_date 
-----+-------------+-----------+-----------------------
 100 |          10 |         1 | 2020-05-14 14:00:00
 100 |          10 |         1 | 2020-05-14 14:00:00
 100 |          10 |         1 | 2020-05-14 14:00:00
 100 |          20 |         1 | 2020-05-16 09:00:00
(4 rows)

Null display is "NULL".
SELECT DISTINCT ON (contract_id) contract_id,
       change_effective_date
FROM contract_versions contract 
WHERE client_id = 1 
GROUP BY contract_id, id, change_effective_date
ORDER BY contract_id, change_effective_date DESC;
 contract_id | change_effective_date 
-------------+-----------------------
          10 | 2020-05-14 14:00:00
          20 | 2020-05-16 09:00:00
(2 rows)

SELECT DISTINCT ON (contract_id) contract_id,
       COUNT(contract_id) AS cnt,
       change_effective_date
FROM contract_versions contract 
WHERE client_id = 1 
GROUP BY contract_id, id, change_effective_date
ORDER BY contract_id, change_effective_date DESC;
 contract_id | cnt | change_effective_date 
-------------+-----+-----------------------
          10 |   3 | 2020-05-14 14:00:00
          20 |   1 | 2020-05-16 09:00:00
(2 rows)

SELECT
contract_id,
CASE WHEN cnt > 1 THEN change_effective_date <= now() 
END 
FROM
(
  SELECT DISTINCT ON (contract_id) contract_id,
         COUNT(contract_id) AS cnt,
         change_effective_date
  FROM contract_versions contract 
  WHERE client_id = 1 
  GROUP BY contract_id, id, change_effective_date
  ORDER BY contract_id, change_effective_date DESC
) v;
 contract_id | case 
-------------+------
          10 | t
          20 | NULL
(2 rows)
我从来没有看到过“清晰”与“分组”相结合。可以先聚合,然后从聚合结果中选取行,但这不是您正在做的,也不是您想要的。您希望ORDER by子句为DISTINCT ON应用的排名考虑当前日期

SELECT DISTINCT ON (contract_id) *
FROM contract_versions
WHERE client_id = 1
ORDER BY 
  contract_id,
  CASE WHEN change_effective_date <= CURRENT_DATE THEN 1 ELSE 2 END,
  change_effective_date DESC;
演示:

带行数窗口功能:

select t.id, t.contract_id, t.client_id, t.change_effective_date
from (
  select *,
    row_number() over (
      partition by contract_id
      order by (change_effective_date > now())::int, change_effective_date desc
    ) rn
  from contract_versions 
) t
where t.rn = 1 
order by t.id 
您的问题中不清楚,因为如果合同id的值只属于一个客户id,则示例数据只包含一个客户id。 如果不是这样,则必须在上述查询中进行更改:

partition by contract_id
致:

看。 结果:


在合同id为10的变更生效日期中输入不同的日期。它并没有给出最新的行,而只是选择找到的第一行。我想检索具有最新更改生效日期但合同id不同的行,如果某些合同id出现在更改生效日期之前不止一次,请编辑您的问题以添加一些输入数据和预期的查询结果。谢谢,这很有效。请您解释一下这一行:如果更改生效日期到今天,我们会先订购,因为我们给他们排序键1,而其他人会给他们排序键2。因此,我们在2020-05-17之前得到2020-05-16,例如,如果合同id在今天和将来都有行。毕竟,排序顺序只是DISTINCT ON选择其行的排序顺序。@ThorstenKettner。DISTINCT ON也可以用于GROUP BY。考虑一个查询,在这里你想得到像每个城市中最有秩序的东西。”Gordon Linoff:我同意。我只是以前没有见过使用它,但这可能是因为主要使用Oracle。如果PostgreSQL是我的DBMS,我很肯定我自己也会使用它:-谢谢你给我举个例子。这一个也有用,谢谢,但它更复杂。
partition by contract_id, client_id
| id  | contract_id | client_id | change_effective_date    |
| --- | ----------- | --------- | ------------------------ |
| 200 | 10          | 1         | 2020-05-16 00:00:00.000  |
| 400 | 20          | 1         | 2020-05-17 00:00:00.000  |
| 600 | 30          | 1         | 2020-05-14 00:00:00.000  |