SQL根据一个表中的行而不是另一个表更新并连接三个表

时间:2012-03-09 16:32:37

标签: c++ sql sqlite join

我需要做一些复杂的SQL查询,而且我有点卡住了。我正在使用SQLite,如果它改变了什么。

我有以下表结构:

Table G
---------
G_id (primary key) | Other cols ...
====================================
        21
        22
        23
        24
        25
        26
        27 (no g_to_s_map)
        28 

Table S
---------
S_id (primary key) |  S_num  | Other cols.....
====================================
        1              1101
        2              1102
        3              1103
        4              1104
        5              1105
        6              1106
        7              1107      (no g_to_s_map, no s_to_t_map)
        8              1108      (no g_to_s_map, there IS an s_to_t_map)
        9              1109      (there is an g_to_s_map, but no s_to_t map)

Table T
---------
T_id (primary key) | Other cols...
==================================
        1
        2

然后我还有两个映射表:

Table G_to_S_Map (1:1 mapping, unique values of both g_id and s_id)
----------
G_id (foreign key ref g)| S_id (foreign key ref s)
===================================================
           21                        1  
           22                        2  
           23                        3  
           24                        4  
           25                        5  
           26                        6  
           28                        9

Table S_to_T_Map (many:1 mapping, many unique s_id to a t_id)
----------
S_id (foreign key ref s) | T_id (foreign key ref s)
===================================================
           1                         1    
           2                         1    
           3                         1    
           4                         2    
           5                         2    
           6                         2 
           8                         2

只有 T_id G_id ,我需要能够使用第一个 S_id G_to_S_Map strong>对应于指定的 T_id (在 S_to_T_Map 中),不在 G_to_S_Map

我想到的第一件事就是在 S_to_T_Map 中获得与 T_id 相对应的 S_id

SELECT S_id FROM S_to_T_Map where T_id = GIVEN_T_ID;

然后假设我会以某种方式使用左/右连接以 G_to_S_Map 加入这些值,然后查找其中一侧不存在的第一个值?然后我需要根据 S_id GIVEN_G_ID 值等插入 G_to_S_Map

有关如何解决这个问题的任何建议?谢谢!


编辑:添加了一些虚拟数据:

2 个答案:

答案 0 :(得分:2)

我相信这应该有效:

INSERT INTO G_To_S_Map (G_id, S_id) 
          (SELECT :inputGId, a.S_id
           FROM S_To_T_Map as a
           LEFT JOIN G_To_S_Map as b
           ON b.S_id = a.S_id
           AND b.G_id = :inputGId
           WHERE a.T_id = :inputTId
           AND b.G_id IS NULL
           ORDER BY a.S_id
           LIMIT 1);

<小时/> 编辑:

如果您想要通过其他表格执行订单,请使用以下版本:

INSERT INTO G_To_S_Map (G_id, S_id) 
          (SELECT :inputGId, a.S_id
           FROM S_To_T_Map as a
           JOIN S as b
           ON b.S_id = a.S_id
           LEFT JOIN G_To_S_Map as c
           ON c.S_id = a.S_id
           AND c.G_id = :inputGId
           WHERE a.T_id = :inputTId
           AND c.G_id IS NULL
           ORDER BY b.S_num
           LIMIT 1);

(顺便说一句,我真的希望你的表格不是实际这样命名,因为这是一件非常糟糕的事情。Map的使用尤其应该可能可以避免)

<小时/> 编辑:

这是一些示例测试数据。我错过了什么吗?我是否错误地概念化了这种关系?

S_To_T_Map
================
S_ID    T_ID    
   1       1    
   2       1    
   3       1    
   1       2    
   1       3    
   3       3 

G_To_S_Map
==================   
G_ID    S_ID  
   1       1  
   3       1  
   2       1  
   3       2  
   2       3  
   3       3  

产生的联合数据:
(CTE用于生成交叉连接测试数据)

Results:
=============================
G_TEST    T_TEST    S_ID 
     1         1       3 
     2         1       2 
     1         3       3 

<小时/> 编辑:

啊,好吧,现在我遇到了问题。我的问题是我假设SG之间存在某种多方关系。由于情况并非如此,请使用此修订声明:

INSERT INTO G_To_S_Map (G_id, S_id)  
      (SELECT :inputGId, a.S_id 
       FROM S_To_T_Map as a 
       JOIN S as b 
       ON b.S_id = a.S_id 
       LEFT JOIN G_To_S_Map as c 
       ON c.S_id = a.S_id 
       OR c.G_id = :inputGId
       WHERE a.T_id = :inputTId 
       AND c.G_id IS NULL 
       ORDER BY b.S_num 
       LIMIT 1); 

特别是,需要将包含G_To_S_Map的行检查G_Id的行从使用AND切换为OR - 关键要求之前未指定的G_IdS_IdG_To_S_Map中唯一的事实。
如果先前已映射提供的G_Id,或者映射到给定S_Id的所有T_Id已映射,则此语句不会插入行。

答案 1 :(得分:0)

嗯,以下似乎很好用,虽然我还没有把“插入”与它结合起来。

Select s.S_ID from S as s 
inner join(
    Select st.S_ID from s_to_t_map as st 
    where st.T_ID=???? AND not exists
                    (Select * from g_to_s_Map as gs where gs.S_ID = st.S_ID)
 ) rslt on s.S_ID=rslt.S_ID  ORDER BY s.s_Num ASC limit 1;