根据来自另一个 table 的匹配行查找 table 中的行集
Finding set of rows in table based on matching rows from another table
我知道这个主题充其量有点模糊,但找不到更好的方法来描述我的问题...
举个例子,我有下面两个表:
表A
IdA
Code
Value
123
A
1
123
B
2
123
C
3
456
A
4
456
F
6
456
E
7
...
表B
IdB
Code
Value
X
A
1
X
B
2
X
C
3
Y
G
2
Y
D
8
Y
C
3
Z
A
1
Z
B
2
Z
C
3
Z
D
5
...
TableA 中给定 IdA 的一组记录与 TableB 中具有特定 IdB 的一组等效记录相关联。
例如,对于表 A 中的 IdA = 123,我正好有三行具有某些代码和值,这将“映射”到表 B 中具有 IDB = X 的行,因为它具有相同的代码和值组合,并且行数相同。请注意,它不会映射到 TableB 中的 IdB = Z,因为它有一个代码 D 的额外行,而 IdA = 123 在 TableA 中没有。
仅给定 IdA,如何最好地编写查询来查找 IdB?
如果知道代码和值,我可以做类似的事情:
SELECT b.IdB FROM TableB b
WHERE
EXISTS(SELECT * FROM TableB x WHERE x.IdB = b.IdB AND x.Code = 'A' AND x.Value = '1') AND
EXISTS(SELECT * FROM TableB x WHERE x.IdB = b.IdB AND x.Code = 'B' AND x.Value = '2') AND
EXISTS(SELECT * FROM TableB x WHERE x.IdB = b.IdB AND x.Code = 'C' AND x.Value = '3') AND
(SELECT COUNT(*) FROM TableB x WHERE x.IdB = b.IdB) = 3
但现在我只获得了 IdA 的值,因此我需要从 TableA 中查找值并将其合并到 TableB 的查询中。关于如何解决这个问题有什么聪明的想法吗?
这是Relational Division Without Remainder的问题。
有很多解决方案,这里是一个:
- 采取
TableB
并离开加入 TableA
- 但是计算 A
中整组值的总和
- 分组依据
IdB
- 过滤,所以我们只有总计数等于与 A 的匹配数的行(因为
COUNT(IdA)
只计算非空值)并且总计数也必须与总数相同我们要匹配的行数。
DECLARE @idA int = 123;
SELECT
b.IdB
FROM TableB b
LEFT JOIN (
SELECT *,
total = COUNT(*) OVER ()
FROM TableA a
WHERE a.IdA = @idA
) a ON b.Code = a.Code AND b.Value = a.Value
GROUP BY
b.IdB
HAVING COUNT(*) = COUNT(a.IdA)
AND COUNT(*) = MIN(a.total);
我知道这个主题充其量有点模糊,但找不到更好的方法来描述我的问题...
举个例子,我有下面两个表:
表A
IdA | Code | Value |
---|---|---|
123 | A | 1 |
123 | B | 2 |
123 | C | 3 |
456 | A | 4 |
456 | F | 6 |
456 | E | 7 |
... |
表B
IdB | Code | Value |
---|---|---|
X | A | 1 |
X | B | 2 |
X | C | 3 |
Y | G | 2 |
Y | D | 8 |
Y | C | 3 |
Z | A | 1 |
Z | B | 2 |
Z | C | 3 |
Z | D | 5 |
... |
TableA 中给定 IdA 的一组记录与 TableB 中具有特定 IdB 的一组等效记录相关联。
例如,对于表 A 中的 IdA = 123,我正好有三行具有某些代码和值,这将“映射”到表 B 中具有 IDB = X 的行,因为它具有相同的代码和值组合,并且行数相同。请注意,它不会映射到 TableB 中的 IdB = Z,因为它有一个代码 D 的额外行,而 IdA = 123 在 TableA 中没有。
仅给定 IdA,如何最好地编写查询来查找 IdB?
如果知道代码和值,我可以做类似的事情:
SELECT b.IdB FROM TableB b
WHERE
EXISTS(SELECT * FROM TableB x WHERE x.IdB = b.IdB AND x.Code = 'A' AND x.Value = '1') AND
EXISTS(SELECT * FROM TableB x WHERE x.IdB = b.IdB AND x.Code = 'B' AND x.Value = '2') AND
EXISTS(SELECT * FROM TableB x WHERE x.IdB = b.IdB AND x.Code = 'C' AND x.Value = '3') AND
(SELECT COUNT(*) FROM TableB x WHERE x.IdB = b.IdB) = 3
但现在我只获得了 IdA 的值,因此我需要从 TableA 中查找值并将其合并到 TableB 的查询中。关于如何解决这个问题有什么聪明的想法吗?
这是Relational Division Without Remainder的问题。
有很多解决方案,这里是一个:
- 采取
TableB
并离开加入TableA
- 但是计算 A 中整组值的总和
- 分组依据
IdB
- 过滤,所以我们只有总计数等于与 A 的匹配数的行(因为
COUNT(IdA)
只计算非空值)并且总计数也必须与总数相同我们要匹配的行数。
DECLARE @idA int = 123;
SELECT
b.IdB
FROM TableB b
LEFT JOIN (
SELECT *,
total = COUNT(*) OVER ()
FROM TableA a
WHERE a.IdA = @idA
) a ON b.Code = a.Code AND b.Value = a.Value
GROUP BY
b.IdB
HAVING COUNT(*) = COUNT(a.IdA)
AND COUNT(*) = MIN(a.total);