SQL问题 - 跨多个表(用户组)选择

时间:2010-04-17 17:41:29

标签: sql

我有一个db模式,看起来像这样:

create table user         (id int, name varchar(32));
create table group        (id int, name varchar(32));
create table group_member (group_id int, user_id int, flag int);

我想编写一个允许我这样做的查询:

给定有效的用户ID(UID),获取与指定用户ID(UID)在同一组中的所有用户的ID,并且group_member.flag = 3。

而不仅仅是拥有SQL。我想学习如何像Db程序员一样思考。作为一名程序员,SQL是我最薄弱的环节(因为我对命令式语言比对声明性语言更为满意) - 但我想改变它。

无论如何,这里是我确定的必要步骤来分解任务。如果一些SQL专家可以演示简单的SQL语句(即原子SQL语句,下面是每个已识别的子任务一个语句),最后我将如何组合这些语句来制作实现所需功能的ONE语句,我将不胜感激。

这里(假设指定的user_id [UID] = 1):

//Subtask #1.
Fetch list of all groups of which I am a member

Select group.id from user inner join group_member where user.id=group_member.user_id and user.id=1

//Subtask #2
Fetch a list of all members who are members of the groups I am a member of (i.e. groups in subtask #1)

Not sure about this ...

select user.id from user, group_member gm1,  group_member gm2, ... [Stuck]

//Subtask #3
Get list of users that satisfy criteria group_member.flag=3
Select user.id from user inner join group_member where user.id=group_member.user_id and user.id=1 and group_member.flag=3

一旦我获得了subask2的SQL,我就会想看看如何从这些子任务构建完整的SQL语句(你不必在子任务中使用SQL,它只是解释所涉及的步骤的一种方式 - 另外,我的SQL可能不正确/效率低下,如果是这样,请随时纠正它,并指出它有什么问题。)

由于

3 个答案:

答案 0 :(得分:6)

查询1 - 选择我所属的所有群组。

除非您还想要群组的名称,否则您不需要加入此处。只需查看group_member表格。

SELECT group_id
FROM group_member
WHERE user_id = 1

结果:

1
3

查询2 :选择与我在同一组中的所有用户。

您可以自行加入group_member表以查找彼此位于同一组中的所有用户,然后添加where子句以仅查找与您自己位于同一组中的所有用户。添加DISTINCT以确保您不会让人们两次。

SELECT DISTINCT T2.user_id
FROM group_member AS T1
JOIN group_member AS T2
ON T1.group_id = T2.group_id
WHERE T1.user_id = 1
AND T2.user_id <> 1 -- Remove myself

结果:

2
3
5

查询3 :在任何群组中都有标记3的用户。

您只需要查看group_member表。如果您只想查看每个用户一次,请再次添加DISTINCT

SELECT DISTINCT user_id
FROM group_member
WHERE group_member.flag=3

结果:

2
3
4

最终查询:与我有同一组的用户,拥有标记3。

这与查询2几乎相同,只需添加一个额外的WHERE条件。

SELECT DISTINCT T2.user_id
FROM group_member AS T1
JOIN group_member AS T2
ON T1.group_id = T2.group_id
WHERE T1.user_id = 1
AND T2.user_id <> 1 -- Remove myself
AND T2.flag = 3

结果:

2
3

测试数据:

create table user         (id int, name varchar(32));
create table `group`        (id int, name varchar(32));
create table group_member (group_id int, user_id int, flag int);

insert into user (id, name) VALUES (1, 'user1'), (2, 'user2'), (3, 'user3'), (4, 'user4'), (5, 'user5');
insert into `group` (id, name) VALUES (1, 'group1'),(2, 'group2'), (3, 'group3');
insert into group_member (group_id, user_id, flag) VALUES (1, 1, 0), (1, 2, 3), (1, 3, 3), (2, 3, 3), (2, 4, 3), (2, 5, 0), (3, 1, 0), (3, 5, 0);

答案 1 :(得分:2)

这应该找到具有指定标志的特定用户所在的同一组中的所有人。

SELECT DISTINCT g2.user_id
FROM group_member AS g INNER JOIN group_member AS g2
  ON g.group_id = g2.group_id
WHERE g.user_id = <the userid you want to find>
  AND g2.flag = 3

为了解决这个问题,我做了以下几点:

我们需要比较两个group_member,因为我们想要知道哪些属于同一组,因此我们需要将group_member与自己联系起来。 (在group_id上,因为我们想要同一组中的那些。)

我想确保其中一个是我要比较的用户,然后另一个必须有正确的标记。

完成此操作后,我只需从我与原始用户比较的user_id中取出DISTINCT即可。由于我认为用户可能在另外一个用户所在的两个组中,因此添加user_id也可能是明智之举,以确保我们只从其中获取每个{{1}}一次。

答案 2 :(得分:-1)

SQL的优点在于,您可以将这三个选项与一个有效的连接一起加入。在这种情况下,我使用了WHERE版本的连接,因为我发现它更容易理解。但是你也可以看一下LEFT JOIN和INNER JOIN的语法,因为它们会给你很多表现力。

SELECT * FROM user, group_member, group 
WHERE user.id = group_member.user_id
&& group_member.group_id = group.id
&& group_member.flag = 3