SELECT 行的结果等于来自 DISTINCT 的值列表

SELECT rows HAVING result equal to a list of values from DISTINCT

我想要 return 结果与 key 匹配,其中所有 parts 都存在。鉴于:

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

编辑

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

这是来自 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);

我认为 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']
);

基本上这可以转换为 .

的情况

检查每个键的部件的不同计数的查询必须处理 table 的 所有 行。另外,distinct 计数是昂贵的。聚合和比较数组的成本更高。

如果大多数行都符合条件,那不会有太大的区别,因为整个 table 无论如何都会被处理。对于一小部分选择,任何此类方法的表现都非常糟糕。相比之下,可以使用 indexes 的替代查询技术会大放异彩。

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

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');

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

即使你没有 keys table:

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<>fiddle here

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

相关:

  • How to filter SQL results in a has-many-through relation