Использование JOIN, чтобы избежать операторов SELECT-in-SELECT - PullRequest
0 голосов
/ 29 июня 2018

Скажем, у меня есть таблица базы данных со следующей структурой

Таблица Запись :

id       INT NOT NULL (PRIMARY_KEY, AUTO_INCREMENT)
parent   INT NOT NULL
priority INT NUL NULL

Теперь я хочу выбрать все записи, но мне нужен столбец, который сопоставляет каждую строку с последующей (на основе priority в порядке возрастания), которая имеет тот же parent - если он существует, в противном случае NULL , В этом произвольном примере parent является идентификатором полностью внешней таблицы и не имеет никакого отношения к записям напрямую.

Например, набор данных:

| id | parent | priority |
|----|--------|----------|
| 1  | 1      | 2        |
| 2  | 1      | 6        |
| 3  | 1      | 1        |
| 4  | 2      | 4        |
| 5  | 2      | 3        |

Должно выдать следующее:

| id | parent | priority | match |
|----|--------|----------|-------|
| 1  | 1      | 2        | 2     |
| 2  | 1      | 6        | NULL  |
| 3  | 1      | 1        | 1     |
| 4  | 2      | 4        | NULL  |
| 5  | 2      | 3        | 4     |

Реализация SQL, которая работает:

SELECT r1.*, 
    (SELECT r2.id 
        FROM record AS r2 
        WHERE r2.parent = r1.parent 
            AND r2.priority > r1.priority 
        ORDER BY r2.priority ASC 
        LIMIT 1
    ) AS match_id
FROM record AS r1

Тем не менее, я весьма обеспокоен SELECT-in-SELECT в отношении масштабируемости. Есть идеи, как сделать это чисто? Можно ли это сделать с помощью JOIN?

Ответы [ 2 ]

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

Предполагая, что у вас есть уникальный приоритет для каждого родителя, я думаю, это сработает:

select r.id, r.parent, r.priority, r2.id as `match`
from (
    select r.id, r.parent, r.priority, min(r2.priority) as next_priority
    from record r
    left join record r2 on
      r.parent = r2.parent
      and r.priority < r2.priority
    group by r.id, r.parent, r.priority
  ) r
left join record r2 on
    r.parent = r2.parent
    and r.next_priority = r2.priority
order by r.id

match - зарезервированное ключевое слово в MySQL, поэтому требуются обратные пометки.

Как это работает, мы вытягиваем следующий приоритет из возрастающего порядка, который выше текущего, и на основании этого (и того факта, что у нас есть уникальные приоритеты для каждого родителя) мы можем получить соответствующий идентификатор строки.

Live DEMO - SQL Fiddle

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

Это будет работать для вас здесь и избегать использования подзапросов, как вы упомянули. Вы можете сделать то, что вы хотите, с помощью LEFT объединения, так что значения NULL останутся, а затем положить то, что вы хотите на on, например r1.parent = r2.parent and r2.priority > r1.priority

http://sqlfiddle.com/#!9/3a592/25

SELECT r1.*, r2.id as 'Match'
FROM record r1
left join record r2 on r1.parent = r2.parent and r2.priority > r1.priority
group by r1.id
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...