Обновление SQL и объединение трех таблиц на основе строк в одной таблице, а не в другой - PullRequest
1 голос
/ 09 марта 2012

У меня есть немного сложный 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 , мне нужно иметь возможность обновить G_to_S_Map с первым S_id , соответствующим указанный T_id S_to_T_Map ), который НЕ находится в G_to_S_Map

Первое, о чем я думал, это просто получить любые S_id , которые соответствуют T_id в S_to_T_Map :

SELECT S_id FROM S_to_T_Map where T_id = GIVEN_T_ID;

Тогда, предположительно, я бы как-то соединил эти значения с G_to_S_Map , используя, возможно, левое / правое соединение, а затем искал бы первое значение, которого не существует на одной из сторон? Затем мне нужно сделать вставку в G_to_S_Map на основе этого S_id и значения GIVEN_G_ID или чего-то еще.

Есть предложения, как это сделать? Спасибо!


Редактировать: Добавлены некоторые фиктивные данные:

Ответы [ 2 ]

2 голосов
/ 09 марта 2012

Я считаю, что это должно работать:

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, особенно, должно , вероятно, следует избегать)

<ч /> EDIT:

Вот несколько примеров тестовых данных. Я что-то пропустил? Я неправильно осмыслил отношения?

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 

<ч /> РЕДАКТИРОВАТЬ:

Ах, хорошо, теперь у меня проблема. Моя проблема заключалась в том, что я предполагал, что между S и G были какие-то отношения типа «один-один». Поскольку это не так, используйте это исправленное утверждение:

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_Id и S_Id были уникальными в G_To_S_Map.
Этот оператор не вставит строку, если либо предоставленный G_Id был сопоставлен ранее, либо если все S_Id сопоставлены с данным T_Id, были сопоставлены.

0 голосов
/ 09 марта 2012

Хм, похоже, что следующее работает хорошо, хотя я еще не комбинировал с ним "вставку".

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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...