Перечислите все значения массива перечислений Postgres в сочетании со значениями, примененными к записи, показывая состояние, применено оно или нет - PullRequest
0 голосов
/ 17 февраля 2019

Недавно я заново открыл пользовательские типы и массивы Postgres, которые заставили меня почувствовать, что Postgres был NoSQL (не только SQL) задолго до того, как термин стал популярным.

Необходимо сделать выбормассив столбца значений перечисления для отображения всех значений перечисления и флаг, если столбец массива перечисления включает значение перечисления или не имеет правильной сортировки (сначала сортировка по примененным значениям перечисления по столбцу, а затем по порядку значений перечисления, если значение перечисления не было включено встолбец)

Пример DDL:

-- available website settings enum:
CREATE TYPE website_menu_extras_type AS ENUM ( 'logo', 'emails', 'locations', 'phones', 'search' );

-- this type represents if website setting is enabled or not (the setting is treated as enabled if it's included to a website's column `menu_extras` of type `website_menu_extras_type[]`):
CREATE TYPE website_menu_extras_with_defaults AS ( menu_extra website_menu_extras_type, is_enabled BOOLEAN );

-- website table which contains applied `website_menu_extras_type` values as array:
CREATE TABLE website ( ID serial PRIMARY KEY, menu_extras website_menu_extras_type [] );

-- insert some values:
INSERT INTO website ( menu_extras )
VALUES
    ( ARRAY [ 'logo', 'emails' ]:: website_menu_extras_type [] );

-- select `menu_extras` as applied values 
-- and `menu_extras_with_defaults` which is an array 
-- of website_menu_extras_with_defaults having 
-- all values of `website_menu_extras_type` enum
-- and `is_enabled` set to true if `menu_extras` includes enum value
-- and `is_enabled` set to false if `menu_extras` does not include enum value
-- `menu_extras_with_defaults` should be sorted by `menu_extras` order 
-- and then by `website_menu_extras_type` enum order if `menu_extras` didn't include the enum value
SELECT
    id, menu_extras, menu_extras as menu_extras_with_defaults
FROM
    website;

Может быть огромное количество записей на веб-сайте, будет в основном чтение, и в будущем будет расширен список настроек, поэтомунастройки, «включенные» в запись веб-сайта, выглядят гораздо лучшим решением, чем использование таблицы «многие ко многим».

Я начал с UDF (например, он не будет работать так, как ожидалось), например:

  CREATE FUNCTION website_menu_extras_with_defaults ( website website ) RETURNS website_menu_extras_with_defaults[] AS $$ 
  WITH
    all_enum_values
    AS
    (
      SELECT UNNEST
        (
        enum_range ( NULL
     :: website_menu_extras_type )) AS val 
    ),
    all_enum_values1 AS
  (
    SELECT UNNEST
        (
        enum_range ( NULL
  :: website_menu_extras_type )) AS val 
    )
  -- select * from x1
  SELECT

    array[( val, FALSE ), (val, TRUE)]
  :: website_menu_extras_with_defaults []
FROM
    all_enum_values
-- where val in (website).menu_extras
    $$ LANGUAGE SQL STABLE;

, который мне не удалось сделать так, как ожидалось.

Как бы вы получили правильное значение menu_extras_with_defaults в этом случае?се

1 Ответ

0 голосов
/ 17 февраля 2019

unnest(...) WITH ORDINALITY ваш друг здесь:

CREATE OR REPLACE FUNCTION website_menu_extras_with_defaults(website website)
   RETURNS website_menu_extras_with_defaults[]
   LANGUAGE sql AS
$$SELECT array_agg(
            ROW(et.e, me.num IS NOT NULL)::website_menu_extras_with_defaults
               ORDER BY me.num, et.num
         )
FROM unnest(enum_range(NULL::website_menu_extras_type)) WITH ORDINALITY AS et(e, num)
   LEFT JOIN unnest(website.menu_extras) WITH ORDINALITY AS me(e, num)
      USING (e)$$;

Позвольте мне добавить здесь пару слов.

Несмотря на то, что PostgreSQL поддерживает составные типы данных и массивы, вы должны 't начать использовать их везде.

Нет необходимости использовать массивы и составные типы здесь.website также может иметь только id, а menu_extras должна быть второй таблицей, ссылающейся на website.

Более того, не используйте типы enum, если вы не уверены, что диапазонзначений никогда не изменится.Например, вы не можете удалить значение из типа enum.Лучше использовать обычную таблицу поиска.

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

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

...