我找不到解决问题的方法。我有两个表Order和OrderDetail。
订单表 (简单版本)
| ID | modified |
| 1 | 7.1.2018. |
| 2 | 10.1.2018.|
| 3 | 15.1.2018.|
| 4 | 20.1.2018.|
| 5 | 25.1.2018.|
OrderDetails (简单版本)
| 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.|
我知道要联接表,并从具有期望列的联接表中获取所有行,但是我不知道如何从每个 order_id,detail_id 对中仅过滤具有最新时间戳的行。请,任何帮助将不胜感激。
Firebird 数据库需要查询。
第一个样本数据在某种程度上具有误导性。请再次查看扩展表和期望的结果。 我需要所有不同的行(基于“ details_id”)及其上次修改的数据。如何使用较旧的时间戳排除每个“ detail_id”的“重复”行,而仅保留具有最新时间戳的“ detail_id”行?
答案 0 :(得分:1)
这解决了问题的前两个版本。
对于每个详细记录,您都需要最新的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
);
答案 1 :(得分: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
这里我们使用通用表表达式,因此我们仅将两个表连接一次。 至少在编写查询时,我们只做过一次-因此,我们出现错别字或复制粘贴错误的机会会更少。 我们还暗示SQL Server仅执行一次连接,然后重用它,但是它是否遵循此提示-取决于其内部实现。
关于CTE的另一件好事:它可以帮助您逐步地从简单到复杂地构建查询。在https://en.wikipedia.org/wiki/REPL上了解有关Read-eval-print循环的信息
我稍后会再添加一些。
您可以在Google中找到许多有关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和REPL 。
在逐步构建查询时,从第一个模糊的主意到特定的行,最好检查输出数据是否确实符合您的期望。 “大大象最好被小块吃掉。”
在这里,我将向您展示逐步构建查询的过程。 如果您在上面链接的SQL Fiddle中重复这些步骤,将很有用。
首先,我创建并填充了表格。
然后,我发出第一个查询只是为了检查是否正确填充了它们。
1:select * from orders
-在SQL小提琴(或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中引入的 Window Functions 。
以下是使用该方法的类似问题的答案-Firebird select from table distinct one field
窗口功能在Firebird 2.x中不可用。
答案 2 :(得分:0)
您可以尝试此查询。根据修改后的日期从订单表中获取最上面的行,然后将该行与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