postgresql - 连接表时如何避免子查询?

标签 postgresql

-- 我是新手,觉得这不是微不足道就是错误的数据库建模--

在下面的例子中:

create TABLE objects (
id BIGSERIAL NOT NULL UNIQUE PRIMARY KEY,
name text unique
);

create TABLE features (
id BIGSERIAL NOT NULL UNIQUE PRIMARY KEY,
name text
);

create TABLE features_map (
id BIGSERIAL NOT NULL UNIQUE PRIMARY KEY,
o_id BIGINT REFERENCES objects ON DELETE restrict,
f_id BIGINT REFERENCES features ON DELETE restrict,
value text
);

insert into features(id, name) values 
(1, 'length'), 
(2, 'wheels'); 

insert into objects(id, name) values 
(1, 'car'), 
(2, 'bike'); 

insert into features_map(o_id,f_id,value) values
(1,1,'4.5m'),
(1,2,'4'),
(2,1,'2.3m'),
(2,2,'2');

我想获得所需的输出,即左连接但将结果合并到具有不同列的单行中:

select o.id, o.name, 
(select value from features_map fm join features f on fm.f_id=f.id where fm.o_id=o.id and f.name='length') as length, 
(select value from features_map fm join features f on fm.f_id=f.id where fm.o_id=o.id and f.name='wheels') as wheels
from objects o;

id|name|length|wheels|
--|----|------|------|
 1|car |4.5m  |4     |
 2|bike|2.3m  |2     |

这种类型的查询随着表的大小增加而变得太慢,例如objects count>10000 和 features_map count>40000。

使用 join 查询保持相当快,但结果(显然)出现在多行上:

select *
from objects o
join features_map fm on o.id=fm.o_id
join features f on f.id=fm.f_id;

id|name|id|o_id|f_id|value|id|name  |
--|----|--|----|----|-----|--|------|
 1|car | 1|   1|   1|4.5m | 1|length|
 1|car | 2|   1|   2|4    | 2|wheels|
 2|bike| 3|   2|   1|2.3m | 1|length|
 2|bike| 4|   2|   2|2    | 2|wheels|

如何以 join 方法的速度获得所需的输出?

再见, aaWnSd

最佳答案

demo:db<>fiddle

您需要一个数据透视表。这可以通过对数据集进行分组然后使用过滤值进行聚合来实现。

在这种情况下使用了MIN() 函数,但这并不重要。您也可以使用 MAX()SUM(),因为您只有一个值。所以一个单一值的 MIN() == 这个值的 MAX() == SUM() ...

SELECT
    o.id,
    o.name,
    MIN(value) FILTER (WHERE f.name = 'length') AS length,
    MIN(value) FILTER (WHERE f.name = 'wheels') AS wheels
FROM objects o
JOIN features_map fm ON o.id=fm.o_id
JOIN features f ON f.id=fm.f_id
GROUP BY o.id, o.name
ORDER BY o.id

关于postgresql - 连接表时如何避免子查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57758851/

相关文章:

postgresql - PL/PgSQL 在循环中调用一个函数给出错误

postgresql - 使用 Homebrew 软件安装旧版本的 postgres

perl - 我应该提交以下代码吗?

java - Postgres+JDBC 模板太多客户端已经异常

json - 如何将 to_jsonb 用作 row_to_jsonb?关于 "how much"的详细信息在哪里?

python - Pyramid Postgresql 连接问题

sql - 在 Postgres 中有条件地将一列设置为其默认值

python - Alembic 不处理 column_types.PasswordType : Flask+SQLAlchemy+Alembic

postgresql - 如何从大型 postgres 文件中的特定表导入数据?

sql - 根据不同列的条件对列中的行进行排名