Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PostgreSQL选择每个日期范围内每个客户的最后订单_Sql_Postgresql_Sql Order By_Greatest N Per Group_Subquery - Fatal编程技术网

PostgreSQL选择每个日期范围内每个客户的最后订单

PostgreSQL选择每个日期范围内每个客户的最后订单,sql,postgresql,sql-order-by,greatest-n-per-group,subquery,Sql,Postgresql,Sql Order By,Greatest N Per Group,Subquery,在PostgreSQL中: 我有一个有3列的表: CustomerNum、OrderNum、OrderDate 每个日期范围内的每个客户可能有(也可能没有)多个订单。我需要的是位于所提供日期范围内的每个客户的最后一个OrderNum。 我一直在做的是获取客户的结果集并分别查询每个客户,但这花费了太多的时间 是否有任何方法可以使用子选择来选择客户,然后获取每个客户的最后一个OrderNum SELECT t1.CustomerNum, t1.OrderNum As LastOrderNum, t1

在PostgreSQL中: 我有一个有3列的表:

CustomerNum、OrderNum、OrderDate

每个日期范围内的每个客户可能有(也可能没有)多个订单。我需要的是位于所提供日期范围内的每个客户的最后一个OrderNum。 我一直在做的是获取客户的结果集并分别查询每个客户,但这花费了太多的时间

是否有任何方法可以使用子选择来选择客户,然后获取每个客户的最后一个OrderNum

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

仅此而已。

不确定客户表的结构或关系,但这应该可以:

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

如果“上一个订单号”指的是最大订单号,则您可以使用select作为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
如果最后一个订单号不一定是最大订单号,则您需要查找每个客户的最大订单日期,并将其与其他订单一起查找相应的订单号:


在postgres上,您还可以使用非标准的
DISTINCT On
子句:

SELECT DISTINCT ON (CustomerNum) CustomerNum, OrderNum, OrderDate
  FROM Orders
  WHERE OrderDate BETWEEN 'yesterday' AND 'today'
  ORDER BY CustomerNum, OrderDate DESC;

结果:

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)

这就是我要说的。所有这些都是一个分组依据。假定
OrderNum
是一个连续值可能不成立,或者创建顺序可能与日期顺序不匹配(例如,
OrderDate
可能会标记订单完成的时间,而不是创建的时间,并且您关心完成的时间)。这将导致外部完整表扫描和内部子查询的嵌套循环,因为Postgresql无法通过子查询中的聚合解除OrderDate范围约束。在date1和date2之间添加和t1.OrderDate将允许它在OrderDate上使用索引来限制结果集。@Ants:Postgre真的不够聪明,不能将子查询用作嵌套循环联接中的外部表吗?看起来是这个问题的最佳答案,即使它不是标准SQL。谢谢你比其他解决方案更快,它在一张2600万行的表格上给了我35秒的结果。这也适用于不在分组中的字段,例如:
SELECT DISTINCT ON(字段))*FROM…
SELECT DISTINCT ON (CustomerNum) CustomerNum, OrderNum, OrderDate
  FROM Orders
  WHERE OrderDate BETWEEN 'yesterday' AND 'today'
  ORDER BY CustomerNum, OrderDate DESC;
-- 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)