【问题标题】:Multiple SQL joins difficult query多条SQL连接难查询
【发布时间】:2015-03-25 07:16:50
【问题描述】:

我有一个奇怪的架构,但在设计时它在当时似乎是个好主意。我有一个 master 表,lesson_objects,它具有链接到词汇表、视频表和测验表的外键。

词汇表:

CREATE TABLE `se_vocab` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `vocab_word` VARCHAR(255) NOT NULL,
    `vocab_audio` INT(10) NULL DEFAULT '0',
    `vocab_image` INT(10) NULL DEFAULT '0',
    PRIMARY KEY (`id`)
)

视频表:

CREATE TABLE `se_video` (
    `id` INT(10) NOT NULL AUTO_INCREMENT,
    `video_name` VARCHAR(255) NOT NULL,
    `video_description` MEDIUMTEXT NOT NULL,
    `video_file_name` VARCHAR(50) NULL DEFAULT NULL,
    `video_url` VARCHAR(255) NOT NULL,
    PRIMARY KEY (`id`)
)

测验表:

CREATE TABLE `se_quizzes` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `quiz_name` VARCHAR(80) NOT NULL,
    `quiz_description` TINYTEXT NULL,
    PRIMARY KEY (`id`)
)

课程对象(包含以前表的外键)

CREATE TABLE `se_lesson_org` (
    `id` INT(10) NOT NULL AUTO_INCREMENT,
    `lesson_id` INT(10) NOT NULL,
    `section_object_type` ENUM('video','vocabulary','quiz') NOT NULL,
    `section_object_id` INT(10) NOT NULL,
    PRIMARY KEY (`id`)
)

我正在尝试创建一个查询,该查询返回来自课程对象的所有记录,但还包括该记录中类型(词汇等)的列中的数据

例如:

只有我的查询不返回任何行,而理想情况下它应该变成多行,每条记录都包含一些空列。例如。如果不是词汇,则测验和视频的列将为空。

我的尝试非常糟糕,但为了指导,这里有一个:

SELECT 
    lo.id, lo.section_object_type, lo.section_object_id, 
    vo.id, vo.vocab_text, vo.vocab_image, vo.vocab_audio
    vi.id, vi.video_name, vi.video_url,
    q.id, q.quiz_name
    FROM se_lesson_org lo, se_vocab vo, se_video vi, se_quizzes q
    WHERE lo.section_object_id = vo.id 
    OR lo.section_object_id = vi.id
    OR lo.section_object_id = q.id

任何帮助/cmets 将不胜感激。谢谢。

【问题讨论】:

  • 显示示例数据或创建一个 sqlfiddle
  • 请发布预期的结果格式。
  • MySQL 或/和 SQL Server?不要标记未涉及的产品!
  • @jarlh 从技术上讲,它是 Google SQL 存储,但这不是一个选项,所以它是 SQL 和 mysql 的混合体(我最好的选择)。抱歉,我没有尝试发送垃圾邮件。

标签: mysql sql sql-server join inner-join


【解决方案1】:

使用LEFT JOIN 返回来自se_lesson_org 的所有行。此外,添加JOIN 条件以匹配特定的section_object_type

SELECT
    lo.*,
    vo.*,
    vi.*,
    q.*
FROM se_lesson_org lo
LEFT JOIN se_vocab vo
    ON vo.id = lo.section_object_id
    AND lo.section_object_type = 'vocabulary'
LEFT JOIN se_video vi
    ON vi.id = lo.section_object_id
    AND lo.section_object_type = 'video'
LEFT JOIN se_quizzes q
    ON q.id = lo.section_object_id
    AND lo.section_object_type = 'quiz'

注意:避免使用旧式 JOIN 语法。阅读 Aaron Bertrand 的 article

【讨论】:

  • 很棒的东西。完美运行。我会看看那篇文章。谢谢!
  • 没问题,很高兴我能帮上忙。
  • 好文章,@wewestthemenace。他说*=, =*是什么意思?可能是一个愚蠢的问题,但我在他引用的查询中没有看到它......
  • 这只是OUTER JOIN 的旧式语法。请注意,这篇文章是针对SQL Server (MSSQL) 但该原理可以应用于所有 RDBM。
【解决方案2】:

听起来您正在这些表格中的每一个上寻找LEFT JOIN。这样,如果外键有效,您将显示值,如果它无效,您将只获得相关列的 NULL。

SELECT 
    lo.id, lo.section_object_type, lo.section_object_id, 
    vo.id, vo.vocab_text, vo.vocab_image, vo.vocab_audio
    vi.id, vi.video_name, vi.video_url,
    q.id, q.quiz_name
    FROM se_lesson_org lo
    LEFT JOIN se_vocab vo ON vo.id = lo.section_object_id 
        AND lo.section_object_type = 'vocabulary'
    LEFT JOIN se_video vi ON vi.id = lo.section_object_id 
        AND lo.section_object_type = 'video'
    LEFT JOIN se_quizzes q ON q.id = lo.section_object_id 
        AND lo.section_object_type = 'quiz'

还要注意这种语法如何清楚地表明每个表是如何连接到查询的其余部分的,而不是在最后的 WHERE 子句中出现一堆乱七八糟的条件。

【讨论】:

  • 效果很好,感谢您的解释。我想这就是我这个学期要上 SQL 课的原因。
猜你喜欢
  • 1970-01-01
  • 2018-03-08
  • 2020-03-25
  • 2016-02-17
  • 1970-01-01
  • 2012-04-27
  • 2023-04-08
  • 1970-01-01
  • 2017-10-11
相关资源
最近更新 更多