2010-01-22 35 views
5

Chỉnh sửa 1 (làm rõ): Cảm ơn bạn đã trả lời cho đến nay! Câu trả lời là hài lòng.
Tôi muốn làm rõ câu hỏi một chút vì dựa trên câu trả lời Tôi nghĩ rằng tôi đã không mô tả một khía cạnh của vấn đề một cách chính xác (và tôi chắc chắn đó là lỗi của tôi vì tôi đã có một thời gian khó xác định nó ngay cả cho bản thân mình).
Đây là chà: Tập kết quả chỉ nên chứa các bản ghi với tstamp GIỮA '2010-01-03' VÀ '2010-01-09', và một bản ghi trong đó tstamp IS NULL cho mỗi order_num trong lần đầu tiên được đặt (sẽ có luôn là là một giá trị có tstamp không cho mỗi đơn đặt hàng).
Các câu trả lời được đưa ra cho đến nay dường như bao gồm tất cả bản ghi cho một trật tự nhất định nếu có bất kỳ với tstamp GIỮA '2010-01-03' VÀ '2010-01-09'. Ví dụ: nếu có một bản ghi khác với order_num = 2 và tstamp = 2010-01-12 00:00:00 thì phải không phải là trong kết quả.SQL hiệu quả hơn sử dụng "A UNION (B in A)"?

gốc câu hỏi:
Hãy xem xét một bảng lệnh chứa id (unique), order_num, tstamp (một timestamp) và item_id (các mục duy nhất bao gồm trong một thứ tự). tstamp là null, trừ khi thứ tự đã được sửa đổi, trong trường hợp đó có một bản ghi khác với order_num giống hệt nhau và tstamp sau đó chứa dấu thời gian khi thay đổi xảy ra.

Ví dụ ...

 
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 

các câu lệnh SQL hiệu quả nhất để lấy tất cả các đơn đặt hàng (dựa trên order_num) mà đã được sửa đổi một hoặc nhiều lần trong một phạm vi ngày nhất định là gì? Nói cách khác, đối với mỗi đơn đặt hàng chúng tôi cần tất cả các hồ sơ với cùng một order_num (bao gồm cả một với NULL tstamp), cho mỗi order_num WHERE ít nhất một trong số order_num có tstamp NOT NULL và tstamp BETWEEN '2010-01-03' VÀ '2010-01-09'. Đó là "WHERE ít nhất một trong số order_num có tstamp NOT NULL" mà tôi đang gặp khó khăn với.

Tập kết quả sẽ giống như thế này:

 
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 mà tôi đã đưa ra là thế này, mà chủ yếu là "Một UNION (B trong A)", nhưng nó thực thi chậm và tôi hy vọng có là một giải pháp hiệu quả hơn:

 
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

Tôi tò mò về hiệu suất của các truy vấn được cung cấp, có thể bạn có thể chia sẻ kết quả kiểm tra? –

+0

Tôi sẽ báo cáo về cải thiện hiệu suất của giải pháp cuối cùng trong thời gian ngắn - điều đó rất quan trọng. – machinatus

Trả lời

0

Cảm ơn bạn một lần nữa vì tất cả các đề xuất. Tôi đã tìm thấy ba giải pháp hoạt động, kể cả bản gốc của tôi. Cuối cùng tôi đã thêm một số kết quả hiệu suất, mà không phải là tuyệt vời như tôi đã hy vọng. Nếu bất cứ ai có thể cải thiện điều này tôi sẽ rất vui mừng!

1) Giải pháp tốt nhất tìm thấy cho đến nay dường như là:

 
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) Tôi cũng đã cố gắng sử dụng EXISTS ở vị trí của IN, mà đòi hỏi phải có thêm mệnh đề WHERE trong SELECT lần cuối:

 
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) Và cuối cùng là giải pháp ban đầu của tôi, sử dụng UNION.

Nhận xét:
Để nhận xét về kích thước bảng, vấn đề "thế giới thực" của tôi liên quan đến 4 bảng (kết nối với tham gia bên trong) chứa 98, 2189, 43897, 785656.

Performance - Tôi chạy mỗi giải pháp ba lần và đây là kết quả thế giới thực của tôi:
1: 52, 51, 51 giây
2: 54, 54, 53 s
3: 56, 56, 56 s

+0

Bạn có chỉ mục trên order_id và tstamp không? –

+0

Không, và tôi không có quyền sửa đổi thiết kế vì đây không phải là báo cáo chính. Nó sẽ không được chạy rất thường xuyên vì vậy tôi khá hài lòng với những gì tôi có bây giờ. Không phải là tôi không quan tâm đến những cách để cải tiến thêm, chỉ vì kiến ​​thức của riêng tôi! – machinatus

3

lẽ một subquery:

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 để dễ đọc nhất trong ba giải pháp gần giống hệt nhau đầu tiên. – egrunin

+0

Vì vậy, sau khi bao gồm thay đổi cần thiết dựa trên làm rõ ("Chỉnh sửa 1") trong câu hỏi ban đầu, giải pháp của tôi là sử dụng câu trả lời này trong khi thêm truy vấn phụ vào lựa chọn đầu tiên với mệnh đề WHERE giới hạn kết quả thành tstamp GIỮA ' 2010-01-03 'AND' 2010-01-09 ' HOẶC tstamp LÀ NULL. Tôi sẽ sớm thêm một câu trả lời đầy đủ và chính xác. – machinatus

1

Trừ khi tôi đã misund erstood, một cái gì đó như thế này nên làm các trick:

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') 

Lợi ích của việc sử dụng EXISTS là nó dừng lại ngay khi nó phạt tiền trận đấu đầu tiên.

0

Hy vọng tôi có câu hỏi của bạn đúng. Điều này sẽ trả về tất cả các đơn đặt hàng có thứ tự đã được thay đổi trong dấu thời gian được cung cấp.

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

Bạn có thể tự tham gia bảng.Đơn giản hóa, điều này sẽ trông giống như:

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

Tôi biết rất muộn để làm lại nhưng tôi chỉ thấy bài đăng này và tôi nghĩ có lẽ tôi nên thử điều này một lần, truy vấn này, nó thực sự rất nhỏ so với tất cả các giải pháp trên và giải quyết mục đích.

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') 
Các vấn đề liên quan