2017-08-25 45 views
0

假设我有一个这样的表:选择在MySQL从以前的行多列

| 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”实际上可能与前一行有所不同,而是“满足条件的前一行”。因此,假设我的表中包含一个额外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 | 

我想“前行”是上一行与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 -statement的变量,但在这种情况下可能有另一种解决方案。

编辑。SQLfiddle

+0

为防万一你已经阅读我的答案,我犯了一个错误,现在已经纠正了这个问题 –

+0

你想实现什么?请评论你的问题陈述。 – Imran

+0

我想要选择所有的行,例如前一行的值为'x',名称'y'等。这可以通过在SELECT * FROM([query])中嵌入我要查询的查询作为temp WHERE prev_name = [...]和prev_value = [..]'。此外,我的原始问题还没有完全完成,我在编辑中添加了一些额外的信息。 – konewka

回答

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; 

我将离开返回与此行相关的其余数据作为读者练习的业务。

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; 

当我第一次发布的时候就搞砸了,注意变量必须在从前一行返回后设置。要重新排序列(如果需要),可以将此查询包装到另一个中,然后对结果列进行重新排序。

让我知道如果你需要任何东西,

问候,

詹姆斯

+0

我在我的问题下面的评论中也提到了一些额外的信息。如前所述,我认为您的查询可以改变为适用于我的案例,但也许还有另一种更好的解决方案 – konewka