将2个复杂的GROUP BY / PARTITION BY查询转换为1个查询

时间:2019-02-03 11:05:08

标签: sql sql-server postgresql

我试图使用GROUP BY仅用1个查询来解决任务,但最终使用WITH子句得到了一个复杂的解决方案-因此我将2个查询组合在一起。但是我怀疑我倾向于过度设计它。

说,我们有3张桌子:

(请参见下面的 schema 部分中有关表布局的整个SQL)

  • 作者
  • 主题

例如,任务读取

  

查找撰写了超过2个主题的书的作者

在研究过程中,我提出了复杂的,过度设计的2个解决方案:

解决方案1 ​​-使用PARTITION BY子句计算行号

WITH temp1 AS 
(
    SELECT author_id, subject_id, ROW_NUMBER () OVER (PARTITION BY author_id) as rn
    FROM books
    GROUP BY author_id, subject_id
)
SELECT DISTINCT author_id FROM temp1 WHERE rn > 2
;

解决方案2 -合并2个包含GROUP BY子句的查询

WITH temp1 AS 
(
    SELECT author_id, subject_id
    FROM books
    GROUP BY author_id, subject_id
)
SELECT DISTINCT author_id, COUNT(*) FROM temp1
GROUP BY author_id
HAVING COUNT(*) > 2
;

有什么方法可以仅通过1个查询来解决这样的任务?


架构

以下SQL适用于PostgreSQL

CREATE SEQUENCE authors_id_seq;

CREATE TABLE authors
(
    id bigint NOT NULL DEFAULT nextval('authors_id_seq'::regclass),
    name TEXT NOT NULL,
    CONSTRAINT pk_authors PRIMARY KEY (id)
);

CREATE SEQUENCE subjects_id_seq;

CREATE TABLE subjects
(
    id bigint NOT NULL DEFAULT nextval('subjects_id_seq'::regclass),
    name TEXT NOT NULL,
    CONSTRAINT pk_subjects PRIMARY KEY (id)
);

CREATE SEQUENCE books_id_seq;

CREATE TABLE books
(
    id bigint NOT NULL DEFAULT nextval('books_id_seq'::regclass),
    name TEXT NOT NULL,
    popularity int NOT NULL,
    author_id bigint NOT NULL,
    subject_id bigint NOT NULL,
    CONSTRAINT pk_books PRIMARY KEY (id),
    CONSTRAINT fk_books_authors_author_id FOREIGN KEY (author_id)
        REFERENCES authors (id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE CASCADE,
    CONSTRAINT fk_books_subjects_subject_id FOREIGN KEY (subject_id)
        REFERENCES subjects (id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE CASCADE
);

种子数据:

INSERT INTO authors (name) VALUES 
('John Doe'),
('Friedrich Nietzsche');
INSERT INTO subjects (name) VALUES 
('anatomy'),
('geography'),
('nature');
INSERT INTO books (name, popularity, author_id, subject_id) VALUES
('body', 5, 1, 1),
('earth', 10, 1, 2),
('ocean', 9, 1, 2),
('animals', 9, 1, 3),
('birds', 7, 2, 3);

1 个答案:

答案 0 :(得分:2)

只是您需要基于author_id的不同主题计数

SELECT author_id FROM books 
GROUP BY author_id
HAVING COUNT(DISTINCT subject_id) > 2