#sql #postgresql
#sql #postgresql
Вопрос:
У меня есть таблица с тремя столбцами: «идентификатор», «буква» и «номер». У меня есть список пар «буква» и «число», для которых мне нужно получить «идентификаторы» в одном запросе. Очевидно, что простым решением является использование n запросов, где n — размер списка.
SELECT id FROM table WHERE number=... AND letter=...
Но для этого требуется n запросов, в моем случае это миллионы, и это большие накладные расходы. Ранее у меня был фильтр только для списка «чисел», поэтому я использовал
SELECT id FROM table WHERE number = ANY(ARRAY[...])
Есть ли какой-нибудь синтаксис, который делал бы то, что мне нужно, что-то вроде
SELECT id FROM table WHERE PAIR[letter,number] = ANY(ARRAY[PAIR[...],...])
Спасибо.
Ответ №1:
Вы могли бы использовать массив строк:
select id from table where (letter, number) = any(array[(l1, n1), (l2, n2), ...])
если вы настроены на использование = any
. Возможно, вам потребуется включить множество приведений типов, чтобы убедиться, что все выровнено, поэтому это может быть уродливее, чем присоединение к списку ЗНАЧЕНИЙ.
Комментарии:
1. Это не работает, однако проблема может заключаться в том, что вторая строка на самом деле «отличается от символа». Я получаю ОШИБКУ: не удается сравнить разные типы столбцов, различающиеся символами и неизвестные в столбце записи 2
2. Отсюда примечание в конце «Возможно, вам потребуется включить множество приведений типов, чтобы убедиться, что все выровнено». Возможно, вам потребуется сказать что-то вроде
(l1::varchar, n1::int)
, чтобы получить правильные типы.
Ответ №2:
Хотя вы, безусловно, можете использовать МАССИВ с <@
(is-contained-by) оператором ANY
или operator, для этого вам не нужны массивы. JOIN
При фиксированных значениях, безусловно, будет выполняться намного быстрее, чем другие варианты.
Рассмотрим следующую test
таблицу с данными:
CREATE TEMP TABLE IF NOT EXISTS
test(id SERIAL, letter TEXT, num NUMERIC);
WITH letters AS (
SELECT chr(generate_series(65, 90)) AS letter
)
,numbers AS (
SELECT generate_series(101, 999) AS num
)
INSERT INTO test(letter, num)
SELECT letter, num
FROM letters, numbers
Теперь вы можете добавить свои значения в запрос и выполнить JOIN
. Например, следующий запрос находит id
из пар (‘A’, 105), (‘B’, 110) и (‘C’, 879):
SELECT id
FROM test T
JOIN (VALUES /* your query criteria goes here */
('A', 105)
,('B', 110)
,('C', 879)
) AS V(l, n)
ON T.letter = V.l AND T.num = V.n
Который возвращает (при условии, что в тестовую таблицу не производилось никаких предварительных записей):
id |
----|
5|
909|
2577|
Комментарии:
1. Спасибо, это работает. Я, наконец, обнаружил
SELECT id FROM table WHERE (number, letter) = ANY (VALUES(1, 'A'), (2, 'B'), (3, 'C'))
, который кажется самым коротким.