在MySQL中从上一行选择多个列

q43xntqr  于 2023-05-16  发布在  Mysql
关注(0)|答案(2)|浏览(197)

假设我有一张这样的table:
| 身份证|日期|名称|价值|
| --------------|--------------|--------------|--------------|
| 0| 2017-01-14 2017-01-14|福|一个|
| 1| 2017-01-17 2017-01-17|杆|两个|
| 二|2017-01-18 2017-01-18|约翰|五|
| 三|2017-01-19 2017-01-19 2017-01-19|母鹿|十|
(其中date不一定需要排序)
我希望能够选择 previous 行的一些值(基于date)。这样的功能可以通过以下查询来实现:

SELECT 
  *, 
  (SELECT 
     name 
   FROM 
     example e2 
   WHERE 
     e2.dt < e1.dt 
   ORDER BY dt DESC 
   LIMIT 1
   ) as prev_name 
FROM example e1

结果表:
| 身份证|dt|名称|价值|上一个名称|
| --------------|--------------|--------------|--------------|--------------|
| 0| 2017-01-14 2017-01-14|福|一个|(空)|
| 1| 2017-01-17 2017-01-17|杆|两个|福|
| 二|2017-01-18 2017-01-18|约翰|五|杆|
| 三|2017-01-19 2017-01-19 2017-01-19|母鹿|十|约翰|
现在,这个工作正常。但是,如果我可以轻松地从前一行中选择 * 多个 * 列,则会更好,结果如下:
| 身份证|dt|名称|价值|上一个名称|前值|上一个dt|
| --------------|--------------|--------------|--------------|--------------|--------------|--------------|
| 0| 2017-01-14 2017-01-14|福|一个|(空)|(空)|(空)|
| 1| 2017-01-17 2017-01-17|杆|两个|福|一个|2017-01-14 2017-01-14|
| 二|2017-01-18 2017-01-18|约翰|五|杆|两个|2017-01-17 2017-01-17|
| 三|2017-01-19 2017-01-19 2017-01-19|母鹿|十|约翰|五|2017-01-18 2017-01-18|
这当然可以通过简单地将子查询(SELECT [..] FROM example e2 ...)多次复制到查询中来实现,但我想这不是最好的方法。我发现了几个关于SO的问题,要么解决“如何从前一行选择记录”,要么解决“如何使用子查询选择多个列”的问题,但不能同时解决这两个问题。后一个问题主要是通过使用JOIN语句来解决的,但我认为这与“前一行”的情况是不可组合的。所以我的问题是有什么更好的方法来产生最后一个结果,而不是为我们需要的每一列复制一个子查询?

**编辑。**作为一个额外的约束,我没有包括在原来的问题中,“previous”实际上可以是与前一行不同的东西,而是“满足条件的前一行”。假设我的表包含一个额外的booleanb

身份证dt名称价值B
02017-01-14 2017-01-14一个1
12017-01-17 2017-01-17两个0
2017-01-18 2017-01-18约翰1
2017-01-19 2017-01-19 2017-01-19母鹿0

我希望“previous row”是b = 1的前一行,因此期望的结果是:
| 身份证|dt|名称|价值|B|上一个名称|前值|上一个dt|
| --------------|--------------|--------------|--------------|--------------|--------------|--------------|--------------|
| 0| 2017-01-14 2017-01-14|福|一个|1|(空)|(空)|(空)|
| 1| 2017-01-17 2017-01-17|杆|两个|0|福|一个|2017-01-14 2017-01-14|
| 二|2017-01-18 2017-01-18|约翰|五|1|福|一个|2017-01-14 2017-01-14|
| 三|2017-01-19 2017-01-19 2017-01-19|母鹿|十|0|约翰|五|2017-01-18 2017-01-18|
我认为这仍然可以通过James Scott的答案来实现,只需在b = 1时使用IF-语句更新变量,但在这种情况下可能有另一种解决方案。

**EDIT.**SQLfiddle

hc8w905p

hc8w905p1#

类似这样的操作将返回'previous'行的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;

我将把返回与此行关联的其余数据的工作留给读者作为练习。

elcex8rz

elcex8rz2#

看起来是会话变量的一个很好的用例,如果你只想要前一行,你可以使用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;

当我第一次发布的时候就搞砸了,注意变量必须在从前一行返回后设置。若要对列重新排序(如果需要),可以将此查询 Package 在另一个查询中,然后重新排序结果列。
如果你还需要什么就告诉我,
致上,
詹姆斯

相关问题