棘手的PostgreSQL连接和订单查询
我在PostgreSQL 9.3.6数据库中有四个表:棘手的PostgreSQL连接和订单查询,sql,postgresql,Sql,Postgresql,我在PostgreSQL 9.3.6数据库中有四个表: 章节 字段(节的子项) 条目(节的子项) 数据(条目的子项) 我正在尝试生成一个如下所示的页面: section title field 1 title | field 2 title | field 3 title entry 1 | data 'as' json | data 1 json | data 3 json <-- table entry 2 | data 'df' js
- 章节
- 字段(节的子项)
- 条目(节的子项)
- 数据(条目的子项)
section title
field 1 title | field 2 title | field 3 title
entry 1 | data 'as' json | data 1 json | data 3 json <-- table
entry 2 | data 'df' json | data 5 json | data 6 json
entry 3 | data 'gh' json | data 8 json | data 9 json
section title
field 1 title | field 2 title | field 3 title
entry 3 | data 'gh' json | data 8 json | data 9 json
entry 2 | data 'df' json | data 5 json | data 6 json
entry 1 | data 'as' json | data 1 json | data 3 json <-- table
章节标题
字段1标题|字段2标题|字段3标题
条目1 | data“as”json | data 1 json | data 3 json编写此查询的关键是理解您只需要获取单个节的所有数据,其余的数据只需加入。您也不能使用模式直接按节筛选数据,因此您需要加入条目,以便:
SELECT d.* FROM data d JOIN entries e ON (d.entry = e.id)
WHERE e.section = ?
然后,您可以将字段连接到每一行,以获得默认值、类型和标题:
SELECT d.*, f.title, f.type, f."default"
FROM data d JOIN entries e ON (d.entry = e.id)
JOIN fields f ON (d.field = f.id)
WHERE e.section = ?
或者,您可以在单独的查询中选择字段以保存一些网络流量
这是一个答案,奖金来了:
使用外键而不是整数来引用其他表,这将使数据库为您检查一致性
按照惯例,关系(表)应以单数形式调用,因此它是部分
、条目
和字段
引用字段被称为\u id
,例如字段id
或节id
JSON字段的全部意义在于存储一个包含非静态定义数据的集合,因此不使用条目
和数据
表,而是使用包含所有字段的JSON的单个表更有意义
像这样:
CREATE TABLE row ( -- less generic name would be even better
id int primary key,
section_id int references section (id),
data json
)
使用包含以下内容的数据字段:
{
"title": "iPhone 6",
"price": 650,
"available": true,
...
}
提供了很好的建议,其中一些建议你已经接受了。我正在更新的模式上构建
模式
我又改变了两个细节:
section\u id
而不是id
,等等。“id”作为列名是一种反模式,由于一些orm使用它,这种反模式变得很流行。不要。描述性名称更好。相同内容的相同名称是一条有用的指导原则。它还允许在join子句中使用快捷方式:
- 不要使用保留字作为标识符。只使用合法的、小写的、不带引号的名字,让你的生活更轻松
参照完整性?
您的设计中还有一个固有的弱点。是什么阻止数据
中的条目引用不在一起的字段
和条目
?关于dba.SE的密切相关问题
查询
不确定您是否需要复杂的设计。但要回答这个问题,这是基本查询:
SELECT entry_id, field_id, COALESCE(d.data, f.default_val) AS data
FROM entry e
JOIN field f USING (section_id)
LEFT JOIN data d USING (field_id, entry_id) -- can be missing
WHERE e.section_id = 1
ORDER BY 1, 2;
LEFT JOIN
对于允许丢失数据条目并使用默认值非常重要
crosstab()
最后一步是交叉制表。由于未安装附加模块tablefunc
,因此无法在SQL FIDLE中显示此信息
交叉表()的基础知识
:
这里比较棘手的部分是函数的返回类型。我为3个字段提供了一个静态类型,但您确实需要动态类型。此外,我正在引用json
类型中的一个字段,该字段可能存在,也可能不存在。。。
因此,动态构建该查询并在第二次调用中执行它
更多信息:
您还可以发布数据库表的架构吗?或者您正在查找完整的表信息吗?我希望获得一些表名和列名,以便构造正确的SQL查询。好了-谢谢您的检查!你对博士后的看法应该一直是个问题。我会做1-3题。您是否能够按照4中的设置以任何方式说“title”进行排序?另外,您提供的查询看起来与我要查找的非常相似。不过,我可能会在单独的查询中选择字段。有没有办法通过其中一个查询按数据对结果进行排序?如果是这样的话,我不知道该怎么做——我只需要一个通用的指令,在PostgreSQL 9.3中,您可以访问JSON字段中的值,所以可以按标题排序。您还可以创建一个函数索引,使其更快。您可以升级到PostgreSQL 9.4并获取二进制JSON和GIN索引。如果您需要编写这样的查询,您的模式可能设计得不好。@Suor:可能是这样。引用完整性还有另一个问题。我添加了一点,如果我删除了数据表,并在条目表中添加了一个数据json列,我认为这将完全消除对join的需要——我可以选择字段。然后选择条目并按我想要的json字段中的任意键进行排序。然后,在创建表时,如果设置了该列/字段的条目json键,则使用该值,否则使用默认值。唯一棘手的部分是有效地更新数据json字段,然后假设在9.3中按json键排序效果良好,这里是否需要交叉表步骤?如果没有它,它在小提琴中似乎很好用?交叉表部分做什么?@maxhud:它将列字段\u id
的值转换为单独的列,以匹配您问题中的格式。请关注详细信息。
{
"title": "iPhone 6",
"price": 650,
"available": true,
...
}
CREATE TABLE section (
section_id serial PRIMARY KEY,
title text,
grp integer
);
CREATE TABLE field (
field_id serial PRIMARY KEY,
section_id integer REFERENCES section,
title text,
type text,
default_val json
);
CREATE TABLE entry (
entry_id serial PRIMARY KEY,
section_id integer REFERENCES section
);
CREATE TABLE data (
data_id serial PRIMARY KEY,
field_id integer REFERENCES field,
entry_id integer REFERENCES entry,
data json
);
SELECT entry_id, field_id, COALESCE(d.data, f.default_val) AS data
FROM entry e
JOIN field f USING (section_id)
LEFT JOIN data d USING (field_id, entry_id) -- can be missing
WHERE e.section_id = 1
ORDER BY 1, 2;
SELECT * FROM crosstab(
$$
SELECT entry_id, field_id, COALESCE(d.data, f.default_val) AS data
FROM entry e
JOIN field f USING (section_id)
LEFT JOIN data d USING (field_id, entry_id) -- can be missing
WHERE e.section_id = 1
ORDER BY 1, 2
$$
,$$SELECT field_id FROM field WHERE section_id = 1 ORDER BY field_id$$
) AS ct (entry int, f1 json, f2 json, f3 json) -- static
ORDER BY f3->>'a'; -- static