棘手的SQL查询,也许某种联接会起作用吗?

时间:2012-03-29 15:51:43

标签: sql sqlite select

我有一个我正在尝试写的SQL查询,但我不太确定如何让它工作。

我有三个表:“s”,“t”和“st”(这是“s”和“t”之间的映射。

table s
=======
primary key sID   |   val
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
       a              0
       b              1
       c              5
       d              6
       e              7



table t
=======
primary key tID   |   val
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
      nul               -1
      bbb                2
      ccc                3
      ddd                4



table st
========
foreign key sID   |  foreign key tID
(unique)          |  (multiple sID to one tID, meaning tID is not unique)
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
       a                    ddd
       b                    ccc
       c                    nul
       d                    ccc
       e                    bbb

所以,所有的'必须'映射到't',但不是真正的't'的是映射到默认的/ null't'(nul)。

val'在's'和't'都是唯一的,这意味着如果table''的值为1,则表't'不能为1。


所以我的问题如下:

给定一组val(可以是's'或't'),我需要在相应ID的'st'表中获取sID和tID。问题是,如果一个's'在集合中但是't'不在集合中,我需要获取值(sID,'nul')而不是(sID,tID)。

例如,给定值(3,1,6),它将返回对:(b,ccc); (d,CCC);

给定值(0,4),它将返回对:(a,ddd)

但是,给定值(6),它将需要返回(d, nul ),因为val 3(对应于c被映射到的ccc)不在组。我不需要null's',只是null't'。


我正在考虑使用以下语句,但如果只有's'在集合中而不是't',这对我返回“id,nul”没有帮助。

SELECT st.sID, st.tID FROM t, st WHERE t.tID=st.tID AND (t.val=%_VAL1_% OR t.val=%_VAL_2 OR ......);

这给了我任何在集合中同时具有“t”和“s”的东西(实际上它让我所有的'与集合中的任何't'相关联),但它没有给出我是他们自己的's'。

也许我可以对's'中的任何内容进行后期处理,但不能在'st'中进行后处理,但如果可能的话,我想避免这种情况。

有没有人有任何建议?我很困惑。

谢谢!

(注意:s,t和st不是我真正的表名,不用担心。另外,不幸的是,主键实际上是文本GUID,但我试图让它更容易区分)< / em>的

2 个答案:

答案 0 :(得分:3)

这是你想要的:

SELECT s.sID, t.tID
FROM st
    LEFT JOIN s
        ON s.sID = st.sID AND s.val IN (6)
    LEFT JOIN t
        ON t.tID = st.tID AND t.val IN (6)
WHERE NOT(s.sid IS NULL AND t.tid IS NULL)

这是SQLFiddle that proves it for all 3 scenarios。您必须将映射表作为主要表,因为结果集来自可以为null的表。

虽然,这是非常奇怪的逻辑。通常,如果在多对多关系中未映射映射,则只返回0行,而不是部分....

如果要取消多个映射未命中可能出现的重复项(在一个列输出中为null),则添加DISTINCT。像这样:

SELECT DISTINCT s.sID, t.tID
FROM st
    LEFT JOIN s
        ON s.sID = st.sID AND s.val IN (6)
    LEFT JOIN t
        ON t.tID = st.tID AND t.val IN (6)
WHERE NOT(s.sid IS NULL AND t.tid IS NULL)

Here is the fiddle that shows the duplication

And, here is the one that fixes it

AND最后,根据最新更新。如果要排除任何NULL的列,只需将其设为INNER JOIN,然后可以删除NULL检查,因为您不会获得双NULL的现在......如果您确实需要多个sID|NULL结果,请随意删除。

SELECT DISTINCT s.sID, t.tID
FROM st
    JOIN s
        ON s.sID = st.sID AND s.val IN (6)
    LEFT JOIN t
        ON t.tID = st.tID AND t.val IN (6)

Here is the SQLFiddle

答案 1 :(得分:0)

您正在寻找LEFT JOIN

SELECT s.sid AS sid, t.tid AS tid
  FROM s
  LEFT JOIN st
    ON s.sid = st.sid
  LEFT JOIN t
    ON t.tid = st.tid
WHERE s.val IN (3, 1, 6)
  AND t.val IN (3, 1, 6)