最後爲了在PostgreSQL: 我有一個有3列一個表:PostgreSQL的選擇每個客戶的每日期範圍
CustomerNum, OrderNum, OrderDate
。
對於每個日期範圍內的每個客戶,可能(或可能不)有很多訂單。我需要的是位於提供的日期範圍內的每個客戶的最後一個OrderNum。 我一直在做的是獲得客戶的ResultSet並分別查詢每個客戶,但這需要花費太多時間。
是否有任何方式使用子選擇選擇客戶,然後獲取每個客戶的最後一個OrderNum?
最後爲了在PostgreSQL: 我有一個有3列一個表:PostgreSQL的選擇每個客戶的每日期範圍
CustomerNum, OrderNum, OrderDate
。
對於每個日期範圍內的每個客戶,可能(或可能不)有很多訂單。我需要的是位於提供的日期範圍內的每個客戶的最後一個OrderNum。 我一直在做的是獲得客戶的ResultSet並分別查詢每個客戶,但這需要花費太多時間。
是否有任何方式使用子選擇選擇客戶,然後獲取每個客戶的最後一個OrderNum?
select customernum, max(ordernum)
from table
where orderdate between '...' and '...'
group by customernum
僅此而已。
SELECT t1.CustomerNum, t1.OrderNum As LastOrderNum, t1.LastOrderDate
FROM table1 As t1
WHERE t1.OrderDate = (SELECT MAX(t2.OrderDate)
FROM table1 t2
WHERE t1.CustomerNum = t2.CustomerNum
AND t2.OrderDate BETWEEN date1 AND date2)
AND t1.OrderDate BETWEEN date1 AND date2
這將導致一個使用外部全表掃描和內部子查詢嵌套循環,因爲Postgresql無法通過子查詢中的聚合提升OrderDate範圍約束。添加AND t1.OrderDate BETWEEN date1和date2將允許它在OrderDate上使用索引來限制結果集。 – 2009-10-20 20:50:24
@Ants:Postgre真的不夠聰明,使用子查詢作爲嵌套循環連接中的外部表嗎? – erikkallen 2009-10-20 21:08:27
不知道你的客戶表的結構或關係,但這應該工作:
SELECT Customer.Num, (
SELECT OrderNum FROM Orders WHERE CustomerNum = Customer.Num AND OrderDate BETWEEN :start AND :end ORDER BY OrderNum DESC LIMIT 1
) AS LastOrderNum
FROM Customer
如果最後一個訂單號碼,你的意思是最大的訂單號碼,然後你可以用你的選擇作謂語,爲客戶NUM ,組結果和選擇最大:
SELECT CustomerNum, MAX(OrderNum) AS LastOrderNum
FROM Orders
WHERE
CustomerNum IN (SELECT CustomerNum FROM ...)
AND
OrderDate BETWEEN :first_date AND :last_date
GROUP BY CustomerNum
如果最後一個訂單號不一定是最大的訂單數,那麼你要麼需要爲每個客戶找到最大的訂單日期,並與一起加入吧其餘的命令找到t他對應的號碼:
SELECT O.CustomerNum, O.OrderNum AS LastOrderNum
FROM
(SELECT CustomerNum, MAX(OrderDate) AS OrderDate
FROM Orders
WHERE
OrderDate BETWEEN :first_date AND :last_date
AND
CustomerNum IN (SELECT CustomerNum FROM ...)
GROUP BY CustomerNum
) AS CustLatest
INNER JOIN
Orders AS O USING (CustomerNum, OrderDate);
在Postgres的,你也可以使用非標DISTINCT ON
條款:
SELECT DISTINCT ON (CustomerNum) CustomerNum, OrderNum, OrderDate
FROM Orders
WHERE OrderDate BETWEEN 'yesterday' AND 'today'
ORDER BY CustomerNum, OrderDate DESC;
見http://www.postgresql.org/docs/current/static/sql-select.html#SQL-DISTINCT
即使它不是標準的SQL,它也是這個問題的最佳答案。謝謝 – jlandercy 2015-10-07 09:01:14
比其他解決方案更快,它在26萬行的表格上給了我35秒的結果。也可以使用不在分組中的字段,如: 'SELECT DISTINCT ON(field(s))* FROM ...' – 2017-04-06 19:39:04
-- generate some data
DROP TABLE tmp.orders;
CREATE TABLE tmp.orders
(id INTEGER NOT NULL
, odate DATE NOT NULL
, payload VARCHAR
)
;
ALTER TABLE tmp.orders ADD PRIMARY KEY (id,odate);
INSERT INTO tmp.orders(id,odate,payload) VALUES
(1, '2011-10-04' , 'one')
, (1, '2011-10-24' , 'two')
, (1, '2011-10-25' , 'three')
, (1, '2011-10-26' , 'four')
, (2, '2011-10-23' , 'five')
, (2, '2011-10-24' , 'six')
;
-- CTE to the rescue ...
WITH sel AS (
SELECT * FROM tmp.orders
WHERE odate BETWEEN '2011-10-23' AND '2011-10-24'
)
SELECT * FROM sel s0
WHERE NOT EXISTS (
SELECT * FROM sel sx
WHERE sx.id = s0.id
AND sx.odate > s0.odate
)
;
結果:
DROP TABLE
CREATE TABLE
NOTICE: ALTER TABLE/ADD PRIMARY KEY will create implicit index "orders_pkey" for table "orders"
ALTER TABLE
INSERT 0 6
id | odate | payload
----+------------+---------
1 | 2011-10-24 | two
2 | 2011-10-24 | six
(2 rows)
這就是我要說的。它只需要一個小組。 – 2009-10-20 20:50:21
「OrderNum」是一個順序值的假設可能不成立,或者簡單地說創建順序可能與日期順序不匹配(例如,OrderDate可能會標記訂單已完成的時間,而不是創建時間,並且你關心最終的時間)。 – 2017-06-21 15:07:39