Возвращает true, если все значения столбца верны

Есть ли более быстрый способ в PostgreSQL по существу сделать if, если на нескольких строках?

Скажем, у меня есть таблица

ticket | row | archived
1      | 1   | true
1      | 2   | true
1      | 3   | true
2      | 1   | false
2      | 2   | true

Есть ли способ сделать оператор if в столбце, где ticket =? Так что, когда ticket = 1 будет истинным, потому что

true && true && true = true

и где ticket = 2 будет ложным, потому что

false && true = false

Или я должен просто придерживаться

SELECT ( (SELECT COUNT(*) FROM table WHERE ticket = 1)
       = (SELECT COUNT(*) FROM table WHERE ticket = 1 AND archived = true) )

Ответ 1

Агрегатная функция bool_and()

Просто, коротко, понятно:

SELECT bool_and(archived)
FROM   tbl
WHERE  ticket = 1;

Руководство:

истина, если все входные значения верны, иначе ложь

Выражение подзапроса EXISTS

Нравится @Mike при условии.

Быстрее. Но вам нужно дополнительно проверить, существуют ли вообще какие-либо строки с ticket = 1, или вы получите неправильные результаты для несуществующих тикетов:

SELECT EXISTS (SELECT 1 FROM tbl WHERE ticket=1)
       AND NOT
       EXISTS (SELECT 1 FROM tbl WHERE ticket=1 AND archived = FALSE);

Индексы

Обе формы могут и будут использовать такой индекс:

CREATE index tbl_ticket_idx ON tbl (ticket);

.. что делает оба быстрее, но запрос EXISTS быстрее, потому что эта форма может перестать сканировать, как только найдена первая подходящая строка. Почти нет разницы между двумя запросами с несколькими строками на заявку, но существенная разница для многих строк на заявку.

Чтобы использовать сканирование только по индексу в pg 9.2, вам понадобится многостолбцовый индекс в виде:

CREATE index tbl_ticket_archived_idx ON tbl (ticket, archived);

Этот вариант лучше в любом случае в большинстве случаев и в любой версии PostgreSQL. Из-за выравнивания данных добавление boolean к integer в индексе не приведет к росту индекса вообще. Добавленная выгода едва ли любой ценой.

Однако индексированные столбцы предотвращают обновления HOT (Heap Only Tuple). Скажем, UPDATE изменяет только столбец в archived. Если столбец не используется каким-либо индексом (каким-либо образом), строка может быть ГОРЯЧЕЙ обновлена. Иначе, этот ярлык не может быть использован. Я написал больше об горячих обновлениях в этом связанном ответе.

Так что, как всегда, это зависит от вашей рабочей нагрузки.

Ответ 2

Как насчет чего-то типа:

select not exists (select 1 from table where ticket=1 and not archived)

Я думаю, что это может быть выгодно для сравнения счетчиков, так как count может или не может использовать индекс и действительно все, что вам нужно знать, есть ли какие-либо строки FALSE для этого билета. Я думаю, что просто создание частичного индекса на ticket может быть невероятно быстрым.

SQL Fiddle

Ответ 3

select not false = any (
        select archived
        from foo
        where ticket = 1
    )

SQL Fiddle