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 的另一个好处是:它可以帮助您从简单到复杂逐步增量地构建查询。阅读有关 Read-eval-print 循环的内容:https://en.wikipedia.org/wiki/REPL
稍后我会添加更多内容。
你可以在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小提琴
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 );
Query 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 |
请注意,如果您有两个或多个具有相同时间戳的订单,则会有不同的输出!看来你根本没有想过这种可能性——但既然有可能,它最终就会发生。
Now, 返回 CTE 和 REPL.
当您逐步构建查询时,从第一个模糊的想法到特定的行,最好检查输出数据是否正是您所期望的。 “大象大不如小块吃”。
在这里我将向您展示查询的逐步构建。
如果您在上面链接的 SQL Fiddle 中重复这些步骤,将会很有用。
首先,我创建并填充了表。
然后我发出第一个查询只是为了检查我是否正确填充了它们。
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:最后一步也是保存测试二级查询,并在它们之上编写最终的第三级查询,给出最终的过滤数据
然而,更有效的解决方案可以使用一次性连接查询(我在上面介绍的一个)Step 3.并另存为x
)并添加order by detail_id, modified desc
然后使用窗口函数Firebird 3 中引入。
这是使用该方法对类似问题的答案 -Firebird 从表中选择不同的一个字段
不过,窗口函数在 Firebird 2.x 中不可用。