创建视图时重用子查询的结果

时间:2018-03-09 20:22:48

标签: sql postgresql

在postgresql中创建视图时,是否可以在后续子查询中重用子查询的结果?

例如,我有以下两个表:

CREATE TABLE application
(
    id INT PRIMARY KEY,
    name CHARACTER VARYING(255)
);
CREATE TABLE application_user
(
    id INT PRIMARY KEY,
    application_id INT REFERENCES application (id) ON DELETE CASCADE,
    active BOOLEAN
);

-- some sample data
INSERT INTO application (id, name) VALUES 
    (10, 'application1'), 
    (20, 'application2'), 
    (30, 'application3');
INSERT INTO application_user (id, application_id, active) VALUES 
    (1, 10, true),
    (2, 10, false),
    (3, 20, false),
    (4, 20, false),
    (5, 20, false);

我需要的视图(现在)看起来如下:

CREATE VIEW application_stats AS
SELECT a.name,
    (SELECT COUNT(1) FROM application_user u 
        WHERE a.id = u.application_id) AS users,
    (SELECT COUNT(1) FROM application_user u 
        WHERE a.id = u.application_id AND u.active = true) AS active_users
    FROM application a;

这确实给了我正确的结果:

name             users    active_users
application1     2        1
application2     3        0
application3     0        0

然而,由于我使用两次几乎相同的查询并且理想情况下我想重用第一个查询的结果,因此效率也非常低。有没有一种有效的方法呢?

2 个答案:

答案 0 :(得分:1)

这通常表示为join / group by

SELECT a.name, COUNT(au.application_id) as users,
       SUM( (au.active = true)::int) as active_users
FROM application a LEFT JOIN
     application_user au
     ON a.name = au.application_id
GROUP BY a.name;

我很惊讶application没有serial主键。但由于您使用的是name,因此根本不需要join

SELECT au.application_id, COUNT(*) as users,
       SUM( (au.active = true)::int) as active_users
FROM application_user au
GROUP BY au.application_id;

这将返回至少有一台服务器的应用程序。

答案 1 :(得分:0)

您应该加入两个表,按application_id分组,并使用带有count子句的FILTER (WHERE ...)来计算您想要的行:

CREATE VIEW application_stats AS
SELECT a.name
       count(*) AS users,
       count(*) FILTER (WHERE u.active) AS active_users
FROM application a
   LEFT JOIN application_user u ON a.id = u.application_id
GROUP BY a.id;