2010-01-22 36 views
5

编辑1(说明):谢谢你到目前为止的答案!回应令人欣慰。
我想澄清一点问题,因为根据答案我认为我没有正确描述问题的一个方面(而且我确定这是我的错,因为即使对我自己也难以定义它)。
这里的问题:结果集应该只包含tstamp BETWEEN'2010-01-03'和'2010-01-09'的记录,以及一个记录,其中第一个order_num的tstamp为NULL设置(有总是是一个与每个order_num为空tstamp)。
到目前为止给出的答案似乎包括所有记录为某一order_num如果有任何与tstamp BETWEEN'2010-01-03'和'2010-01-09'。例如,如果另一条记录的order_num = 2和tstamp = 2010-01-12 00:00:00,则应将而不是包含在结果中。比使用“A UNION(B in A)”更高效的SQL?

原始问题:
考虑包含ID(唯一的),order_num,TSTAMP(时间戳)的订单表,和ITEM_ID(包含在订单单项目)。 tstamp为空,除非订单已被修改,在这种情况下,存在具有相同order_num和tstamp的另一条记录,然后包含发生更改时的时间戳。

例...

 
id order_num tstamp    item_id 
__ _________ ___________________ _______ 
0   1       100 
1   2       101 
2   2 2010-01-05 12:34:56  102 
3   3       113 
4   4       124 
5   5       135 
6   5 2010-01-07 01:23:45  136 
7   5 2010-01-07 02:46:00  137 
8   6       100 
9   6 2010-01-13 08:33:55  105 

什么是最有效的SQL语句一定的日期范围内检索所有已修改一次或多次的订单(基于order_num)的?换句话说,对于每个订单,我们需要所有具有相同order_num的记录(包括具有NULL tstamp的记录),对于每个order_num WHERE至少有一个order_num具有tstamp NOT NULL AND tstamp BETWEEN'2010-01-03' AND'2010-01-09'。这是“我至少有一个order_num有tstamp NOT NULL”,我很难。

结果集应该是这样的:

 
id order_num tstamp    item_id 
__ _________ ___________________ _______ 
1   2       101 
2   2 2010-01-05 12:34:56  102 
5   5       135 
6   5 2010-01-07 01:23:45  136 
7   5 2010-01-07 02:46:00  137 

,我想出了是这样的SQL,这基本上是“A UNION(以A-B)”,但它慢慢地执行,我希望有是一种更有效的解决方案:

 
SELECT history_orders.order_id, history_orders.tstamp, history_orders.item_id 
FROM 
    (SELECT orders.order_id, orders.tstamp, orders.item_id 
    FROM orders 
    WHERE orders.tstamp BETWEEN '2010-01-03' AND '2010-01-09') 
    AS history_orders 
UNION 
SELECT current_orders.order_id, current_orders.tstamp, current_orders.item_id 
FROM 
    (SELECT orders.order_id, orders.tstamp, orders.item_id 
    FROM orders 
    WHERE orders.tstamp IS NULL) 
    AS current_orders 
WHERE current_orders.order_id IN 
    (SELECT orders.order_id 
    FROM orders 
    WHERE orders.tstamp BETWEEN '2010-01-03' AND '2010-01-09'); 
+0

我很好奇提供的查询的性能,也许你可以分享测试结果? – 2010-01-22 21:38:53

+0

我会尽快报告最终解决方案的性能改进情况 - 这很重要。 – machinatus 2010-01-25 15:03:21

回答

0

再次感谢您的所有建议。我发现了三种解决方案,包括我的原创。最后,我添加了一些表现结果,这些结果并不像我希望的那么好。如果有人能改善这一点,我会很高兴!

1)迄今为止发现的最好的解决办法似乎是:

 
SELECT history_orders.order_id, history_orders.tstamp, history_orders.item_id 
FROM 
    (SELECT orders.order_id, orders.tstamp, orders.item_id 
    FROM orders 
    WHERE orders.tstamp BETWEEN '2010-01-03' AND '2010-01-09' 
    OR orders.tstamp IS NULL) 
    AS history_orders 
WHERE history_orders.order_id IN 
    (SELECT orders.order_id 
    FROM orders 
    WHERE orders.tstamp BETWEEN '2010-01-03' AND '2010-01-09'); 

2)我使用EXISTS到位的,这需要一个额外的也试过WHERE子句中的最后一个SELECT:

 
SELECT history_orders.order_id, history_orders.tstamp, history_orders.item_id 
FROM 
    (SELECT orders.order_id, orders.tstamp, orders.item_id 
    FROM orders 
    WHERE orders.tstamp BETWEEN '2010-01-03' AND '2010-01-09' 
    OR orders.tstamp IS NULL) 
    AS history_orders 
WHERE EXISTS 
    (SELECT orders.order_id 
    FROM orders 
    WHERE history_orders.order_id = orders.order_id 
    AND orders.tstamp BETWEEN '2010-01-03' AND '2010-01-09'); 

3)最后是我的原始解决方案,使用UNION。

评论:
要在表的大小进行评论,我实际的“现实世界”的问题涉及含98,2189,43897,785656条记录分别为4个表(带内连接连接)。

性能 - 我跑了每个解决方案的三倍,这里是我的真实世界的结果:
1:52,51,51秒
2:54,54,53号
3:56,56,第56号

+0

你在order_id和tstamp上有索引吗? – 2010-01-25 22:12:13

+0

不,我没有权力修改设计,因为这不是关键报告。它不会经常运行,所以我对我现在拥有的东西非常满意。不是说我没有兴趣进一步改进事情,只是为了我自己的知识! – machinatus 2010-01-27 16:03:20

3

也许一个子查询:

select * from order o where o.order_num in (select distinct 
    order_num from order where tstamp between '2010-01-03' and '2010-01-09') 
+0

+1是前三种几乎相同的解决方案中最具可读性的。 – egrunin 2010-01-22 21:35:48

+0

所以,在我的原始问题中包含根据我的说明(“编辑1”)所需的更改后,我的解决方案是使用此答案,同时将WHERE子句添加到第一个选择的子查询中,结果限制为 tstamp BETWEEN' 2010-01-03'AND'2010-01-09' OR tstamp IS NULL。 我会尽快添加一个完整正确的答案。 – machinatus 2010-01-25 15:02:46

1

,我就必须misund erstood,这样的事情应该做的伎俩:

SELECT o1.id, o1.order_num, o.tstamp, o.item_id 
FROM orders o1 
WHERE EXISTS(
    SELECT * FROM orders o2 
    WHERE o1.order_num = o2.order_num 
     AND o2.tstamp BETWEEN '2010-01-03' AND '2010-01-09') 

使用EXISTS的好处是,它一旦停止,因为罚款的第一场比赛。

0

希望我的问题得到了解决。这应该返回订单上已提交的时间戳内已更改的所有订单。

SELECT o.order_id, o.tstamp, o.item_id 
FROM orders o 
JOIN (SELECT DISTINCT o2.order_num 
     FROM orders o2 
     WHERE o2.tstamp BETWEEN '2010-01-03' AND '2010-01-09') o3 
ON (o3.order_num = o.order_num) 
0

您可以自行加入表格。简化后,这看起来像:

select order_id 
from orders all_orders 
inner join orders not_null_orders 
    on all_orders.order_id = not_null_orders.order_id 
where 
    not_null_orders.tstamp is not null 
    and all_orders.tstamp between '2010-01-03' AND '2010-01-09' 
1

我知道现在已经很晚了,但是我刚刚看到这篇文章,我想也许我应该试试这个,这个查询如何,与上述所有解决方案相比,它非常小,并且解决了这个问题。

select * from orders_gc where order_num in 
    (select order_num 
    from orders_gc 
    group by order_num 
    having count(id) > 1 and 
    MAX(tstamp) between '03-jan-2010' and '09-jan-2010') 
相关问题