У меня есть случай, когда пользователь может указать произвольное количество параметров, которые будут отфильтрованы по таблице. Проще говоря, есть ряд параметров по 64 сегмента в каждом. Все вместе это представляет собой линейную последовательность чисел. Каждая запись содержит произвольное количество точек корзины.
Кроме того, эти числа находятся в диапазонах внутри каждого сегмента.
Пользователь может указать желаемый диапазон значений любого количества произвольных записей. Возвращаются записи, в которых перекрытие для ВСЕХ указанных параметров (сегментов).
Вы заметите, что есть минимум и максимум. Это диапазон. Увидев, перекрываются ли они, я могу получить результаты значительно быстрее, чем при использовании запроса диапазона. Это метод оптимизации.
Вот пример с двумя условиями:
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
проверяются на пересечение с массивом указанных диапазонов.
Проблема в том, что мне нужно динамически построить этот запрос в функции. Список параметров передается функции (как определенный пользователем тип [массив]), запрос динамически генерируется, а затем выполняется.
Это работает, но я хочу сделать это без необходимости писать 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