使用JOIN避免SELECT-in-SELECT语句

时间:2018-06-29 13:26:03

标签: mysql sql join select

说我有一个具有以下结构的数据库表

记录

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 :(得分:1)

假设您对每个父母都有唯一的优先级,我相信这会起作用:

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中的保留关键字,因此需要反引号。

此方法的工作原理是我们从高于当前顺序的升序中拉出下一个优先级,并基于此(并且我们对每个父级都有唯一的优先级)可以拉出相应的行ID。

Live DEMO - SQL Fiddle

答案 1 :(得分:0)

这将在这里为您工作,并且避免使用您提到的子查询。您可以通过LEFT连接执行所需的操作,以便保留空值,然后将所需的内容放在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