Postgres очень сложный динамический оператор выбора с COALESCE - PullRequest
0 голосов
/ 26 июня 2018

Имея таблицу и такие данные

CREATE TABLE solicitations
(
  id SERIAL PRIMARY KEY,
  name text
);

CREATE TABLE donations
(
  id SERIAL PRIMARY KEY,
  solicitation_id integer REFERENCES solicitations, -- can be null
  created_at timestamp without time zone NOT NULL DEFAULT (now() at time zone 'utc'),
  amount bigint NOT NULL DEFAULT 0
);


INSERT INTO solicitations (name) VALUES 
  ('solicitation1'), ('solicitation2');

INSERT INTO donations (created_at, solicitation_id, amount) VALUES 
  ('2018-06-26', null, 10), ('2018-06-26', 1, 20), ('2018-06-26', 2, 30),
  ('2018-06-27', null, 10), ('2018-06-27', 1, 20),
  ('2018-06-28', null, 10), ('2018-06-28', 1, 20), ('2018-06-28', 2, 30);

Как сделать динамический идентификатор запроса в следующем операторе select, используя только postgres ???

SELECT
"created_at"
-- make dynamic this begins
, COALESCE("no_solicitation", 0) AS "no_solicitation"
, COALESCE("1", 0) AS "1"
, COALESCE("2", 0) AS "2"
-- make dynamic this ends
FROM crosstab(
  $source_sql$
    SELECT
      created_at::date as row_id
    , COALESCE(solicitation_id::text, 'no_solicitation') as category
    , SUM(amount) as value
    FROM donations
    GROUP BY row_id, category
    ORDER BY row_id, category
  $source_sql$
, $category_sql$
  -- parametrize with ids from here begins
  SELECT unnest('{no_solicitation}'::text[] || ARRAY(SELECT DISTINCT id::text FROM solicitations ORDER BY id))
  -- parametrize with ids from here ends
  $category_sql$
) AS ct (
  "created_at" date
-- make dynamic this begins
, "no_solicitation" bigint
, "1" bigint
, "2" bigint
-- make dynamic this ends
)

Выбор должен возвращать данные, подобные этому

created_at  no_solicitation  1    2
____________________________________
2018-06-26  10               20   30
2018-06-27  10               20   0
2018-06-28  10               20   30

Идентификаторы запроса, которые должны параметризоваться, такие же, как в

    SELECT unnest('{no_solicitation}'::text[] || ARRAY(SELECT DISTINCT id::text FROM solicitations ORDER BY id))

Код можно изменить здесь

1 Ответ

0 голосов
/ 27 июня 2018

Я решил использовать json, который намного проще, чем кросс-таблица

WITH
  all_solicitation_ids AS (
    SELECT
      unnest('{no_solicitation}'::text[] ||
      ARRAY(SELECT DISTINCT id::text FROM solicitations ORDER BY id))
    AS col
  )
, all_days AS (
  SELECT
    -- TODO: compute days ad hoc, from min created_at day of donations to max created_at day of donations
    generate_series('2018-06-26', '2018-06-28', '1 day'::interval)::date
  AS col
)
, all_days_and_all_solicitation_ids AS (
  SELECT
    all_days.col AS created_at
  , all_solicitation_ids.col AS solicitation_id
  FROM all_days, all_solicitation_ids
  ORDER BY all_days.col, all_solicitation_ids.col
)
, donations_ AS (
  SELECT
    created_at::date as created_at
  , COALESCE(solicitation_id::text, 'no_solicitation') as solicitation_id
  , SUM(amount) as amount
  FROM donations
  GROUP BY created_at, solicitation_id
  ORDER BY created_at, solicitation_id
)
, donations__ AS (
  SELECT
    all_days_and_all_solicitation_ids.created_at
  , all_days_and_all_solicitation_ids.solicitation_id
  , COALESCE(donations_.amount, 0) AS amount
  FROM all_days_and_all_solicitation_ids
  LEFT JOIN donations_
    ON all_days_and_all_solicitation_ids.created_at = donations_.created_at
   AND all_days_and_all_solicitation_ids.solicitation_id = donations_.solicitation_id
)

SELECT
  jsonb_object_agg(solicitation_id, amount) ||
  jsonb_object_agg('date', created_at)
  AS data
FROM donations__
GROUP BY created_at

что приводит

data
______________________________________________________________
{"1": 20, "2": 30, "date": "2018-06-28", "no_solicitation": 10}
{"1": 20, "2": 30, "date": "2018-06-26", "no_solicitation": 10}
{"1": 20, "2": 0, "date": "2018-06-27", "no_solicitation": 10}

Мысль это не то, что я просил. Он возвращает только столбец data вместо date, no_solicitation, 1, 2, ...., для этого мне нужно использовать json_to_record, но я не знаю, как динамически создать его аргумент as

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...