Menjalankan kueri yang kompleks untuk setiap tanggal dalam suatu rentang

9

Saya punya daftar pesanan

   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

Data memiliki pesanan berdiri non tumpang tindih untuk client_id dan kadang-kadang pesanan sementara yang mengesampingkan urutan berdiri pada itu start_date ketika mereka memiliki client_id yang cocok. Ada batasan level aplikasi yang membuat pesanan dari jenis yang sama tidak tumpang tindih.

 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

Sebagai contoh, pada 2015-07-18klien 16 memiliki urutan # 20 sebagai pesanan aktif karena menimpa urutan berdiri # 19. Dengan beberapa keributan saya menemukan cara yang efisien untuk menanyakan id pesanan aktif pada tanggal.

    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

Jika Anda menanyakan ini dengan 2015-07-18sebagai placeholder, Anda akan mendapatkannya

 id 
----
 17
 18
 20

Rencana kueri pada kueri ini dibandingkan dengan beberapa ide saya yang lain (seperti sub kueri yang menghitung jumlah pesanan sementara untuk seorang klien pada suatu tanggal) cukup kecil dan saya cukup senang dengannya. (Desain meja, saya tidak senang tentang)

Sekarang, saya perlu mencari semua pesanan aktif untuk rentang tanggal yang digabung dengan tanggal mereka aktif. Misalnya, dengan rentang tanggal 2015-07-18hingga 2015-07-19saya ingin hasil berikut.

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

Pesan 20 ganti pesanan 19 2015-07-18tetapi tidak aktif 2015-07-19.

Saya menemukan dengan generate_series()saya dapat menghasilkan berbagai tanggal, tetapi saya tidak tahu bagaimana cara menggabungkannya dengan ini untuk mendapatkan daftar tanggal dan memesan id. Firasat saya adalah gabungan silang tetapi saya tidak tahu bagaimana cara membuatnya bekerja dalam keadaan ini.

Terima kasih

UPDATE Menambahkan biola sql .

pengintaian
sumber
2
Bisakah Anda menampilkan beberapa contoh data? Hal-hal yang aktif / tidak aktif dan sementara ini tidak begitu jelas setelah dibaca pertama kali.
dezso
Ya, tidak jelas. Permintaan Anda akan menemukan satu pesanan per klien dan sepertinya tidak deterministik. Jika ada 2 atau lebih pesanan untuk klien, dengan tipe yang sama, yang mana dari keduanya akan dikembalikan akan berubah-ubah dan bervariasi per eksekusi. Jadi, Anda memiliki beberapa kendala di tabel yang belum Anda beri tahu kami atau kueri Anda tidak benar.
ypercubeᵀᴹ
Saya memperbarui pertanyaan saya dengan lebih banyak detail, dan ya ada kendala pada data.
Mengulang kembali

Jawaban:

5

Saya akan menggunakan select distinct onalih-alih fungsi jendela, lalu bergabung saja beberapa hari.

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

Saya bisa menguraikan lebih banyak jika ada sesuatu yang tidak jelas.

Simon Perepelitsa
sumber
Ini tidak mencakup pesanan sementara / pesanan berdiri tetapi itu bisa dilakukan setelah bergabung =)
recbot
Ini menentukan urutan yang sama seperti dalam permintaan jendela Anda. Jadi untuk setiap (tanggal, client_id) itu akan memilih urutan_pertama dalam urutan alfabet terbalik.
Simon Perepelitsa
Gabungan dalam sempurna, dan pilih yang berbeda jauh lebih mudah untuk dipahami (dan berkinerja sama baiknya) daripada jendela. Ada alasan lain saya tidak seharusnya menggunakan fungsi windowing?
Mengulang kembali
1
Itu saja. Saya pikir distinct onini lebih dioptimalkan daripada permintaan jendela. By the way, saya harus menyebutkan bahwa ini adalah masalah "top-in-group" yang umum di SQL: stackoverflow.com/questions/3800551/…
Simon Perepelitsa
Itu bacaan yang bagus, saya harus belajar. Jika Anda punya waktu, saya memiliki versi yang diperluas dari pertanyaan ini yang menggunakan apa yang saya pelajari di sini. dba.stackexchange.com/questions/108767/... Saya yakin saya akan kembali memperbaruinya dengan apa yang saya pelajari dari tautan itu. Dan Terima kasih
pengawas ulang
0

Tulis fungsi yang mengambil satu tanggal sebagai parameter dan mengembalikan daftar tanggal + id yang memiliki pesanan.

Kemudian, gunakan generate_series seperti yang Anda sarankan dan panggil fungsi tersebut pada rentang tanggal.

Ini adalah strategi umum ketika berhadapan dengan kondisi kompleks dalam SQL.

Saya sudah memasukkan beberapa kode di bawah ini, tetapi jawaban SQL di atas jauh lebih sederhana.

Inilah fungsinya:

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 ;

Dan bagaimana menyebutnya:

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

SQLFiddle

Don Drake
sumber
2
Anda mungkin ingin menyiram jawaban itu dengan beberapa perincian, kode sampel, dll. Seperti itu, jawaban ini mungkin terhapus karena cukup samar.
Max Vernon
Apakah Anda dapat memperbarui biola saya dengan contoh? sqlfiddle.com/#!15/5a420/3/0
recbot
Saya telah memperbarui jawaban saya untuk memasukkan beberapa kode tetapi jawaban di atas lebih sederhana.
Don Drake