Dan*_*cco 7 sql postgresql data-modeling
我有四张桌子
create table entities{
integer id;
string name;
}
create table users{
integer id;//fk to entities
string email;
}
create table groups{
integer id;//fk to entities
}
create table group_members{
integer group_id; //fk to group
integer entity_id;//fk to entity
}
Run Code Online (Sandbox Code Playgroud)
我想创建一个查询,直接或间接返回用户所属的所有组.显而易见的解决方案是在应用程序级别进行递归.我想知道我可以对我的数据模型进行哪些更改以减少数据库访问,从而获得更好的性能.
Qua*_*noi 16
在Oracle:
SELECT group_id
FROM group_members
START WITH
entity_id = :user_id
CONNECT BY
entity_id = PRIOR group_id
Run Code Online (Sandbox Code Playgroud)
在SQL Server:
WITH q AS
(
SELECT group_id, entity_id
FROM group_members
WHERE entity_id = @user_id
UNION ALL
SELECT gm.group_id, gm.entity_id
FROM group_members gm
JOIN q
ON gm.entity_id = q.group_id
)
SELECT group_id
FROM q
Run Code Online (Sandbox Code Playgroud)
在PostgreSQL 8.4:
WITH RECURSIVE
q AS
(
SELECT group_id, entity_id
FROM group_members
WHERE entity_id = @user_id
UNION ALL
SELECT gm.group_id, gm.entity_id
FROM group_members gm
JOIN q
ON gm.entity_id = q.group_id
)
SELECT group_id
FROM q
Run Code Online (Sandbox Code Playgroud)
在PostgreSQL 8.3及以下:
CREATE OR REPLACE FUNCTION fn_group_members(INT)
RETURNS SETOF group_members
AS
$$
SELECT group_members
FROM group_members
WHERE entity_id = $1
UNION ALL
SELECT fn_group_members(group_members.group_id)
FROM group_members
WHERE entity_id = $1;
$$
LANGUAGE 'sql';
SELECT group_id
FROM group_members(:myuser) gm
Run Code Online (Sandbox Code Playgroud)
有一些方法可以避免树层次结构查询中的递归(与人们在这里所说的相反).
我最常用的是嵌套集.
然而,与所有生活和技术决策一样,还需要权衡利弊.嵌套集的更新速度通常较慢,但查询速度要快得多.有一些聪明而复杂的方法来提高更新层次结构的速度,但还有另一种权衡取舍; 性能与代码复杂性.
嵌套集的一个简单示例......
树视图:
-Electronics
|
|-Televisions
| |
| |-Tube
| |-LCD
| |-Plasma
|
|-Portable Electronics
|
|-MP3 Players
| |
| |-Flash
|
|-CD Players
|-2 Way Radios
Run Code Online (Sandbox Code Playgroud)
嵌套集表示
+-------------+----------------------+-----+-----+
| category_id | name | lft | rgt |
+-------------+----------------------+-----+-----+
| 1 | ELECTRONICS | 1 | 20 |
| 2 | TELEVISIONS | 2 | 9 |
| 3 | TUBE | 3 | 4 |
| 4 | LCD | 5 | 6 |
| 5 | PLASMA | 7 | 8 |
| 6 | PORTABLE ELECTRONICS | 10 | 19 |
| 7 | MP3 PLAYERS | 11 | 14 |
| 8 | FLASH | 12 | 13 |
| 9 | CD PLAYERS | 15 | 16 |
| 10 | 2 WAY RADIOS | 17 | 18 |
+-------------+----------------------+-----+-----+
Run Code Online (Sandbox Code Playgroud)
你想阅读我链接的文章,完全理解这一点,但我会尝试简短的解释.
如果(子项的"lft"(左)值大于父项的"ltf"值)AND(子项的"rgt"值小于父项的"rgt"值),则项目是另一项目的成员
"Flash"是"MP3播放器","便携式电子产品"和"电子产品"的成员之一
或者说,"便携式电子产品"的成员是:
- MP3播放器
- 闪光灯
- CD播放器
- 双向无线电
Joe Celko有一本关于"SQL中的树和层次结构"的书.有比你想象的更多的选择,但需要做出很多权衡.
注意:永远不要说某些事情无法完成,有些mofo会出现向你展示.
您能澄清一下实体和用户之间的区别吗?否则,你的桌子看起来不错。您假设组和实体之间存在多对多关系。
无论如何,对于标准 SQL,请使用以下查询:
SELECT name, group_id
FROM entities JOIN group_members ON entities.id = group_members.entity_id;
Run Code Online (Sandbox Code Playgroud)
这将为您提供名称和 group_id 的列表,每行一对。如果一个实体是多个组的成员,则该实体将被列出多次。
如果您想知道为什么没有 JOIN 到 groups 表,那是因为 groups 表中没有不在 group_members 表中的数据。例如,如果您在组表中包含了组名称,并且希望显示该组名称,那么您也必须加入组。
某些 SQL 变体具有与报告相关的命令。它们允许您将多个组作为单个实体列在同一行上。但它不是标准的,不能在所有平台上工作。
| 归档时间: |
|
| 查看次数: |
6011 次 |
| 最近记录: |