我有两张桌子:
create table doi (
id number primary key not null,
-- Other columns omitted
);
create table doi_membership (
id number primary key not null,
doi_id number not null, --foreign key to doi.id
key_1 number not null,
key_2 number not null,
-- Other columns omitted
);
我有一组key_1,key_2对,我想知道是否有一个doi包含给定key_1,key_2对的完整集合,仅此而已。我似乎无法想到执行此操作所必需的SQL。如果有帮助,我正在使用oracle数据库。有什么想法吗?
更新
我认为我没有很好地解释这一点,所以我会举一个例子。
从概念上讲,单个DOI包含key_1,key_2对的列表。我有自己的key_1,key_2对列表,我想知道是否存在一个DOI,其中的对列表与我的对列表完全匹配。
因此,假设有一个DOI具有以下key_1,key_2对列表(这些行中的每一行都是与同一个doi相关的单独的doi_membership行):
1, 2
3, 4
5, 6
另一个DOI,其中包含以下列表:
1, 2
3, 4
5, 6
7, 8
我拥有的那对配对
1, 2
3, 4
5, 6
我想匹配给出的第一个DOI,因为它的对和我的一组对完全匹配。第二个DOI应不匹配。
我希望能够解决问题。
答案 0 :(得分:1)
我认为处理集合成员资格的最佳方法是在SQL中使用HAVING
子句。我们的想法是将集合的元素组合在一起,在本例中为每个doi的成员资格记录,然后在个人层面进行测试。
例如,以下having子句将检查keyval1是否存在:
having sum(case when keyval_1 = <keyval1> then 1 else 0 end) > 0
它通过将记录数与keyval_1 = <keval1>
相加来实现。如果大于0,则“doi_id”符合条件。
你的条件有点复杂,因为你正在寻找成对的价值观。解决这个问题的一种方法是将值连接在一起(不是必需的,但它有点简化了逻辑)。以下子句验证doi_id上仅存在您的值对:
having sum(case when concat(key_1, ',', key_2) in (<key value pairs here>)
then 0 else 1 end) = 0
它的作用是计算密钥对不匹配的记录数。如果有,则比较失败。您需要为in子句连接键值对。类似于in ('1,1', '2,2', '3,14')
。
为了概括所有匹配的条件,我使用以下内容:
select doi_id
from doi_membership
group by doi_id
having sum(case when concat(key_1, ',', key_2) in (<key value pairs here>)
then 0 else 1 end) = 0 and
sum(case when concat(key_1, ',', key_2) = <key pair 1>
then 1 else 0 end) > 0 and
sum(case when concat(key_1, ',', key_2) = <key pair 2>
then 1 else 0 end) > 0 and
. . .
sum(case when concat(key_1, ',', key_2) = <key pair n>
then 1 else 0 end)
HAVING
子句首先测试所有对都存在。然后剩余的条款测试每对的存在。
还有其他方法。我发现HAVING
子句是最通用的,因为它可以适应集合的包含标准的各种逻辑。
答案 1 :(得分:1)
假设您的密钥对列表存储在一个表中,这是您可以考虑的另一种方法:
SELECT m.doi_id
FROM doi_membership m
LEFT JOIN sample_key_set s
ON m.key_1 = s.key_1 AND m.key_2 = s.key_2
GROUP BY m.doi_id
HAVING COUNT(*) = ALL(
COUNT(s.key_1),
(SELECT COUNT(*) FROM sample_key_set)
)
;
查询外部将doi_membership
连接到对的样本列表,按doi_id
对结果集进行分组,并将组中的总行数与匹配行的总数进行比较,以及与样本对的总数。如果所有计数相等,则返回相应的doi_id
。
如果你不知道ALL谓词,这个条件
COUNT(*) = ALL(
COUNT(s.key_1),
(SELECT COUNT(*) FROM sample_key_set)
)
只是
的捷径 COUNT(*) = COUNT(s.key_1)
AND COUNT(*) = (SELECT COUNT(*) FROM sample_key_set)
为了表明该方法有效,下面分析了各种例子:
# Rows in "m" Rows in "s" Count values Outcome
-- ----------- ----------- -------------------- -------
1 1, 2 1, 2 COUNT(*) =2 MATCH
3, 4 3, 4 COUNT(s.key_1) =2
SELECT COUNT(*)...=2
-- ----------- ----------- -------------------- -------
2 1, 2 1, 2 COUNT(*) =1 NO
3, 4 COUNT(s.key_1) =1 MATCH
SELECT COUNT(*)...=2
-- ----------- ----------- -------------------- -------
3 1, 2 1, 2 COUNT(*) =2 NO
5, 6 3, 4 COUNT(s.key_1) =1 MATCH
SELECT COUNT(*)...=2
-- ----------- ----------- -------------------- -------
4 1, 2 1, 2 COUNT(*) =3 NO
3, 4 3, 4 COUNT(s.key_1) =2 MATCH
5, 6 SELECT COUNT(*)...=2
如您所见,使用此方法,仅返回其键集完全匹配的DOI。
作为将示例密钥对列表存储在表中的替代方法,您可以使用如下的公用表表达式:
WITH sample_key_set AS (
SELECT key1, key2 FROM DUAL UNION ALL
SELECT key3, key4 FROM DUAL UNION ALL
...
)
SELECT m.doi_id
FROM ... /* the rest of the above query */
还有一个方法at SQL Fiddle的演示。
答案 2 :(得分:0)
SELECT <whatever you need>
FROM doi_membership
WHERE (Key_1 = <key value your looking for> AND Key_2 = <key value you're looking for>)
除非我误解了这个问题,否则我认为这很容易
答案 3 :(得分:0)
你不能只使用自我加入吗?
好的,所以你不需要内部比较,只需要参数/硬编码密钥对值。
内部检查将是:
SELECT
d.doi_ID,
c.CountOfID
FROM
doiMembership d INNER JOIN
(SELECT
doi_ID,Count(ID) CountOfID
FROM doiMembership
GROUP BY doi_ID) c ON
d.doi_ID = c.doi_ID INNER JOIN
(SELECT
doi_ID, Count(ID) CountOfID
FROM doiMembership
GROUP BY doi_ID) c2 on
c2.CountOfID = c.CountOfID inner join
doiMembership d2 ON
c2.doi_ID = d2.doi_ID and
c.CountOfID = d2.CountOfID AND
(d.key1 = d2.[key1]) AND
(d.key2 = d2.[key2])
WHERE
(d.ID <> d2.[id])
GROUP BY
d.doi_ID,
c.CountOfID
但是如果你想与已知的doi进行比较,你可以使用:
SELECT
d.doi_ID,
c.CountOfID
FROM
doiMembership d INNER JOIN
(SELECT
doi_ID,Count(ID) AS CountOfID
FROM doiMembership
GROUP BY doi_ID) c ON
d.doi_ID = c.doi_ID INNER JOIN
(SELECT
doi_ID, Count(ID) AS CountOfID
FROM doiMembership
GROUP BY doi_ID) c2 INNER JOIN
doiMembership AS d2 ON
c2.doi_ID = d2.doi_ID and
c.CountOfID = d2.CountOfID
WHERE
(d.ID <> d2.[id]) AND
(d.key1 = d2.[key1]) AND
(d.key2 = d2.[key2]) and
d.doi_id = 'value'
GROUP BY
d.doi_ID,
c.CountOfID