如何将多个 INNER JOIN 转换为通用/可编程函数

Posted

技术标签:

【中文标题】如何将多个 INNER JOIN 转换为通用/可编程函数【英文标题】:How to convert multiple INNER JOINs into a generic/programmable function 【发布时间】:2022-01-01 23:27:45 【问题描述】:

假设我们存储文件及其属性(存在几个不同的属性,每个属性都有一个值):

CREATE TABLE file(
    id UUID NOT NULL,
    name TEXT NOT NULL,
    CONSTRAINT file_primarykey PRIMARY KEY(id)
);

CREATE TABLE attribute(
    id UUID NOT NULL,
    name TEXT NOT NULL,
    CONSTRAINT attribute_primarykey PRIMARY KEY(id)
);

CREATE TABLE file_attribute(
    id UUID NOT NULL,
    file_id UUID NOT NULL,
    attribute_id UUID NOT NULL,
    value TEXT NOT NULL,
    CONSTRAINT file_attribute_primarykey PRIMARY KEY(id),
    CONSTRAINT file_attribute_foreignkey_file_id FOREIGN KEY(file_id) REFERENCES file ON DELETE CASCADE,
    CONSTRAINT file_attribute_foreignkey_attribute_id FOREIGN KEY(attribute_id) REFERENCES attribute ON DELETE CASCADE
);

INSERT INTO file(id, name) VALUES
('aaa2a8e9-a004-44bf-9ec7-0c20733380da', 'Die Verwandlung.pdf'),
('bba2a8e9-a004-44bf-9ec7-0c20733380da', 'Star Wars.pdf');

INSERT INTO attribute(id, name) VALUES
('11a2a8e9-a004-44bf-9ec7-0c20733380da', 'FILE_SIZE'),
('1aa2a8e9-a004-44bf-9ec7-0c20733380da', 'FILE_EXTENSION'),
('2aa2a8e9-a004-44bf-9ec7-0c20733380da', 'FILE_OWNER');

INSERT INTO file_attribute(id, file_id, attribute_id, value) VALUES
('1111a8e9-a004-44bf-9ec7-0c20733380da', 'aaa2a8e9-a004-44bf-9ec7-0c20733380da', '11a2a8e9-a004-44bf-9ec7-0c20733380da', '101'),
('2222a8e9-a004-44bf-9ec7-0c20733380da', 'aaa2a8e9-a004-44bf-9ec7-0c20733380da', '1aa2a8e9-a004-44bf-9ec7-0c20733380da', '.pdf'),
('3333a8e9-a004-44bf-9ec7-0c20733380da', 'aaa2a8e9-a004-44bf-9ec7-0c20733380da', '2aa2a8e9-a004-44bf-9ec7-0c20733380da', 'James'),
('4444a8e9-a004-44bf-9ec7-0c20733380da', 'bba2a8e9-a004-44bf-9ec7-0c20733380da', '11a2a8e9-a004-44bf-9ec7-0c20733380da', '251'),
('5555a8e9-a004-44bf-9ec7-0c20733380da', 'bba2a8e9-a004-44bf-9ec7-0c20733380da', '1aa2a8e9-a004-44bf-9ec7-0c20733380da', '.pdf');

情况:我想按属性获取文件:

-- Search for all files that have a file attribute "FILE_EXTENSION" ending with .pdf --> Will return Die Verwandlung
SELECT f.id, f.name FROM file f INNER JOIN file_attribute fa ON f.id = fa.file_id WHERE fa.attribute_id = '1aa2a8e9-a004-44bf-9ec7-0c20733380da' AND fa.value = '.pdf';

-- Search for all files that have a file attribute "FILE_SIZE" with the size of 251 -->  Will return Star Wars
SELECT f.id, f.name FROM file f INNER JOIN file_attribute fa ON f.id = fa.file_id WHERE fa.attribute_id = '11a2a8e9-a004-44bf-9ec7-0c20733380da' AND fa.value = '251';

-- Search for file extension .pdf and file size 101 --> Will return Die Verwandlung
SELECT f.id, f.name FROM file f
INNER JOIN file_attribute fa1 ON f.id = fa1.file_id
INNER JOIN file_attribute fa2 ON f.id = fa2.file_id 
WHERE fa1.attribute_id = '1aa2a8e9-a004-44bf-9ec7-0c20733380da' AND fa1.value = '.pdf' AND fa2.attribute_id = '11a2a8e9-a004-44bf-9ec7-0c20733380da' AND fa2.value = '101';

问题/问题:

1.) 多个连接如何影响[在同一个连接表上] 的性能? [过早] 优化的任何提示?或者有没有更好的方法来设计查询?

2.) 如何将查询转换为自定义函数,以便以地图样式的方式传递属性 ID 和值?这个想法是在文件中搜索 0 - n 个文件属性 + 文件中不属于此问题的其他列。伪调用:

select search_files([attribute_id: 1aa2a8e9-a004-44bf-9ec7-0c20733380da, value: .pdf, attribute_id: 11a2a8e9-a004-44bf-9ec7-0c20733380da, value: 101])

我想从JDBC 调用此函数,并希望将值传递为Map(如果可能的话)

【问题讨论】:

【参考方案1】:

如果您不需要结果 rs 中的属性,则存在于 where 子句中可能会更好

在函数中添加这个没有问题吗?

SELECT f.id, f.name FROM file f 
WHERE EXISTS (select 0 from file_attribute fa1 ON f.id = fa1.file_id and fa1.attribute_id = '1aa2a8e9-a004-44bf-9ec7-0c20733380da' AND fa1.value = '.pdf') AND 
EXISTS (select 0 from file_attribute fa2 ON f.id = fa2.file_id and fa2.attribute_id = '1aa2a8e9-a004-44bf-9ec7-0c20733380da' AND fa2.value = '101')

【讨论】:

以上是关于如何将多个 INNER JOIN 转换为通用/可编程函数的主要内容,如果未能解决你的问题,请参考以下文章

如何将 IN 条件转换为 INNER JOIN 条件 - 加入速度较慢

如何在sql中创建INNER JOIN多个表

使用 INNER JOIN LATERAL 和 postgresql 将宽表转换为长表

如何在 R 中 dplyr::inner_join 多个 tbls 或 data.frames

如何使用多个 INNER JOIN 加快查询速度

带有 WHERE 子句的 SQL INNER JOIN 到 LINQ 格式