代码之家  ›  专栏  ›  技术社区  ›  Å emsudin Tafilović

只选择具有上次修改时间戳的行,不选择具有相同ID和旧时间戳的重复行

  •  0
  • Å emsudin Tafilović  · 技术社区  · 8 年前

    我找不到解决我问题的办法。我有两张表,订单和订单详情。

    订单表 (简单版本)

    | ID | modified  |
    | 1  | 7.1.2018. |
    | 2  | 10.1.2018.|
    | 3  | 15.1.2018.|
    | 4  | 20.1.2018.|
    | 5  | 25.1.2018.|
    

    订单详细信息 (简单版本)

    | order_id | detail_id | base_price | buy_price | sell_price|
    | 1        | 1         | 99.00      | 111.00    | 122.00    |
    | 1        | 2         | 82.00      | 95.00     | 117.00    | 
    | 1        | 3         | 82.00      | 95.00     | 117.00    |
    | 2        | 4         | 95.00      | 108.00    | 119.00    | 
    | 2        | 5         | 86.00      | 94.00     | 115.00    | 
    | 2        | 1         | 82.00      | 95.00     | 117.00    |
    | 3        | 1         | 92.00      | 106.00    | 116.00    | 
    | 3        | 4         | 90.00      | 100.00    | 120.00    | 
    | 3        | 5         | 82.00      | 95.00     | 117.00    |
    | 4        | 2         | 92.00      | 106.00    | 116.00    | 
    | 4        | 3         | 90.00      | 100.00    | 120.00    | 
    | 4        | 1         | 82.00      | 95.00     | 117.00    |
    | 5        | 1         | 92.00      | 106.00    | 116.00    | 
    | 5        | 5         | 90.00      | 100.00    | 120.00    | 
    | 5        | 3         | 82.00      | 95.00     | 117.00    |
    

    如何从orderdetails表中获取与order表中最后修改的时间戳相连接的行?

    结果应该是:

    | order_id | detail_id | base_price | buy_price | sell_price | modified  |
    | 5        | 1         | 92.00      | 106.00    | 116.00     | 25.1.2018.|
    | 4        | 2         | 92.00      | 106.00    | 116.00     | 20.1.2018.|
    | 5        | 3         | 82.00      | 95.00     | 117.00     | 25.1.2018.|
    | 3        | 4         | 90.00      | 100.00    | 120.00     | 15.1.2018.|
    | 5        | 5         | 90.00      | 100.00    | 120.00     | 25.1.2018.|
    

    我知道联接表,并从具有所需列的联接表中获取所有行,但我不知道如何仅筛选具有最新时间戳的行 一对。拜托,任何帮助都会非常感谢。

    编辑

    需要查询 火鸟 数据库。

    编辑2。

    第一个样本数据有点误导人。请再看一下扩展表和期望的结果。 我需要所有不同的行(基于“details_id”)及其最后修改的数据。如何排除具有旧时间戳的每个“细节\ id”的“重复”行,并且只保留具有最新时间戳的“细节\ id”行????

    3 回复  |  直到 8 年前
        1
  •  1
  •   Arioch 'The    8 年前
    with x as (select o.modified, od.* 
               from orderDetails od, orders o
               where o.id=od.order_id)
     , mx as (select max(modified) as modified, detail_id
              from x group by detail_id)
    Select x.* from x, mx
    Where x.detail_id = mx.detail_id and x.modified=mx.modified
    

    这里我们使用公共表表达式,因此我们只连接两个表一次。 至少我们在编写查询时只做了一次——这样我们就不太可能出现打字错误或复制粘贴错误。 我们还暗示SQL Server只执行一次联接,然后重用它,但是它是否遵循这个提示-取决于它的内部实现。

    关于CTE的另一个好处是:它可以帮助您逐步地从简单到复杂地逐步构建查询。阅读阅读阅读“Eval”打印循环 https://en.wikipedia.org/wiki/REPL
    我以后再加一点。

    你可以在谷歌上找到很多关于CTE的文章。Firebird的实施记录如下: https://www.firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-dml-select.html#fblangref25-dml-select-cte

    因为我只使用非常基本的SQL,所以我相信它几乎可以在任何实际的SQL服务器上工作,包括Firebird。

    以下是查询结果和输出数据: SQL Fiddle

    PostgreSQL 9.6模式设置 :

    create table orders
     (id integer primary key,
      modified timestamp);
    create index o_m on orders(modified);  
    
    create table OrderDetails(
      order_id integer references orders(id),
      detail_id integer not null,
      base_price float,
      buy_price float,
      sell_price float );
    create index od_do on OrderDetails(detail_id, order_id);
    
    Insert into orders values
    ( 1, '2018-1-07'),
    ( 2, '2018-1-10'),
    ( 3, '2018-1-15'),
    ( 4, '2018-1-20'),
    ( 5, '2018-1-25');
    
    Insert into OrderDetails values
    (   1   ,   1   ,   99.00   ,   111.00  ,   122.00  ),
    (   1   ,   2   ,   82.00   ,   95.00   ,   117.00  ),
    (   1   ,   3   ,   82.00   ,   95.00   ,   117.00  ),
    (   2   ,   4   ,   95.00   ,   108.00  ,   119.00  ),
    (   2   ,   5   ,   86.00   ,   94.00   ,   115.00  ),
    (   2   ,   1   ,   82.00   ,   95.00   ,   117.00  ),
    (   3   ,   1   ,   92.00   ,   106.00  ,   116.00  ),
    (   3   ,   4   ,   90.00   ,   100.00  ,   120.00  ),
    (   3   ,   5   ,   82.00   ,   95.00   ,   117.00  ),
    (   4   ,   2   ,   92.00   ,   106.00  ,   116.00  ),
    (   4   ,   3   ,   90.00   ,   100.00  ,   120.00  ),
    (   4   ,   1   ,   82.00   ,   95.00   ,   117.00  ),
    (   5   ,   1   ,   92.00   ,   106.00  ,   116.00  ),
    (   5   ,   5   ,   90.00   ,   100.00  ,   120.00  ),
    (   5   ,   3   ,   82.00   ,   95.00   ,   117.00  );
    

    查询1 :

    with x as (select o.modified, od.* 
               from orderDetails od, orders o
               where o.id=od.order_id)
     , mx as (select max(modified) as modified, detail_id
              from x group by detail_id)
    Select x.* from x, mx
    Where x.detail_id = mx.detail_id and x.modified=mx.modified
    Order by detail_id
    

    Results :

    |             modified | order_id | detail_id | base_price | buy_price | sell_price |
    |----------------------|----------|-----------|------------|-----------|------------|
    | 2018-01-25T00:00:00Z |        5 |         1 |         92 |       106 |        116 |
    | 2018-01-20T00:00:00Z |        4 |         2 |         92 |       106 |        116 |
    | 2018-01-25T00:00:00Z |        5 |         3 |         82 |        95 |        117 |
    | 2018-01-15T00:00:00Z |        3 |         4 |         90 |       100 |        120 |
    | 2018-01-25T00:00:00Z |        5 |         5 |         90 |       100 |        120 |
    

    注意,如果您有两个或多个具有相同时间戳的订单,它将有不同的输出!似乎你甚至没有考虑过这种可能性——但因为它是可能的,它最终会发生。

    现在, 返回CTE并回复 .

    当您逐步构建查询时,从第一个模糊的想法到特定的行,最好检查输出数据是否正是您所期望的。”大象最好被小象吃。

    在这里,我将向您展示查询的逐步构建。 如果您在上面链接的SQL小提琴中重复这些步骤,这将非常有用。

    首先,我创建并填充了表。

    然后我发出了第一个查询,只是为了检查是否正确地填充了它们。

    1: select * from orders -尝试此操作并在SQL fiddle(或ibexpert、flamerobin等)中进一步查询

    2: select * from orderDetails

    3:然后我发出了连接查询来检查我的交叉表查询是否真的提供了有意义的输出。是的。

    select o.modified, od.* 
    from orderDetails od, orders o
    where o.id=od.order_id
    

    4:然后我想知道,我能从这个查询中得到详细信息的最后一个时间戳吗?为了检查它,我做了以下工作:1)保存了前面我做的和测试过的查询,2)在上面写了一个二级查询。它确实提取了上次更改的日期。书写和测试。

    with x as (select o.modified, od.* 
               from orderDetails od, orders o
               where o.id=od.order_id)
    Select max(modified) as modified, detail_id
      from x group by detail_id
    

    5:最后一步也是保存测试二次查询,并在二次查询之上写入最终的三次查询,给出最终筛选的数据。


    然而,更有效的解决方案是使用一次运行的连接查询(我在上面介绍的查询 第3步。 并另存为 x )添加 order by detail_id, modified desc 然后使用 窗口功能 在Firebird 3中引入。

    下面是使用该方法对类似问题的答案- Firebird select from table distinct one field

    但是,在Firebird 2.x中窗口功能不可用。

        2
  •  1
  •   Gordon Linoff    8 年前

    这解决了问题的前两个版本。

    对于每个细节记录,您需要最新的 order 记录。当你的数据被列出时,这相当于 order_id . 比日期更简单:

    select od.*
    from orderdetail od
    where od.order_id = (select max(od2.order_id)
                         from orderdetail od2
                         where od2.detail_id = od.detail_id
                        );
    
        3
  •  0
  •   Vinit    8 年前

    您可以尝试此查询。根据修改日期从订单表中获取最上面的行,然后将该行与orderdetails表内部联接。

    SELECT od.*, o.modified 
    FROM OrderDetails od
    Inner join (Select top 1 * -- get topmost row
               from [Order] 
               order by modified desc ) O on o.id = od.order_id