5

我有这张桌子

 ----------------
|   X    |   Y   |
 ----------------
|   a    |   1   |
|   c    |   6   |
|   e    |   3   |
|   d    |   6   |
|   c    |   4   |
|   b    |   1   |
|   a    |   5   |
|   g    |   1   |
 ----------------

当我得到一个数组 [c,d] 时,我需要在上表中找到“6”。即对于每组元素,我需要找到集合中所有元素共享的 Y 值,但前提是没有其他元素(即不在给定数组中的元素)共享该值。数组中的元素数量没有理论上的限制。

更多示例:对于 [a,b,c] 我什么都不需要。对于 [a,b] 我也不需要找到任何东西(因为 g 也有一个 Y = 1 的条目,所以对于 [a,b,g] 我确实需要找到“1”)。

我当然可以遍历数组,逐个查询,但这似乎是一种效率低下的方式。在 SQL 中执行此操作的最佳方法是什么?谢谢你。

4

2 回答 2

2

这些类型的查询在大型数据集和/或 Y 中的许多值共享 X 中的相同值的情况下永远不会特别高效。

也就是说,这是我正常做法的简单版本......

CREATE TEMPORARY TABLE params (
  item VARCHAR(16)
)
INSERT INTO params SELECT 'a'
INSERT INTO params SELECT 'b'
INSERT INTO params SELECT 'g'


SELECT
  yourTable.Y
FROM
  yourTable
LEFT JOIN
  params
    ON yourTable.X = params.item
GROUP BY
  yourTable.Y
HAVING
  COUNT(DISTINCT yourTable.X) = COUNT(DISTINCT params.item)


另一个不需要参数表的选项,虽然我不认为它更高效......

SELECT
  y
FROM
  yourTable
GROUP BY
  y
HAVING
  COUNT(DISTINCT x) = COUNT(DISTINCT CASE WHEN x IN ('a', 'b', 'g') THEN x ELSE NULL END)

这没有连接,但是以进行全表扫描为代价。

于 2012-07-04T16:25:06.660 回答
2

这是一种将“查询”值放在单独的表中的方法。

create table t ( x varchar(1), y int);

insert into t (x, y) values ('a', 1);
insert into t (x, y) values ('c', 6);
insert into t (x, y) values ('e', 3);
insert into t (x, y) values ('d', 6);
insert into t (x, y) values ('c', 4);
insert into t (x, y) values ('b', 1);
insert into t (x, y) values ('a', 5);
insert into t (x, y) values ('g', 1);

create table q ( x varchar(1) );

insert into q (x) values ('a');
insert into q (x) values ('b');

select a.y from
(
   select t.y
     from t join q on (t.x = q.x)
   group by t.y
   having count(*) = (select count(*) from q)
) a 
join t on (a.y = t.y) 
group by a.y
having count(*) = (select count(*) from q)

这是一个示例 SQLFiddle

这假设您不能有重复的组合。

如果您想在没有第二个表的情况下执行此操作,您可以将 in 替换为select count(*)您在 IN 列表中匹配的值的数量,而不是在内部子查询上执行连接,而是使用 where 子句。

select a.y from
(
select t.y
from t
  where t.x in ('c', 'd')
group by t.y
having count(*) = 2
) a 
join t on (a.y = t.y) 
group by a.y
having count(*) = 2
于 2012-07-04T16:30:46.963 回答