假设有一个名为
Cars
的表,其结构如下(我们可以忽略缺乏适当键限制等因素,因为这与我的问题无关):CREATE TABLE Cars
(
id Integer,
maker_id Integer,
status_id Integer,
notes Varchar(100)
);
现在想象一下像这样加载一些测试数据:
INSERT INTO Cars
(id, maker_id, status_id, notes)
VALUES
(1, 1001, 0, 'test1'),
(2, 1001, 0, 'test2'),
(3, 1001, 0, 'test3'),
(4, 1002, 0, 'test4'),
(5, 1002, 0, 'test5'),
(6, 1002, 1, 'test6'),
(7, 1002, 1, 'test7'),
(8, 1002, 2, 'test8'),
(9, 1003, 3, 'test9'),
(10, 1003, 3, 'test10'),
(11, 1003, 4, 'test11'),
(12, 1003, 4, 'test12'),
(13, 1003, 5, 'test13'),
(14, 1003, 5, 'test14')
这里有14条记录,maker_id
(1001、1002、1003)有3个DISTINCT
值,而status_id
(0、1、2、3、4、5)有6个DISTINCT
值。
现在,想象一下将(maker_id
, status_id
)这些DISTINCT
的组合取出来。
SELECT DISTINCT maker_id, status_id FROM Cars;
以下是SQL Fiddle示例的链接:http://sqlfiddle.com/#!9/cb1c7/2。
下面是所需返回的记录(
maker_id
,status_id
):- (1001, 0) - (1002, 0) - (1002, 1) - (1002, 2) - (1003, 3) - (1003, 4) - (1003, 5)
需要返回的逻辑如下:
- 如果给定的
maker_id
值(例如1001)仅具有对应的DISTINCT
(maker_id
, status_id
) 对中的1条不同记录,则仅返回它。在这个例子中:(1001, 0)。
- 如果给定的maker_id
值具有多于1个对应的DISTINCT
(maker_id
, status_id
) 对的不同记录,则返回所有记录,除了一个status_id
值为0的记录。在这个例子中:(1002, 1),(1002, 2),(1003, 3),(1003, 4)和(1003, 5)。请注意,我们省略了(1002, 0)。
是否有人能想到更简洁/更有效(就运行时间而言)的编写此查询的方法?在现实世界中,我的表拥有数百万条记录。
我提出了以下解决方案:
SELECT
subq.maker_id,
subq.status_id
FROM
(
SELECT DISTINCT
maker_id,
status_id,
(SELECT COUNT(*) FROM Cars WHERE maker_id = c.maker_id AND status_id != 0 GROUP BY maker_id) AS counter
FROM Cars AS c
) AS subq
WHERE
subq.counter IS NULL
OR (subq.counter IS NOT NULL AND subq.status_id != 0)
;
这是一个 SQL Fiddle 的例子: http://sqlfiddle.com/#!9/cb1c7/3
UNION ALL
比UNION
更好,因为它避免了进行排序和去重的开销。 - spencer7593