【问题标题】:How to subtract second row from first row and generate a output column in mysql如何从第一行中减去第二行并在mysql中生成输出列
【发布时间】:2015-10-20 23:39:48
【问题描述】:

我有一个情况,考虑以下查询:

select 
    A.cakename, A.status, B.ordertime
from
    Cake as A
        inner join
    Orders as B on A.cakeid = B.cakeid

这个查询的输出

cakename,   status,      ordertime
Apple Pie, available,    2014-03-20 22:34:46
Apple Pie, available,    2014-10-10 04:00:00
Apple Pie, available,    2015-03-20 22:34:46
Brownie,   available,    2014-03-20 22:35:07
Brownie,   available,    2015-05-20 22:35:07
Brownie,   available,    2014-03-26 22:36:07
Brownie,   available,    2015-05-20 14:35:48
Brownie,   available,    2015-05-20 22:35:07
Brownie,   available,    2015-05-10 22:35:07

现在我想减去ordertime row n+1 - ordertime row n 并创建一个单独的列来存储结果。现在你可以忽略最后一行,因为没有下一行。

例如:2014-10-10 04:00:00 - 2014-03-20 22:34:46 这个等式将用于第一行,其结果将存储在新列中让我们采用difference of consecutive ordertime。谁能给我一些解决这种情况的指示?

如果您能帮助创建一个 auto increment column,那就太好了,因为这样我就可以自行加入并从中受益。

【问题讨论】:

    标签: mysql sql mysql-workbench


    【解决方案1】:

    您可以添加一个额外的计算字段:

    select 
    A.cakename, A.status, B.ordertime,
    (SELECT MAX(ordertime) FROM Orders AS C WHERE C.ordertime < B.ordertime) AS prev
    from
    Cake as A
        inner join
    Orders as B on A.cakeid = B.cakeid
    ORDER BY ordertime;
    

    但你最好在ordertime 上有一个索引:

    CREATE INDEX ord_ndx ON Orders(ordertime, cakeid);
    

    实际上,您可以直接计算the difference from the previous time(假设它不为NULL;您必须为此提供带有IF的默认值)。

    另一种方式

    但是,根据您的架构,添加列 (previous_order) 可能会更好地为您服务。当您插入订单时,您就知道自己需要什么。使用TRIGGER查看此示例:

    CREATE TABLE test ( itemid integer, ordertime timestamp, previous datetime );
    CREATE INDEX test_ndx ON test (itemid, ordertime);
    
    CREATE TRIGGER test_set_prev 
        BEFORE INSERT ON test 
        FOR EACH ROW
            SET NEW.previous = (
                SELECT MAX(ordertime) FROM test WHERE itemid = NEW.itemid
            );
    

    现在您的桌​​子会自动工作。 TIMESTAMP 列将自动更新,previous 列也将自动更新:

    insert into test (itemid) values (2);
    select sleep(2);
    insert into test (itemid) values (2);
    
    +--------+---------------------+---------------------+
    | itemid | ordertime           | previous            |
    +--------+---------------------+---------------------+
    |      2 | 2015-10-21 09:30:44 | NULL                |
    |      2 | 2015-10-21 09:30:46 | 2015-10-21 09:30:44 |
    +--------+---------------------+---------------------+
    

    它也适用于多个插入:

    insert into test (itemid) values (3), (2), (3);
    

    【讨论】:

    • 我修改了您的查询,它对我有用 :) 非常感谢
    • select A.cakename, A.status, B.ordertime, (SELECT timestampdiff(month, MAX(ordertime), B.ordertime) FROM Orders AS C WHERE C.ordertime &lt; B.ordertime and A.cakeid = C.cakeid limit 1) AS prev from Cake as A inner join Orders as B ON A.cakeid = B.cakeid ORDER BY A.cakename , B.ordertime; 这是查询
    【解决方案2】:
    SELECT t.*,
      IF(@prev IS NULL ,0 , TIMESTAMPDIFF(SECOND,t.ordertime,@prev)) diff,
      @prev = t.ordertime
    FROM (
      SELECT 
        A.cakename, A.status, B.ordertime
      FROM Cake as A
      INNER JOIN Orders as B 
      ON A.cakeid = B.cakeid
      ORDER BY ordertime 
    ) t
    

    【讨论】:

    • 向我证明并发布预期结果?你能提供用于测试的 sqlfiddle 吗?
    • 这是一个修改后的查询@Iserni 答案,它为我工作select A.cakename, A.status, B.ordertime, (SELECT timestampdiff(month, MAX(ordertime), B.ordertime) FROM Orders AS C WHERE C.ordertime &lt; B.ordertime and A.cakeid = C.cakeid limit 1) AS prev from Cake as A inner join Orders as B ON A.cakeid = B.cakeid ORDER BY A.cakename , B.ordertime;
    • 我更喜欢我的方式。但如果您喜欢您的解决方案 - 这取决于您。我很高兴你现在有一个。
    • 没有测试过,但是 Alex 的解决方案更高效,需要更少的连接,只要你订购你的行(以前的真正意思是“前一行”)。您可能没有这样做,这就是 Alex 的解决方案似乎不起作用的原因。我赞成它:-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多