我有两个具有一对多关系的表(例如,客户表和订单表;每个客户可能已经下了多个订单)。对于每个客户,我只需要检索一个订单,由特定标准(例如最近的订单)定义。
我需要在PostgreSQL 9.1和Microsoft SQL Server 2014中执行此操作(两个系统中的不同数据,但问题非常相同)。这些表约有250万条记录(客户)和1000万条记录(订单)。
我在考虑在SQL服务器中使用外部应用,并在PostgreSQL中对分区或横向连接进行排名,但对语法不太确定。
一个简单的max(order_date)
... group by clientid
就不够了,因为我需要订单表中的所有字段。例如,我需要像
c.clientid, c.client_name, o.order_id, o.order_date, o.order_amount, o.product_ordered
where c = the clients table and o = the orders table.
有什么建议吗?
答案 0 :(得分:1)
我没看到如何进行横向连接。这是一个很好的旧“最大n组”问题,可以通过普通连接和窗口函数来解决:
select *
from clients c
join (
select clientid, order_id, order_date, order_amount, product_ordered
row_number() over (partition by client_id order by order_date desc) as rn
from orders
) o on o.clientid = c.clientid and o.rn = 1;
对于Postgres,使用distinct on
代替窗口函数可以提高效率。如果你有client_id, order_date
的索引,这应该表现得相当不错。
答案 1 :(得分:0)
这是你可以做到的另一种方式。为SQL 2005编写/测试。对于大量的记录,不太确定它的性能。
SELECT
c.clientid,
c.client_name,
o.order_id,
o.order_date,
o.order_amount,
o.product_ordered
FROM c JOIN o ON c.clientid = o.clientid
WHERE order_id IN (
SELECT TOP 1 order_id
FROM o AS o2
WHERE o.clientid = o2.clientid
ORDER BY order_date DESC)
答案 2 :(得分:0)
对于SQL Server,我会使用OUTER APPLY
。
SELECT
clients.clientid
,clients.client_name
,LastOrder.order_id
,LastOrder.order_date
,LastOrder.order_amount
,LastOrder.product_ordered
FROM
clients
OUTER APPLY
(
SELECT TOP(1)
orders.order_id
,orders.order_date
,orders.order_amount
,orders.product_ordered
FROM orders
WHERE orders.clientid = clients.clientid
ORDER BY order_date DESC
) AS LastOrder
;
如果你有一个索引(orders.clientid,orders.order_date)并将其他列添加到索引中,那么OUTER APPLY
应该是对该索引的搜索。
因此,对于clients表中的每一行,应该对订单索引进行单一搜索。
如果索引不包含所有其他列,则会有搜索和查找。
如果您不想让没有任何订单的客户使用CROSS APPLY
而不是OUTER APPLY
。
我认为这种OUTER APPLY
比为所有订单生成ROW_NUMBERS()更有效,然后丢弃大部分结果并仅使用第一行。
当然,您应该使用您的系统测量不同变体的实际性能。
不幸的是,我不知道Postgres。