假设我有一个这样的表:
| id | date | name | value |
|----|------------|------|-------|
| 0 | 2017-01-14 | foo | one |
| 1 | 2017-01-17 | bar | two |
| 2 | 2017-01-18 | john | five |
| 3 | 2017-01-19 | doe | ten |
(其中date
无需订购)
我希望能够选择上一个行的某些值(基于date
)。可以通过以下查询来实现这样的功能:
SELECT
*,
(SELECT
name
FROM
example e2
WHERE
e2.dt < e1.dt
ORDER BY dt DESC
LIMIT 1
) as prev_name
FROM example e1
结果表:
| id | dt | name | value | prev_name |
|----|------------|------|-------|-----------|
| 0 | 2017-01-14 | foo | one | (null) |
| 1 | 2017-01-17 | bar | two | foo |
| 2 | 2017-01-18 | john | five | bar |
| 3 | 2017-01-19 | doe | ten | john |
现在,这很好用。但是,如果我可以轻松地从上一行中选择多个列,最好会产生如下结果:
| id | dt | name | value | prev_name | prev_value | prev_dt |
|----|------------|------|-------|-----------|------------|------------|
| 0 | 2017-01-14 | foo | one | (null) | (null) | (null) |
| 1 | 2017-01-17 | bar | two | foo | one | 2017-01-14 |
| 2 | 2017-01-18 | john | five | bar | two | 2017-01-17 |
| 3 | 2017-01-19 | doe | ten | john | five | 2017-01-18 |
这当然可以通过简单地将子查询(SELECT [..] FROM example e2 ...)
多次复制到查询中来完成,但我想这不是最好的方法。我发现了几个关于SO寻址的问题 “如何从前一行选择记录”或“如何使用子查询选择多列”问题,但不是两者都有。后一个问题通常使用JOIN
语句来解决,但我认为这不能与“前一行”的情况相结合。所以我的问题是:什么是产生最后结果的更好方法,而不是为我们需要的每一列复制子查询?
编辑。作为额外的约束,我没有在原始问题中包含,“previous”实际上可能与前一行不同,而是“满足条件的前一行” ”。因此,假设我的表格包含额外的boolean
列b
| id | dt | name | value | b |
|----|------------|------|-------|---|
| 0 | 2017-01-14 | foo | one | 1 |
| 1 | 2017-01-17 | bar | two | 0 |
| 2 | 2017-01-18 | john | five | 1 |
| 3 | 2017-01-19 | doe | ten | 0 |
我希望“上一行”成为b = 1
的上一行,因此所需的结果将是:
| id | dt | name | value | b | prev_name | prev_value | prev_dt |
|----|------------|------|-------|---|-----------|------------|------------|
| 0 | 2017-01-14 | foo | one | 1 | (null) | (null) | (null) |
| 1 | 2017-01-17 | bar | two | 0 | foo | one | 2017-01-14 |
| 2 | 2017-01-18 | john | five | 1 | foo | one | 2017-01-14 |
| 3 | 2017-01-19 | doe | ten | 0 | john | five | 2017-01-18 |
我认为这仍然可以通过James Scott的答案来完成,只需使用b = 1
语句在IF
时更新变量,但在这种情况下可能还有其他解决方案。< / p>
编辑。 SQLfiddle
答案 0 :(得分:1)
如果您只想要上一行,看起来像是会话变量的一个很好的用例,您可以使用ORDER BY
来获得不同的结果。
SET @VDt := NULL, @VName := NULL, @VValue := NULL;
SELECT id, @VName prev_name, @VValue prev_value, @VDt prev_dt, @VDt := dt dt, @VName := `name` `name`, @VValue := `value` `value` FROM example;
在我第一次发布时搞砸了这一点,请注意必须在从上一行返回变量后设置变量。要重新排序列(如果需要),您可以将此查询包装在另一个中,然后重新排序结果列。
如果您还有其他需要,请告诉我,
此致
詹姆斯
答案 1 :(得分:1)
这样的内容将返回“之前”的ID。行。
SELECT x.*
, MAX(y.id) prev_id
FROM example x
LEFT
JOIN example y
ON y.id < x.id
AND y.b = 1
GROUP
BY x.id;
我将离开与此行相关的其余数据作为读者练习的业务。