基于表格的条件连接更进一步

时间:2012-05-02 12:01:50

标签: mysql

我正在尝试编写一个MySQL查询,该查询将连续三个表连接到主表,但这有条件地基于最后一个表的连接值。我试图做的两种方式都有问题:

  • 我需要的所有主要行都不会显示
  • 或者我在那里得到了一些额外无关的行。

表结构是现有系统的一部分,我无法更改它。一旦我弄清楚SQL,我将不得不找到一种方法将它与它的查询系统集成,所以SQL越简单越好!

我将在这里提出很多细节,对不起,这是一篇很长的帖子,但我认为最好包含所有信息。

以下是更多信息:

数据模型:

存在用户,课程和中间内容类型,其存储特定课程上的每个用户的用户信息,称为cui。 我需要查看所有用户的列表,如果有该用户和课程的cui,也要包含它。

在数据库中,cui的字段内容存储在单独的表中,并通过cui_id连接,这是麻烦的一部分。

剥离数据库结构:

  • 主要表格:user(字段:uid,name)
  • Cui table:node(fields:cui_id)
  • 用户字段表(字段:cui_id,uid)
  • 课程字段表(字段:cui_id,course_id)

加入

user     user_field         node         course_field
----     ----------         -------      ------------
uid ==== uid          
name     cui_id =========== cui_id ===== cui_id
                                         course_id    = 202

尝试查询:

以下查询在具有以下用户的小样本数据集上运行:

  • 用户二:有一个课程的cui,并且有美食 其他课程。
  • 用户一:有其他课程的美食,但没有 一个人质疑。
  • 用户六:没有美食。

第一个查询是最后一个表上的条件连接,问题是它包含一个额外的行,用户2不是正确的cui。 我不想要GROUP BY,因为我认为它不一定会给我正确的行。

SELECT user.uid, user.name, field_user.cui_id,
field_course.course_id
FROM user
LEFT JOIN field_user
ON
user.uid = field_user.uid
LEFT JOIN node AS cui
ON
cui.id = field_user.cui_id
LEFT JOIN field_course
ON
field_course.cui_id = cui.id
AND
field_course.course_id = 202

结果:

uid     name        cui_id  course_id
---------------------------------------------
4       User One    772     NULL
5       User Two    434     202
5       User Two    771     NULL
35      User Six    NULL    NULL

另一种选择是:

SELECT user.uid, user.name, field_user.cui_id,
field_course.course_id
FROM user
LEFT JOIN field_user
ON
user.uid = field_user.uid
LEFT JOIN node AS cui
ON
cui.id = field_user.cui_id
LEFT JOIN field_course
ON
field_course.cui_id = cui.id
WHERE (
field_course.course_id = 202 OR ISNULL(field_course.course_id))

结果:

uid     name    cui_nid     course_nid
---------------------------------------------
5       User Two    434     202
35      User Six    NULL    NULL

麻烦的是它遗漏了用户一,因为用户一确实有其他的美食,只是没有正确的课程。

所以问题是,我该如何得到这个?

uid     name        cui_id  course_id
--------------------------------------------
4       User One    772     NULL
5       User Two    434     202
35      User Six    NULL    NULL

1 个答案:

答案 0 :(得分:1)

真的不是那么漂亮但是应该这样做:

-- Select to get all users irrespective of whether they have a row in field_course or field_user
SELECT user.uid, user.name, field_user.cui_id,
null as course_id
FROM user
LEFT JOIN field_user ON user.uid = field_user.uid
LEFT JOIN node AS cui ON cui.id = field_user.cui_id 
where user.uid not in
(
-- Inline view to get only users that have both a field_course & field_user row
SELECT user.uid
FROM user
INNER JOIN field_user ON user.uid = field_user.uid
INNER JOIN node AS cui ON cui.id = field_user.cui_id
INNER JOIN field_course ON field_course.cui_id = cui.id
where field_course.course_id = 202
)
union all
-- Select to get only users that have both a field_course & field_user row
SELECT user.uid, user.name, field_user.cui_id,
field_course.course_id
FROM user
INNER JOIN field_user ON user.uid = field_user.uid
INNER JOIN node AS cui ON cui.id = field_user.cui_id
INNER JOIN field_course ON field_course.cui_id = cui.id
where field_course.course_id = 202;

修改

以下是我用来测试的表结构和数据:

CREATE TABLE `user` (
  `uid` int(10) unsigned NOT NULL,
  `name` varchar(20) NOT NULL
);

CREATE TABLE `node` (
`id` int(10) unsigned not null primary key
);

CREATE TABLE `field_user` (
  `uid` int(10) unsigned NOT NULL,
  `cui_id` int(10) unsigned NOT NULL
);

CREATE TABLE `field_course` (
  `uid` int(10) unsigned NOT NULL,
  `cui_id` int(10) unsigned NOT NULL,
`course_id` int(10) unsigned NOT NULL
);

insert into user (uid,name) values (4,"User One");
insert into user (uid,name) values (5,"User Two");
insert into user (uid,name) values (35,"User Six");

insert into node (id) values (771);
insert into node (id) values (772);
insert into node (id) values (434);

insert into field_user (uid,cui_id) values (4,772);
insert into field_user (uid,cui_id) values (5,434);
insert into field_user (uid,cui_id) values (5,771);

insert into field_course (uid,cui_id,course_id) values (5,434,202);