我需要执行一些复杂的 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> 对应于不在 G_to_S_Map
中的指定 T_id(在 S_to_T_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 中。
关于如何解决这个问题有什么建议吗?谢谢!
编辑:添加了一些虚拟数据:
最佳答案
我相信这应该有效:
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
编辑:
啊,好的,现在我明白了。我的问题是我假设 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
之前已被映射,或者如果映射到给定 T_Id
的所有 S_Id
已被映射,则此语句不会插入一行映射。
关于c++ - SQL根据一个表中的行而不是另一个表中的行更新和连接三个表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9637603/