不可能有条件的SQL加入?

时间:2017-10-04 01:26:31

标签: mysql sql join

我有2个表,Resources和ChapterMap。

资源表包含教育资源的记录。该表具有一组与主题相关的列(RES_Topic_Sports,RES_Topic_Politics,RES_Topic_CurrentEvents等)。如果其中一个字段的值为1,则资源与该主题相关。

ChapterMap表将主题链接到书中的章节。此表中的每条记录都有一个主题字段,其值为(体育,政治,当前事件等)。它还包含书籍章节的链接(FR_Ch1_Sec1,FR_Ch1_Sec2,FR_Ch2_Sec3等)

我正在尝试在主题上加入这两个表。例如,如果Resources.RES_Topic_Sports = 1,我想加入ChapterMap,其中ChapterMap.Topic ='Sports'。 IF Resources.RES_Topic_Sports = 1 AND Resources.RES_Topic_Politics = 1,我想加入ChapterMap,其中ChapterMap.Topic ='Sports'AND Chapter Chapter.Topic ='Politics'等等。

如果这是最优的话,我也愿意重组表。

我非常感谢任何建议。如果重要,那就是针对全球人权问题的非营利组织。

提前致谢!!

********************样本数据**********************

表:资源
字段: RES_ID,RES_Name,RES_Topic_Sports,RES_Topic_Politics,RES_Topic_CurrentEvents
记录:(101,'体育课计划',1,NULL,1)
说明:与体育和当前活动主题相关的名为“体育课程计划”的资源。

表: CHAPTERMAP
字段: ID,主题,Ch1_Sec1,Ch1_Sec2,Ch1_Sec3,Ch1_Sec4,Ch2_Sec1,Ch2_Sec2,Ch3_Sec1,Ch3_Sec2,Ch3_Sec3
记录:(4,'运动',NULL,NULL,NULL,NULL,1,NULL,NULL,1,1)
说明:将“体育”主题与第2章第1节和第3章第2节以及第3章第3节相关联的映射。

目标:将资源“体育课程计划”链接到第2章第1节和第3章第2节以及第3章第3节。

3 个答案:

答案 0 :(得分:2)

首先需要重构表以规范化数据库。您应该拥有一个主题表,一个资源表和一个连接表,而不是为每个主题添加一列,该连接表存储将哪些主题分配给哪些资源。您应该将相同的主题分配给章节。

例如,请考虑以下表格:

         TOPIC:  ID     NAME
                 ----------------------------------------------------------
                 1      Sports
                 2      Politics


      RESOURCE:  ID     (any other fields you need, i.e. description, etc.)
                 ----------------------------------------------------------
                 1      blah  blah
                 2      blah  blah


RESOURCE_TOPIC:  RESOURCE_ID    TOPIC_ID
                 ----------------------------------------------------------
                 1              2
                 2              1
                 2              2


       CHAPTER:  ID   (any other fields you need)
                 ----------------------------------------------------------
                 Ch1_Sec1      blah blah
                 Ch1_Sec2      blah blah
                 Ch1_Sec1      blah blah


 CHAPTER_TOPIC:  CHAPTER_ID     TOPIC_ID
                 ----------------------------------------------------------
                 Ch1_Sec1       1
                 Ch1_Sec2       2
                 Ch1_Sec1       1

现在,您可以轻松编写JOIN语句,将资源与共享 ANY 常见主题的章节进行匹配:

SELECT
    r.ID AS RESOURCE_ID,
    c.ID AS CHAPTER_ID
    -- any other fields you need
FROM RESOURCE r
JOIN RESOURCE_TOPIC rt ON rt.RESOURCE_ID = r.ID
JOIN CHAPTER_TOPIC ct ON ct.TOPIC_ID = rt.TOPIC_ID
JOIN CHAPTER c ON c.ID = ct.CHAPTER_ID
GROUP BY
    r.ID AS RESOURCE_ID,
    ct.CHAPTER_ID
    -- any other fields you need

如果您想将资源与所有主题匹配的章节相匹配,那么它会更复杂但可行。我不能完全确定您的问题是否符合您的要求,但如果是,请告诉我,我也会提供该查询。

关于规范数据库的一点点

有很多很好的理由来规范化您的数据库,但这里有一些要点:

  • 根据您当前的设置,每次有新主题和/或章节时,您都必须不断向表中添加新列。显然,这些表格会很快爆炸到一个荒谬的列数(正如你所提到的)

  • 此方法可让您轻松添加或删除主题和章节,而无需更改表格结构

  • 根据您当前设置的常见主题,几乎不可能加入资源和章节。规范化表使查询更简单。

  • 如果要重命名主题,则只需更新主题表中的一行,而不是在使用它的任何位置更新它。

答案 1 :(得分:1)

准备"样本数据"你需要考虑" 这是否代表了所需的所有条件?",例如我是否包含所有主题?即每张桌子一行是不够的。

一旦确定了一些样本数据,您还需要努力显示预期结果" - 应该从提供的样本数据中实现。当然,手动准备预期结果是很正常的,因为您可能没有所需的查询。 (但是,您还应该证明您已经绑定了查询。)

无论如何,下面是我对你的问题代表什么的猜测,并补充了样本数据以涵盖更多情况。 SQL Fiddle

MySQL 5.6架构设置

CREATE TABLE RESOURCES
    (`RES_ID` int, `RES_Name` varchar(18), `RES_Topic_Sports` int, `RES_Topic_Politics` varchar(4), `RES_Topic_CurrentEvents` int)
;

INSERT INTO RESOURCES
    (`RES_ID`, `RES_Name`, `RES_Topic_Sports`, `RES_Topic_Politics`, `RES_Topic_CurrentEvents`)
VALUES
    (101, 'Sports Lesson Plan', 1, 1, 1),
    (201, 'Sports Lesson Plan', 1, NULL, NULL),
    (301, 'Political treatse', NULL, 1, NULL),
    (401, 'Event unfolding', NULL, NULL, 1)
;

CREATE TABLE CHAPTERMAP
    (`ID` int, `Topic` varchar(60), `Ch1_Sec1` varchar(4), `Ch1_Sec2` varchar(4), `Ch1_Sec3` varchar(4), `Ch1_Sec4` varchar(4), `Ch2_Sec1` int, `Ch2_Sec2` varchar(4), `Ch3_Sec1` varchar(4), `Ch3_Sec2` int, `Ch3_Sec3` int)
;

INSERT INTO CHAPTERMAP
    (`ID`, `Topic`, `Ch1_Sec1`, `Ch1_Sec2`, `Ch1_Sec3`, `Ch1_Sec4`, `Ch2_Sec1`, `Ch2_Sec2`, `Ch3_Sec1`, `Ch3_Sec2`, `Ch3_Sec3`)
VALUES
    (4, 'Sports', NULL, NULL, NULL, NULL, 1, NULL, NULL, 1, 1),
    (104, 'Politics', NULL, NULL, NULL, NULL, 1, NULL, NULL, 1, 1),
    (401, 'Current Events', NULL, NULL, NULL, NULL, 1, NULL, NULL, 1, 1)
;

查询1

select
*
from RESOURCES r
left join CHAPTERMAP c on (r.RES_Topic_Politics = 1      and c.Topic = 'Politics')
                       or (r.RES_Topic_Sports = 1        and c.Topic = 'Sports')
                       or (r.RES_Topic_CurrentEvents = 1 and c.Topic = 'Current Events') 
order by r.res_id, c.id

<强> Results

| RES_ID |           RES_Name | RES_Topic_Sports | RES_Topic_Politics | RES_Topic_CurrentEvents |  ID |          Topic | Ch1_Sec1 | Ch1_Sec2 | Ch1_Sec3 | Ch1_Sec4 | Ch2_Sec1 | Ch2_Sec2 | Ch3_Sec1 | Ch3_Sec2 | Ch3_Sec3 |
|--------|--------------------|------------------|--------------------|-------------------------|-----|----------------|----------|----------|----------|----------|----------|----------|----------|----------|----------|
|    101 | Sports Lesson Plan |                1 |                  1 |                       1 |   4 |         Sports |   (null) |   (null) |   (null) |   (null) |        1 |   (null) |   (null) |        1 |        1 |
|    101 | Sports Lesson Plan |                1 |                  1 |                       1 | 104 |       Politics |   (null) |   (null) |   (null) |   (null) |        1 |   (null) |   (null) |        1 |        1 |
|    101 | Sports Lesson Plan |                1 |                  1 |                       1 | 401 | Current Events |   (null) |   (null) |   (null) |   (null) |        1 |   (null) |   (null) |        1 |        1 |
|    201 | Sports Lesson Plan |                1 |             (null) |                  (null) |   4 |         Sports |   (null) |   (null) |   (null) |   (null) |        1 |   (null) |   (null) |        1 |        1 |
|    301 |  Political treatse |           (null) |                  1 |                  (null) | 104 |       Politics |   (null) |   (null) |   (null) |   (null) |        1 |   (null) |   (null) |        1 |        1 |
|    401 |    Event unfolding |           (null) |             (null) |                       1 | 401 | Current Events |   (null) |   (null) |   (null) |   (null) |        1 |   (null) |   (null) |        1 |        1 |

答案 2 :(得分:1)

您感兴趣的主题是数据库规范化。要理解,请考虑您在章节地图表中需要一个列,用于您希望数据库涵盖的每本书每章的每个部分

考虑使用名为&#34; Topics&#34;的第三个表。在该表中有两列:topicID和topicName。一个典型的条目是&#39; 1&#39;体育&#39; (&#39; 2&#39;,&#39;政治&#39;等......)。

现在,摆脱&#34;资源&#34;中的所有主题相关列。表。现在,您在参考资料中的行看起来像是&#39; 101&#39;,&#39;体育课计划&#39;。

还有一个要规范化的表:让我们改变你的&#34; Chaptermap&#34;表只包含以下列:ID,章节和部分。典型的行看起来像&#39; 5&#39;,&#39; 2&#39;,&#39; 1&#39;,将ID 5提供给第2章第1节。

我们要将主题内容规范化为另外几个表,以防资源或章节与多个主题(多对多关系)相关。为此,您将再创建两个表:resourceTopics和sectionTopics。 resourceTopics将有两列 - resourceID和topicID。 sectionTopics是相同的交易 - sectionID和topicID。

您的应用程序会在resourceTopics表中添加一行&#39; 101&#39;&#39; 1&#39;表示资源101(体育课程计划)与主题1(体育)相关联。同样,您还要在sectionTopics表&#39; 5&#39;,&#39; 1&#39;中添加一行。显示第5节(第2章,第1节)和主题1(运动)之间的联系。

现在,如果您查询:

SELECT
r.RES_NAME, 
c.chapter,
c.section
FROM CHAPTERMAP c
INNER JOIN sectionTopics st
ON st.sectionID = c.id
INNER JOIN resourceTopics rt
ON rt.topicID = st.topicID
INNER JOIN Resources r
ON r.RES_ID = rt.resourceID
INNER JOIN Topics t
ON t.topicID = st.topicID
WHERE st.topicName = 'sports'

你应该得到你正在寻找的结果。