简体   繁体   English

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

[英]Selecting multiple columns from previous row in MySQL

Suppose I have a table like this: 假设我有一个这样的表:

| 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 |

(where date need not necessarily be ordered) date不必一定要订购)

I want to be able to select some values of the previous row (based on date ). 我希望能够选择一行的某些值(基于date )。 Such a functionality can be achieved by the following query: 可以通过以下查询来实现这种功能:

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

with resulting table: 与结果表:

| 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 |

Now, this works just fine. 现在,这很好。 However, it would be preferable if I could easily select multiple columns from the previous row, resulting in a result like: 但是,如果我可以轻松地从上一行中选择多个列,那么结果将是更好的:

| 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 |

This can of course be accomplished by simply copying the subquery (SELECT [..] FROM example e2 ...) into the query multiple times, but I guess this is not the preferable way to go. 当然,这可以通过简单地将子查询(SELECT [..] FROM example e2 ...)复制到查询中多次来实现,但是我想这不是最好的选择。 I have found several question on SO addressing either the "how to select records from a previous row" or the "how to select multiple columns using subqueries" problem, but not both. 我发现在SO解决或者若干问题的还是 “如何使用子查询的选择多列”问题“如何从前一行选择记录”,但不能同时使用。 The latter problem is then mostly solved by using a JOIN statement, but I think this is not combinable with the "previous row" case. 然后,可以通过使用JOIN语句解决后一个问题,但是我认为这不能与“上一行”情况结合使用。 So my question is: what would be a better way to produce the last result, rather then copying a subquery for every column we need? 所以我的问题是:有什么更好的方法来产生最后的结果,而不是为我们需要的每一列复制一个子查询?

EDIT. 编辑。 As an extra constraint, that I did not include in the original question, "previous" could actually be something different from the previous row, but rather "the previous row that satisfies a condition". 作为一个额外的约束,我没有在原始问题中包括,“上一个”实际上可能与上一行有所不同,而是“满足条件的上一行”。 So suppose my table contains an extra boolean column b 因此,假设我的表包含一个额外的booleanb

| 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 |

I would want the "previous row" to be the previous row with b = 1 , so the desired result would be: 我希望“上一行”是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 |

I think this can still be accomplished by James Scott's answer, by simply only updating the variables when b = 1 , using an IF -statement, but maybe there is another solution possible in this case. 我认为这仍然可以通过James Scott的答案来实现,只需使用IF语句仅在b = 1时更新变量即可,但在这种情况下也许还有另一种解决方案。

EDIT. 编辑。 SQLfiddle SQL小提琴

Looks like a good use case for session variables if you only want the previous row, you can use ORDER BY to get different results. 如果只需要上一行,则看起来是会话变量的好用例,则可以使用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;

Messed this up when I first posted, note that the variables must be set after they are returned from the previous row. 当我第一次发布时感到困惑,请注意,必须在从上一行返回变量后对其进行设置。 To reorder the columns (if desired) you can wrap this query in another that then reorders the result columns. 要对列进行重新排序(如果需要),可以将此查询包装在另一个查询中,然后对结果列重新排序。

Let me know if you need anything else, 需要帮助请叫我,

Regards, 问候,

James 詹姆士

Something like this will return the id of the 'previous' row. 这样的事情将返回“上一个”行的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;

I'll leave the business of returning the rest of the data associated with this row as an exercise for the reader. 我将剩下的工作是返回与该行关联的其余数据,作为读者的练习。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM