Chạy một truy vấn phức tạp cho mỗi ngày trong một phạm vi


9

Tôi đã có một bảng đơn đặt hàng

   Column   |            Type             |                      Modifiers                      
------------+-----------------------------+-----------------------------------------------------
 id         | integer                     | not null default nextval('orders_id_seq'::regclass)
 client_id  | integer                     | not null
 start_date | date                        | not null
 end_date   | date                        | 
 order_type | character varying           | not null

Dữ liệu không có các lệnh đứng không trùng nhau cho client_id và đôi khi là một lệnh tạm thời ghi đè lên lệnh đứng trên đó là start_date khi chúng có client_id khớp. Có các ràng buộc cấp độ ứng dụng giữ cho các đơn đặt hàng cùng loại không bị chồng chéo.

 id | client_id | start_date |  end_date  | order_type 
----+-----------+------------+------------+------------
 17 |        11 | 2014-02-05 |            | standing
 18 |        15 | 2014-07-16 | 2015-07-19 | standing
 19 |        16 | 2015-04-01 |            | standing
 20 |        16 | 2015-07-18 | 2015-07-18 | temporary

Ví dụ: trên 2015-07-18máy khách 16 có thứ tự số 20 là thứ tự hoạt động vì nó ghi đè lên thứ tự đứng số 19. Với một số phiền phức, tôi đã tìm thấy một cách truy vấn hiệu quả cho id của đơn hàng đang hoạt động vào một ngày.

    SELECT id from (
      SELECT
        id,
        first_value(id) OVER (PARTITION BY client_id ORDER BY order_type DESC) active_order_id
      FROM orders
      WHERE start_date <= ? and (end_date is null OR end_date >= ?)
    ) active_orders
    WHERE id = active_order_id

Nếu bạn truy vấn điều này với 2015-07-18tư cách là người giữ chỗ, bạn sẽ nhận được

 id 
----
 17
 18
 20

Kế hoạch truy vấn trên truy vấn này so với một số ý tưởng khác của tôi (như truy vấn phụ đếm số lượng đơn đặt hàng tạm thời cho một khách hàng vào một ngày) là khá nhỏ và tôi khá hài lòng với nó. (thiết kế của bảng, tôi không vui mừng)

Bây giờ, tôi cần tìm tất cả các đơn đặt hàng đang hoạt động cho phạm vi ngày được kết hợp với ngày họ đang hoạt động. Ví dụ, với phạm vi ngày 2015-07-18để 2015-07-19tôi muốn kết quả sau.

active_date | id 
------------+----
 2015-07-18 | 17
 2015-07-18 | 18
 2015-07-18 | 20
 2015-07-19 | 17
 2015-07-19 | 18
 2015-07-19 | 19

Lệnh 20 ghi đè thứ tự 19 trên 2015-07-18nhưng không bật 2015-07-19.

Tôi đã tìm thấy với generate_series()tôi có thể tạo ra một loạt các ngày, nhưng tôi không biết làm thế nào để tham gia cùng với điều này để có được một bảng ngày và thứ tự id. Linh cảm của tôi là một sự tham gia chéo nhưng tôi không thể tìm ra cách để làm cho công việc đó trong hoàn cảnh này.

Cảm ơn

CẬP NHẬT Đã thêm một fiddle sql .


2
Bạn có thể hiển thị một số dữ liệu ví dụ? Điều này hoạt động / không hoạt động và tạm thời không rõ ràng sau lần đọc đầu tiên.
dezso

Vâng, nó không rõ ràng. Truy vấn của bạn sẽ tìm thấy một đơn hàng cho mỗi khách hàng và nó dường như không mang tính quyết định. Nếu có từ 2 đơn hàng trở lên cho một khách hàng, với cùng loại, loại nào trong hai đơn hàng sẽ được trả lại sẽ tùy ý và khác nhau cho mỗi lần thực hiện. Vì vậy, bạn có một số ràng buộc trên bảng mà bạn chưa nói với chúng tôi hoặc truy vấn của bạn không chính xác.
ypercubeᵀᴹ

Tôi đã cập nhật câu hỏi của mình với nhiều chi tiết hơn, và vâng, có những ràng buộc về dữ liệu.
recbot

Câu trả lời:


5

Tôi sẽ sử dụng select distinct onthay vì chức năng cửa sổ, sau đó chỉ cần tham gia ngày.

select 
    distinct on (date, client_id) date, 
    id 
from orders
inner join generate_series('2015-07-18'::date, '2015-07-19'::date, '1 day') date
  on start_date <= date and (end_date is null or date <= end_date)
order by date, client_id, order_type desc

http://sqlfiddle.com/#!15/5a420/16/0

Tôi có thể giải thích nhiều hơn nếu có gì đó không rõ ràng.


Điều này không bao gồm thứ tự tạm thời / lệnh tạm thời nhưng điều đó có thể được thực hiện sau khi tham gia =)
recbot

Điều này chỉ định thứ tự giống như trong truy vấn cửa sổ của bạn. Vì vậy, đối với bất kỳ (ngày, client_id), nó sẽ chọn order_type đầu tiên theo thứ tự chữ cái đảo ngược.
Simon Perepelitsa

Sự kết hợp bên trong là hoàn hảo và sự khác biệt được chọn là dễ hiểu hơn rất nhiều (và thực hiện gần như tốt) so với cửa sổ. Bất kỳ lý do nào khác tôi không nên sử dụng các chức năng cửa sổ?
recbot

1
Đó là về nó. Tôi nghĩ distinct onthậm chí còn được tối ưu hóa hơn so với truy vấn cửa sổ. Nhân tiện, tôi nên đề cập rằng đây là một vấn đề phổ biến "hàng đầu trong nhóm" trong SQL: stackoverflow.com/questions/3800551/
trộm

Đó là một bài đọc tuyệt vời, tôi có một số nghiên cứu để làm. Nếu bạn có thời gian tôi có một phiên bản mở rộng của câu hỏi này sử dụng những gì tôi học được ở đây. dba.stackexchange.com/questions/108767/ Tôi chắc chắn tôi sẽ quay lại để cập nhật nó với những gì tôi học được từ liên kết đó. Và cảm ơn
recbot

0

Viết hàm lấy một ngày làm tham số và trả về danh sách ngày + id có đơn hàng.

Sau đó, sử dụng Gener_series như bạn đề xuất và gọi hàm qua phạm vi ngày.

Đây là một chiến lược phổ biến khi xử lý các điều kiện phức tạp trong SQL.

Tôi đã bao gồm một số mã dưới đây, nhưng câu trả lời SQL ở trên đơn giản hơn nhiều.

Đây là chức năng:

create or replace function o( date) returns setof INT AS '
SELECT id from (
 SELECT
  id,
  first_value(id) OVER (PARTITION BY client_id ORDER BY order_type DESC) active_order_id
 FROM orders
 WHERE start_date <= $1 and (end_date is null OR end_date >= $1)
) active_orders
WHERE id = active_order_id;
' LANGUAGE sql ;

Và làm thế nào để gọi nó:

select distinct d, o(d::date) 
from generate_series('2015-07-18'::date, '2015-07-19'::date, '1 day') as d;

SQLFiddle


2
Bạn có thể muốn xóa câu trả lời đó bằng một số chi tiết, mã mẫu, v.v. Vì vậy, câu trả lời này có thể bị xóa vì nó khá mơ hồ.
Max Vernon

Bạn có thể cập nhật fiddle của tôi với một ví dụ? sqlfiddle.com/#!15/5a420/3/0
recbot

Tôi đã cập nhật câu trả lời của mình để bao gồm một số mã nhưng câu trả lời ở trên đơn giản hơn.
Don Drake
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.