Как объединить многие тематические заявления Postgresql - PullRequest
0 голосов
/ 15 мая 2019

РЕДАКТИРОВАННЫЙ ВОПРОС:

У меня есть таблица

CREATE TABLE my_table (id INT, type_key int, rate_1 double precision, rate_2 double precision);

INSERT INTO my_table (id, type_key, rate_1, rate_2) 
VALUES
    (1, NULL, 0.2, 3),
    (2, 1, 1.3, 5),
    (3, 1, NULL, 10),
    (4, 2, 0.5, NULL),
    (5, 2, 0.01, 0),
    (6, 2, 0.75, NULL),
    (7, 3, NULL, NULL),
    (8, 3, 0.34, 1),
    (9, 3, NULL, 1);

И в идеале результирующая таблица должна быть:

(id, score_1, score_2)
    (1, NULL, NULL),
    (2, 0, 4),
    (3, NULL, 3),
    (4, 2, NULL),
    (5, 2, 4),
    (6, 3, NULL),
    (7, NULL, NULL),
    (8, 4, 2),
    (9, NULL, 3);

на основе пороговых значений оценки, как:

CASE WHEN type_key = 1 THEN (
            CASE
                WHEN rate_1 > .7 THEN 0
                WHEN rate_1 > .5 THEN 1
                WHEN rate_1 > .4 THEN 2
                WHEN rate_1 > .3 THEN 3
                ELSE 4

(и повторите для каждого type_key_n и rate_n)

ОРИГИНАЛЬНЫЙ ВОПРОС:

У меня есть таблица, для простоты, скажем, у нее есть три столбца: date, name и value.

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

Теперь, один из способов сделать это - написать:

CREATE TABLE resulting_table AS 
(SELECT DATE,
       name,
       CASE
         WHEN value >= magnitude_1 THEN result_1
         WHEN value >= magnitude_2 THEN result_2
         WHEN value >= magnitude_n THEN result_n
       END AS bins
FROM my_table)

, но с увеличением n этот запрос становится очень длинным и довольно неразборчивым.И если у меня разные пороговые величины для разных name с, то мне нужно сделать вложенный оператор case следующим образом:

CREATE TABLE resulting_table AS 
(SELECT DATE,
       CASE
         WHEN name = 'name_n' THEN
           CASE
             WHEN value >= name_n_magnitude_n THEN result_n_n
           END AS bins 
FROM my_table)

, что означает, что запрос становится еще длиннее и менее разборчивым.

У меня есть две идеи, как решить эту проблему, но я не совсем уверен, что лучше или как я бы их реализовал.

1) Создайте отдельную таблицу для всех name, magnitudeи result комбинаций.Присоединитесь к этой таблице с помощью my_table, чтобы получить resulting_table

2) Используйте смесь postgresql / psycopg2 и python, чтобы реализовать эту логику в удобном для чтения виде.

Любые мыслиВот?Похоже, что это будет распространенная проблема очистки данных / инженерии данных.

Ответы [ 2 ]

0 голосов
/ 25 мая 2019

ответ на (второй) отредактированный вопрос

Допущения и моделирование

Предположим, что для каждого type_key=n существует rate_n, и моделирование ваших ставок по массиву вместо отдельных значений ... Итак, предположим, что rate[type_key] существует для всех строк в вашей таблице.

CREATE TABLE my_table (
  id int,         -- same
  type_key int,   -- same
  rate double precision[] -- changed to array
);
INSERT INTO my_table 
    (id, type_key, rate) 
VALUES
    (1, NULL, array[0.2,  3, NULL]),
    (2, 1,    array[1.3,  5, NULL]),
    (3, 1,    array[NULL, 10, 0.2]),
    (4, 2,    array[0.5,  NULL,0.1]),
    (5, 2,    array[0.01, 0, 0.02]),
    (6, 2,    array[0.75, NULL,0.6]),
    (7, 3,    array[NULL::double precision, NULL,0.1]),
    (8, 3,    array[0.34, 1,0.31]),
    (9, 3,    array[NULL, 1,0.1])
;

Дополняющий образец

Пожалуйста, лучшие образцы для тестирования решения ... Пример:

INSERT INTO my_table 
    (id, type_key, rate) 
VALUES
    (20, 1,    array[0.5, 0, 0]),
    (21, 1,    array[0.7, 0, 0]),
    (22, 2,    array[0, 0.7, 0])
;

Решение

SELECT m.id, (
    SELECT COALESCE( max(idx)-1, 0 ) 
    FROM unnest(cmp[type_key:type_key]) WITH ORDINALITY tt(x,idx) 
    WHERE m.rate[type_key]>x
  ) score
FROM my_table m, 
     (select array[ 
       [0.0, 0.3,  0.4,  0.5,  0.7],  -- "case set" of rate_1
       [0.0, 0.31, 0.4,  0.45, 0.72], -- "case set" of rate_2
       [0.0, 0.22, 0.41, 0.55, 0.8]   -- "case set" of rate_3
      ]) t(cmp)
;

результат

 id | score 
----+-------
  1 |     0
  2 |     4
  3 |     0
  4 |     0
  5 |     0
  6 |     0
  7 |     0
  8 |     1
  9 |     0
 20 |     2
 21 |     3
 22 |     3
0 голосов
/ 15 мая 2019

Пожалуйста, образец ваших данных и более объективная информация о том, что вы хотите: «решение Python» или «решение SQL».Я предпочитаю решать самые возможные с помощью SQL.Здесь общее решение (см. Типы диапазонов ).


Хорошая вещь в SQL также ужасна: он отлично работает только с табличными данными, другой структуры данных нет... Даже что-то похожее на матрицу должно быть неопознанным.Таким образом, ваша подсказка верна: «создать отдельную таблицу».Но для небольших наборов данных есть несколько хороших опций: массив и JSONb.Давайте использовать массив типов диапазона.

Начиная с некоторых дидактических примеров:

SELECT '[1,10)'::int4range @> 4, '[1,10)'::int4range @> 44; -- true, false
SELECT  idx, r @> 4 a,  r @> 44 b
FROM unnest(array[int4range(1,10),int4range(11,50)]) WITH ORDINALITY t(r,idx);

Итак, набор данных массива похож на таблицу с типом столбца и первичным ключом.Теперь вы можете сопоставить этот массив диапазонов с любым другим массивом значений.Решение:

CREATE TABLE resulting_table AS 
(SELECT DATE,
       name,
       (SELECT (array['a','b','c'])[idx]  -- array of results
        FROM unnest(array[int4range(1,10),int4range(11,50),int4range(51,100)]) 
             WITH ORDINALITY t(magnitude,idx)
        WHERE magnitude @> value
       ) AS bins
FROM my_table)

Это быстрее, чем использование таблицы при небольших массивах (потому что она скомпилирована как «встроенная функция»).Используйте EXPLAN ANALYZE , когда массивам требуется больше ~ 1000 элементов.

...