Database PostgreSQL在不动态写入SQL的情况下执行多个动态WHERE条件

Database PostgreSQL在不动态写入SQL的情况下执行多个动态WHERE条件,database,function,postgresql,dynamic,postgresql-9.2,Database,Function,Postgresql,Dynamic,Postgresql 9.2,我有一个例子,用户可以指定任意数量的参数,这些参数将根据表进行过滤。简单地说,有一系列参数,每个参数有64个bucket。总之,这代表了一个线性的数字序列。每个记录包含任意数量的桶点 此外,这些数字在每个铲斗的范围内 用户可以指定任意数量记录的所需值范围。返回所有指定参数(存储桶)重叠的记录 你会注意到有一个低和一个高。这是射程。通过查看两者是否重叠,我可以比使用范围查询更快地获得结果。这是一种优化技术 下面是一个具有两个条件的示例: SELECT id FROM mytable2 WH

我有一个例子,用户可以指定任意数量的参数,这些参数将根据表进行过滤。简单地说,有一系列参数,每个参数有64个bucket。总之,这代表了一个线性的数字序列。每个记录包含任意数量的桶点

此外,这些数字在每个铲斗的范围内

用户可以指定任意数量记录的所需值范围。返回所有指定参数(存储桶)重叠的记录

你会注意到有一个低和一个高。这是射程。通过查看两者是否重叠,我可以比使用范围查询更快地获得结果。这是一种优化技术

下面是一个具有两个条件的示例:

SELECT  id
FROM    mytable2
WHERE   (val_low && (ARRAY(SELECT generate_series((0 * 64) + 20, (0 * 64) + 28))) OR
        val_high && (ARRAY(SELECT generate_series((0 * 64) + 20, (0 * 64) + 28))))
AND     (val_low && (ARRAY(SELECT generate_series((1 * 64) + 12, (1 * 64) + 15))) OR 
        val_high && (ARRAY(SELECT generate_series((1 * 64) + 12, (1 * 64) + 15))))
测试
val_low
val_high
铲斗是否与指定范围的数组相交

问题是我必须在函数中动态构建这个查询。参数列表被传递给函数(作为用户定义的类型[array]),查询将动态生成,然后执行

它可以工作,但我希望能够做到这一点,而不必在函数中编写SQL

具体而言,函数将被传递一个自定义类型数组,如下所示:

param_num int,
val_low   int,
val_high  int
generate_series函数调用中的值是
(param_num*64)+val_low,(param_num*64)+val_high

这可能吗

创建示例数据:

DROP TABLE IF EXISTS
        mytable2;

CREATE TABLE
        mytable2
        (
                id          INT NOT NULL PRIMARY KEY,
                val_low     int[],
                val_high    int[]
        );

SELECT  SETSEED(0.20130725);

WITH    t AS
        (
        SELECT  id,
                1 + FLOOR(RANDOM() * 24) AS l1, (RANDOM() * 8)::int AS h1,
                1 + FLOOR(RANDOM() * 24) AS l2, (RANDOM() * 8)::int AS h2,
                1 + FLOOR(RANDOM() * 24) AS l3, (RANDOM() * 8)::int AS h3,
                1 + FLOOR(RANDOM() * 24) AS l4, (RANDOM() * 8)::int AS h4
        FROM    generate_series(1, 500000) id
        )
INSERT
INTO    mytable2
SELECT  T.id, array[t.l1, (1 * 64) + t.l2, (2 * 64) + t.l3, (3 * 64) + t.l4], 
        array[t.l1 + t.h1, (1 * 64) + t.l2 + t.h2, (2 * 64) + t.l3 + t.h3, 
        (3 * 64) + t.l4 + t.h4]
FROM    T;

CREATE INDEX
    ix_mytable2_vhstore_low
ON      mytable2
USING   GIN (val_low);


CREATE INDEX
    ix_mytable2_vhstore_high
ON      mytable2
USING   GIN (val_high);
示例查询:

--EXPLAIN ANALYZE
SELECT COUNT(1)
FROM
(
    SELECT  id
    FROM    mytable2
    WHERE   (val_low && (ARRAY(SELECT generate_series(20, 28))) OR val_high &&
                (ARRAY(SELECT generate_series(20, 28))))
        AND (val_low && (ARRAY(SELECT generate_series((1 * 64) + 12, (1 * 64) + 15)))
                OR val_high && (ARRAY(SELECT generate_series((1 * 64) + 12, (1 * 64) + 15))))
) m;
结果:54983例


array[[0,20,28],[1,12,15]
是传递的参数

我看不到正在使用的表值。这意味着要么返回全部行,要么不返回任何行。正确吗?返回所有与所提供系列重叠的val_low或val_high行。谢谢。我将不得不使用它一段时间,因为它返回的记录比它应该返回的多。源数据是一个范围类型。随机是种子,因此结果将是相同的。但是,您可以使用查询示例查看结果应该是什么,并与您的新函数进行比较。但是,这不是一个问题。您可以比较两个查询的结果,如果相同,则您的查询有效。删除数组中的“[1,12,15]”部分(只留下第一段),您将看到0个结果,而不是187168。另外,在fiddle页面上,您的源代码是int,而不是int[],因此我不确定它是否会处理相同的代码。
with s as (
    select array(select generate_series(
            a[i][1] * 64 + a[i][2], a[i][1] * 64 + a[i][3]
        )) as a
    from
        (values (array[[0,20,28],[1,12,15]])) s(a)
        cross join
        generate_series(1, array_length(array[[0,20,28],[1,12,15]], 1)) g(i)
)
select id
from mytable2 cross join s
group by id
having count((not(val_low && a or val_high && a)) or null) = 0