Наибольшее N на группу с JOIN и несколькими столбцами заказа - PullRequest
0 голосов
/ 23 декабря 2018

У меня есть две таблицы:

Table0:
| ID | TYPE | TIME  | SITE |
|----|------|-------|------|
| aa | 1    | 12-18 | 100  |
| aa | 1    | 12-10 | 101  |
| bb | 2    | 12-10 | 102  |
| cc | 1    | 12-09 | 100  |
| cc | 2    | 12-12 | 103  |
| cc | 2    | 12-01 | 109  |
| cc | 1    | 12-07 | 101  |
| dd | 1    | 12-08 | 100  |

и

Table1:
| ID |
|----|
| aa |
| cc |
| cc |
| dd |
| dd |

Я пытаюсь вывести результаты, где:

  • ID должно существоватьв обеих таблицах.
  • TYPE должен быть максимальным для каждого ID.
  • TIME должен быть минимальным значением для максимального TYPE для каждого ID.
  • SITE должно быть значением из той же строки, что и минимальное значение TIME.

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

| ID | TYPE | TIME  | SITE |
|----|------|-------|------|
| aa | 1    | 12-10 | 101  |
| cc | 2    | 12-01 | 109  |
| dd | 1    | 12-08 | 100  |

Я пробовал эти операторы:

INSERT INTO "NuTable"
SELECT DISTINCT(QTS."ID"), "SITE",
       CASE WHEN MAS.MAB=1 THEN 'B'
            WHEN MAS.MAB=2 THEN 'F'
            ELSE NULL END,
       "TIME"
FROM (SELECT DISTINCT("ID") FROM TABLE1) AS QTS,
     TABLE0 AS MA,
     (SELECT "ID", MAX("TYPE") AS MASTY, MIN("TIME") AS MASTM 
      FROM TABLE0 
      GROUP BY "ID") AS MAS,
WHERE QTS."ID" = MA."ID"
      AND QTS."ID" = MAS."ID"
      AND MSD.MASTY  =MA."TYPE"

..., что приводит к синтаксической ошибке

INSERT INTO "NuTable"
SELECT DISTINCT(QTS."ID"), "SITE",
       CASE WHEN MAS.MAB=1 THEN 'B'
            WHEN MAS.MAB=2 THEN 'F'
            ELSE NULL END,
       "TIME"
FROM (SELECT DISTINCT("ID") FROM TABLE1) AS QTS,
     TABLE0 AS MA,
     (SELECT "ID", MAX("TYPE") AS MAB 
      FROM TABLE0 
      GROUP BY "ID") AS MAS,
     ((SELECT "ID", MIN("TIME") AS MACTM, MIN("TYPE") AS MACTY 
       FROM TABLE0 
       WHERE "TYPE" = 1 
       GROUP BY "ID")  
      UNION
      (SELECT "ID", MIN("TIME"), MAX("TYPE") 
       FROM TABLE0 
       WHERE "TYPE" = 2 
       GROUP BY "ID")) AS MACU 
WHERE QTS."ID" = MA."ID"
      AND QTS."ID" = MAS."ID"
      AND MACU."ID" = QTS."ID"
      AND MA."TIME" = MACU.MACTM
      AND MA."TYPE" = MACU.MACTB

..., которая дает неправильные результаты.

Ответы [ 3 ]

0 голосов
/ 23 декабря 2018

demo: db <> fiddle

SELECT DISTINCT ON (t0.id)
    t0.id,
    type,
    time,
    first_value(site) OVER (PARTITION BY t0.id ORDER BY time) as site
FROM table0 t0
JOIN table1 t1 ON t0.id = t1.id
ORDER BY t0.id, type DESC, time

ID должно существовать в обеих таблицах

Это может быть достигнуто путем объединенияобе таблицы против их id с.Результатом внутренних объединений являются строки, которые существуют в обеих таблицах.

SITE должно быть значением из той же строки, что и минимальное значение TIME.

Это то же самое, что "Give me the first value of each group of id s ordered by time ".Это можно сделать с помощью оконной функции first_value() .Оконные функции могут группировать ваш набор данных (PARTITION BY).Таким образом, вы получаете группы id с, которые можно заказать отдельно.first_value() дает первое значение этих упорядоченных групп.

TYPE должно быть максимумом для каждого ID.

Чтобы получить максимальный тип для id сначала вам нужно будет ORDER BY id, type DESC.Вы получаете максимум type в качестве первой строки для id ...

TIME должно быть минимальным значением для максимума TYPE для каждого ID.

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

Теперь у вас есть упорядоченный набор данных: Для каждого id, строка с максимальнымtype и его минимум time является первым.

DISTINCT ON дает вам именно первый ряд каждой группы.В этом случае определенная вами группа (id).Результат ожидаемый.

0 голосов
/ 23 декабря 2018

Я бы написал это, используя distinct on и in / exists:

select distinct on (t0.id) t0.*
from table0 t0
where exists (select 1 from table1 t1 where t1.id = t0.id)
order by t0.id, type desc, time asc;
0 голосов
/ 23 декабря 2018

Отвечая на ваш прямой вопрос "как избежать ...":

Эта ошибка появляется, когда вы указываете столбец в области SELECT оператора, которого нет в разделе GROUP BY и нетЯ не могу сказать, что не являюсь частью агрегирующей функции, такой как MAX, MIN, AVG

, в ваших данных

SELECT
  ID, site, min(time)
FROM
  table
GROUP BY
  id 

Я не сказал, что делать с САЙТОМ;это либо ключ группы (в этом случае я получу каждую уникальную комбинацию идентификатора, сайта и минимального времени в каждой), либо он должен быть агрегирован (например, максимальное количество сайтов на идентификатор)

Это нормально:

SELECT
  ID, max(site), min(time)
FROM
  table
GROUP BY
  id 

SELECT
  ID, site, min(time)
FROM
  table
GROUP BY
  id,site

Я просто не могу не указать что с ним делать - что должна возвращать база данных в таком случае?(Если вы все еще боретесь, скажите мне в комментариях, что, по вашему мнению, должен делать БД, и я лучше пойму ваше мышление, чтобы я мог сказать вам, почему он не может этого сделать).Программист базы данных не может принять это решение за вас;Вы должны сделать это

Обычно люди спрашивают об этом, когда хотят идентифицировать:

Минимальное время для идентификатора, а также получать все остальные данные строки.например, «Каковы полные самые ранние данные записи для каждого идентификатора?»

В этом случае вы должны написать запрос, который идентифицирует минимальное время для идентификатора, а затем присоединить этот подзапрос к основной таблице данных по id =id и время = mintime.БД запускает подзапрос, формирует список минимального времени для каждого идентификатора, затем он фактически становится фильтром основной таблицы данных

SELECT * FROM
(
  SELECT
    ID, min(time) as mintime
  FROM
    table
  GROUP BY
    id
) findmin
INNER JOIN table t ON t.id = findmin.id and t.time = findmin.mintime

Что вы не можете сделать, это начать помещать в запрос другие данные, которые вы хотитеэто делает группировку, потому что вы либо должны группировать по столбцам, которые вы добавляете (делает группу более детализированной, а не по вашему желанию), либо вам нужно их агрегировать (и тогда это не обязательно происходит из той же строки, что идругие агрегированные столбцы - минимальное время - от строки 1, минимальное - от строки 3 - не то, что вам нужно)

Рассматривая вашу актуальную проблему:

Значение идентификатора должно существовать вдва стола.Значение типа должно быть самой большой группой по идентификатору.Значение Time должно быть наименьшим в самой большой группе типов.

Оставляя решение, которое требует наличия или аналитики, вы можете разобраться с теорией здесь:

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

SELECT t.id,min(t.time) FROM
(
  SELECT
    ID, max(type) as maxtype
  FROM
    table
  GROUP BY
    id
) findmax
INNER JOIN table t ON t.id = findmax.id and t.type = findmax.maxtype
GROUP BY t.id

Если вы не можете понять почему, дайте мне знать

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