SELECT commandid
FROM results
WHERE NOT EXISTS (
SELECT *
FROM generate_series(0,119999)
WHERE generate_series = results.commandid
);
我在results
类型int
中有一列,但各种测试都失败了,并没有添加到表格中。我想创建一个查询,该查询返回commandid
中找不到的results
列表。我认为上面的查询会做我想要的。但是,如果我使用超出预期可能范围commandid
的范围(如负数),它甚至不起作用。
答案 0 :(得分:13)
给出样本数据:
create table results ( commandid integer primary key);
insert into results (commandid) select * from generate_series(1,1000);
delete from results where random() < 0.20;
这有效:
SELECT s.i AS missing_cmd
FROM generate_series(0,1000) s(i)
WHERE NOT EXISTS (SELECT 1 FROM results WHERE commandid = s.i);
这个替代配方也是如此:
SELECT s.i AS missing_cmd
FROM generate_series(0,1000) s(i)
LEFT OUTER JOIN results ON (results.commandid = s.i)
WHERE results.commandid IS NULL;
上述两种情况似乎都会在我的测试中产生相同的查询计划,但您应该使用EXPLAIN ANALYZE
与数据库中的数据进行比较,以确定哪种方法最佳。
请注意,我使用NOT IN
代替NOT EXISTS
,在一个公式中使用子查询,而在另一个公式中使用普通OUTER JOIN
。数据库服务器可以更轻松地优化这些,并避免NULL
中NOT IN
可能出现的混乱问题。
我最初赞成OUTER JOIN
制定,但至少在9.1中,我的测试数据NOT EXISTS
形式优化到同一计划。
当系列很大时,两者都会比下面的NOT IN
表现更好,就像你的情况一样。 NOT IN
曾经要求Pg对每个被测试的元组进行IN
列表的线性搜索,但是对查询计划的检查表明Pg可能足够聪明,现在可以对其进行哈希处理。 NOT EXISTS
(由查询规划器转换为JOIN
)和JOIN
效果更好。
NOT IN
公式在存在NULL commandid
时会混淆并且效率低下:
SELECT s.i AS missing_cmd
FROM generate_series(0,1000) s(i)
WHERE s.i NOT IN (SELECT commandid FROM results);
所以我会避免它。拥有1,000,000行,其他两个在1.2秒内完成,NOT IN
配方运行CPU限制,直到我感到无聊并取消它。
答案 1 :(得分:6)
正如我在评论中提到的,您需要执行与上述查询相反的操作。
SELECT
generate_series
FROM
generate_series(0, 119999)
WHERE
NOT generate_series IN (SELECT commandid FROM results);
此时,您应该找到所选范围内commandid
列中不存在的值。
答案 2 :(得分:0)
我不是那么有经验的SQL大师,但我喜欢其他解决问题的方法。 就在今天,我遇到了类似的问题 - 在一个字符列中找到未使用的数字。 我通过使用pl / pgsql解决了我的问题,并且非常感兴趣的是我的程序速度。 我使用@Craig Ringer的方式生成带有串行列的表,添加一百万条记录,然后删除每99条记录。此过程在搜索缺失的数字时大约需要3秒钟:
-- creating table
create table results (commandid character(7) primary key);
-- populating table with serial numbers formatted as characters
insert into results (commandid) select cast(num_id as character(7)) from generate_series(1,1000000) as num_id;
-- delete some records
delete from results where cast(commandid as integer) % 99 = 0;
create or replace function unused_numbers()
returns setof integer as
$body$
declare
i integer;
r record;
begin
-- looping trough table with sychronized counter:
i := 1;
for r in
(select distinct cast(commandid as integer) as num_value
from results
order by num_value asc)
loop
if not (i = r.num_value) then
while true loop
return next i;
i = i + 1;
if (i = r.num_value) then
i = i + 1;
exit;
else
continue;
end if;
end loop;
else
i := i + 1;
end if;
end loop;
return;
end;
$body$
language plpgsql volatile
cost 100
rows 1000;
select * from unused_numbers();
也许它可以用于某人。
答案 3 :(得分:0)
如果您使用的是AWS redshift,则最终可能无法解决问题,因为它不支持<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.1/knockout-min.js"></script>
<h1>Knockout Custom Bindings</h1>
<h2>Which factors affect your technology choices?</h2>
<p>Please distribute <span class="points">10</span> points between the following options.</p>
<table>
<thead>
<tr>
<td>Option</td>
<td>Importance</td>
</tr>
</thead>
<tbody data-bind="foreach:options">
<tr>
<td data-bind="text:option"></td>
<td class="select">
<select data-bind="options:$root.range, value:importance"></select>
</td>
</tr>
</tbody>
</table>
<p>You've got <span class="points" data-bind="text:points()"></span> points left to use.</p>
<button data-bind="click:$root.points()">Finished</button>
。你最终会得到这样的东西:
generate_series