如何一次检查多个值的存在

时间:2016-06-12 04:31:14

标签: .net postgresql npgsql

我在PostgreSQL中有一个表,在bytea列上有一个唯一索引。

目前,我正在运行此查询以确定表中该列是否已存在值。

-- mycolumn definition: mycolumn bytea unique not null
SELECT 1 FROM mytable WHERE mycolumn = @mycolumn;

当我将结果发送到DataReader时,我只是检查它是否有行,如果是,则返回true。

但是,我需要批量检查数百个值,由于往返开销,每个值的运行速度有点慢。

我考虑过发送多个语句:

SELECT 1 FROM mytable WHERE mycolumn = @mycolumn1;
SELECT 1 FROM mytable WHERE mycolumn = @mycolumn2;
SELECT 1 FROM mytable WHERE mycolumn = @mycolumn3;
-- etc

在这里,我会看到读者是否有像以前一样的行,然后调用NextResult()转到下一个查询结果。当然,我必须生成此查询并添加参数。这是在pgsql中一次检查多个值是否存在的最快方法?

我还考虑了一起使用EXISTSUNION查询的方案,但文档说UNION不保留排序。那么我还必须在查询中提供一个订单号作为另一个参数,这样我就可以在服务器上重新排序结果。这似乎比上面更浪费......如果有效。

更新

我刚刚根据文档发现了PG中的returning multiple result sets is not supported。所以上面是行不通的。那么最好的方法是什么?

<击>   

命令字符串可以包含多个SQL命令(以分号分隔)。 [...] 请注意,返回的PGresult结构仅描述从字符串执行的最后一个命令的结果。

显然以上只涉及功能。

3 个答案:

答案 0 :(得分:2)

如果你需要的只是bytea值而不是id左右,那么你可以用一组值来解决它,并在处理时保留 normalality (大概和未经测试,我自己不是npgsql用户):

SELECT coalesce(mt.present, false) 
FROM unnest(@values) WITH ORDINALITY x (v, ord)
LEFT JOIN LATERAL (SELECT true AS present FROM mytable WHERE mycolumn = x.v) mt ON true
ORDER BY x.ord;

传入要测试的@values个数组bytea。在取消数组时,使用WITH ORDINALITY子句,以便保留顺序。然后将mytable加入unnested数组值并检查哪些值确实具有相应的值。您将获得等于数组长度的行数,每行包含标量值boolean类型。 normalality 的排序可确保按照数组中值的顺序返回行。

如果您希望获得一个boolean数组,那么您应该将查询包装在外部查询中array_agg(present) coalesce(mt.present, false) AS present子句(因此请使用子语句中的别名)查询)。

答案 1 :(得分:1)

您可以使用Npgsql的原始想法。它将在一次往返中完成所有工作。您也可以获得结果。

答案 2 :(得分:-1)

如何构建这样的动态查询:

SELECT x FROM (
    select unnest( 
        ARRAY[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,
              21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,30]
    ) as x
) x
WHERE x NOT IN ( SELECT my_column FROM my_table )

这只需要向服务器进行一次往返。
您可以在一个查询中打包几十个号码并立即检查所有号码。
在应用程序端,只需直接从结果集中读取缺失的数字。

原则上,也应该可以创建一个只有一个数组类型参数的预备语句,并将一个值数组绑定到这个参数而不是构建一个动态查询,但我从来没有这样做过,并且#&# 39;不知道怎么做。您可以对此主题进行进一步研究。