【问题标题】:SELECT rows HAVING result equal to a list of values from DISTINCTSELECT rows HAVING 结果等于 DISTINCT 中的值列表
【发布时间】:2021-04-11 22:52:07
【问题描述】:

我想返回匹配所有partskey 的结果。给定:

create table things (
  id int not null,
  key int not null,
  part character varying(1),
  details character varying(64),
  CONSTRAINT things_pkey PRIMARY KEY (id)
  );

还有这个:

id key part details
1 1 a 1a details
2 1 b 1b details
3 1 c 1c details
4 2 a 2a details
5 2 b 2b details
6 2 c 2c details
7 3 a 3a details
8 3 c 3c details
9 4 b 4b details
10 5 b 5b details
11 6 b 6b details
12 6 c 6c details
13 7 a 7a details
14 8 a 8a details

我可以做到这一点:

id key part details
1 1 a 1a details
2 1 b 1b details
3 1 c 1c details
4 2 a 2a details
5 2 b 2b details
6 2 c 2c details

使用此查询:

select * 
from things t
where t.key in (
  select x.key
  from things x
  group by x.key
  having count(distinct part) = 3
);

但我真的想匹配不同的部分,而不仅仅是它的数量,例如having distinct part = ['a', 'b', 'c']。我可以在查询中执行此操作还是仅在应用程序代码中执行此操作?

http://sqlfiddle.com/#!17/38b399/6

编辑

基本上,我所追求的是一大堆行,其中所有 parts 的 thing 都存在。一件事有八个部分。它们将被处理并删除此表中的记录。永远重复。

这是来自 pgAdmin 的 CREATE 脚本(噪音降低):

CREATE TABLE public.things (
    id uuid PRIMARY KEY,
    key character varying(255) COLLATE pg_catalog."default" NOT NULL,
    part character varying(3) COLLATE pg_catalog."default" NOT NULL,
    details character varying(1024) COLLATE pg_catalog."default",
    timezone character varying(128) COLLATE pg_catalog."default",
    client_id uuid,
    CONSTRAINT things_client_id_fkey FOREIGN KEY (client_id)
        REFERENCES public.clients (id)

);

CREATE INDEX things_client_id_index ON public.things (client_id);
CREATE UNIQUE INDEX unique_things ON public.things (key, part, client_id);

【问题讨论】:

  • 您的查询有什么问题?
  • 您要解决的原始问题是什么?
  • 请说明您的确切过滤器要求,以及您正在寻找的确切结果。请务必公开您的 Postgres 版本。
  • (key, part) 是否定义为 UNIQUE?如果是这样,是否有 UNIQUE 约束(应该有)?有keys 表吗?指向它的FOREIGN KEY 约束?
  • 你能告诉我们预期的结果吗?

标签: sql postgresql relational-division


【解决方案1】:

基本上这可以转换为 的情况。

检查每个键的不同部分计数的查询必须处理表的所有行。另外,除此之外,distinct 计数非常昂贵。聚合和比较数组更加昂贵。

如果大多数行都符合条件,那并没有太大的区别,因为无论如何都会处理整个表。对于一个小的选择,任何这样的方法都表现得非常糟糕。可以使用索引的替代查询技术将在比较中脱颖而出。

理想情况下,您有一个单独的键表,每个相关键有一行。然后使用这样的东西:

SELECT *
FROM   keys k
WHERE  EXISTS (SELECT FROM things WHERE key = k.key AND part = 'a')
AND    EXISTS (SELECT FROM things WHERE key = k.key AND part = 'b')
AND    EXISTS (SELECT FROM things WHERE key = k.key AND part = 'c');

things 需要(part, key) 上的多列索引以使其快速。

即使您没有keys 表:

SELECT t1.key
FROM   things t1
JOIN   things t2 USING (key)
JOIN   things t3 USING (key)
WHERE  t1.part = 'a'
AND    t2.part = 'b'
AND    t3.part = 'c';

db小提琴here

最佳查询取决于您对过滤器和结果格式的准确要求,以及准确架构定义。

相关:

【讨论】:

  • 您的意思是在keys和things表中插入相同的键,而不在两个表之间创建关系吗?
  • dbfiddle here
  • 查询不关心任何FOREIGN KEY 约束。但从 DB 设计的角度来看,FK 是实现此目的的简洁方式,当然。强制参照完整性。
【解决方案2】:

我认为count(distinct) 可以满足您的需求。如果你想明确指定部分,你可以使用:

where t.key in (
  select x.key
  from things x
  group by x.key
  having array_agg(distinct part order by part)::text[] = array['a', 'b', 'c']
);

【讨论】:

    猜你喜欢
    • 2012-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-25
    • 2019-02-03
    • 2014-07-10
    • 2015-07-20
    • 1970-01-01
    相关资源
    最近更新 更多