2011-02-26 20 views
2

我正在嘗試爲保留系統編寫SQL查詢以查找某個項目的最早可用租用日期。使用SQL查詢幫助查找預訂系統的下一個可用日期

項目按SKU在數據庫中進行分類。一個項目可以有多個副本,每個副本在數據庫中通過序列號唯一標識。

當搜索物品的最早可用租賃日期時,選擇哪個序列號並不重要;只需下一個可用。

該數據庫有2個表; 「預訂」和「項目」。還有一個包含數千個YYYY-MM-DD未來日期的日曆表格。

保留表包含列; 「record_number」,「sku」,「serial_number」,「start_date」,「end_date」加上客戶數據。這是每個預訂在製作時都被記錄的地方。

Items表包含列; 「sku」和「serial_number」。這是系統中所有租賃項目的清單。

我已經解決了這個問題超過2天了,但是我的SQL知識還不足以解決這個難題。

據我已經進步爲生成具有特定SKU至少一個預約日期列表:

SELECT calendar.dt 
    FROM calendar 
LEFT JOIN reservations ON calendar.dt >= reservations.start_date 
         AND calendar.dt <= reservations.end_date 
    WHERE reservations.sku = 'ABC123' 

我能子查詢以上變成了「NOT IN ......」 select語句,但只能完成對特定SKU沒有保留的查找日期。我需要找到至少有一個項目可用的第一個日期。

我想象過從Calendar表中將SKU與Item中的SKU結合起來,預訂表中的預留號在reservation_record中查找「NULL」,表示該日期和序列號組合中沒有預留。但是我一直無法寫出這樣的查詢。

歡迎提問。

回答

0

請求開始和結束日期是某人想要保留給定項目的時間段。 (例如,「我想在7月和9月之間的某個時間預訂小部件」)

修改爲處理現有庫存。雖然目前還不清楚這是如何實際存儲的。您是否擁有每個SKU的現有價值,或者每個商品是否擁有自己的行?

Select Min(C.dt) As EarliestAvailableDate 
From Calendar As C 
    Left Join Reservations As R 
     On R.StartDate <= C.dt 
      And R.EndDate >= C.dt 
      And R.Sku = 'ABC123' 
Where C.dt Between '[Request Start Date]' And '[Request End Date]' 
    And R.record_number Is Null 
    And Exists (
       Select 1 
       From Items As I1 
        Left Join Reservations As R1 
         On R1.StartDate <= C.dt 
          And R1.EndDate >= C.dt 
          And R1.Sku = I1.SKU 
       Where I.SKU = 'ABC123' 
       Having Count(*) > Count(R1.record_number) 
       ) 

如果你的項目表實際存儲爲一個給定的SKU的庫存數的手頭值,然後喲可以簡單地改變像這樣的查詢:

Select Min(C.dt) As EarliestAvailableDate 
From Calendar As C 
    Left Join Reservations As R 
     On R.StartDate <= C.dt 
      And R.EndDate >= C.dt 
      And R.Sku = 'ABC123' 
Where C.dt Between '[Request Start Date]' And '[Request End Date]' 
    And R.record_number Is Null 
    And Exists (
       Select 1 
       From Items As I1 
        Left Join Reservations As R1 
         On R1.StartDate <= C.dt 
          And R1.EndDate >= C.dt 
          And R1.Sku = I1.SKU 
       Where I.SKU = 'ABC123' 
       Having I1.OnHandCount > Count(R1.record_number) 
       ) 
+0

該查詢會過濾掉有預留的日期,但是有足夠的物品可以進行更多的預訂。 – 2011-02-26 01:52:46

+0

@Eran Galperin - 給出關於商品表的假設的簡單修復。目前尚不清楚如何管理庫存。每件商品是否都有自己的排或者是否有現貨價值? OP在這一點上並不清楚。 – Thomas 2011-02-26 03:08:42

1

不幸的是,你可以不尋找缺失的行(你可以找到不存在的行,但不一樣)。

你有一個很好的開始,查詢日曆表,並保留加入到保留,但你犯了一個錯誤,將過濾條件放在WHERE子句中,它將不返回行,而不是返回join ON子句。

SELECT calendar.dt, 
    COUNT(DISTINCT reservations.id) AS reserved, 
    COUNT(DISTINCT items.id) AS inventory 
FROM calendar 
LEFT JOIN reservations 
    ON calendar.dt >= reservations.start_date 
    AND calendar.dt <= reservations.end_date 
    AND reservations.sku = 'ABC123' 
LEFT JOIN items ON items.sku=reservations.sku 
GROUP BY calendar.dt 
HAVING inventory > reserved OR reserved = 0 
ORDER BY calendar.dt ASC 
LIMIT 1 

這個查詢會在日曆表的最早日期凡在項目表項目的現有數量比預訂的(如果你有可用庫存即,第一日期)日期的數量。

編輯:替補「身份證」與表中的主列)

1

我從一個SQL專家在很久以前學到了真正有價值的一課。

不要讓你失明,你需要什麼。考慮在現實世界中使用預訂的位置。

  • 酒店
  • 航空公司
  • 遊船
  • 阿里納斯
  • 足球場

每其中之一有在某一天座椅固定庫存。這些席位中的每一個都可能是開放的或保留的 - 與特定客戶綁定。

您在特定的一天有固定的物品庫存。這些項目中的每一個都可能是可用的或保留的 - 綁定到特定的客戶。

我認爲如果您創建了可用性表格而不是保留表格,您的生活將會輕鬆許多。

create table availability (
    sku varchar(15) not null, 
    sn varchar(15) not null, 
    av_date date not null, 
    customer_id integer, --references customers (customer_id) 
    primary key (sku, sn, av_date), 
    foreign key (sku, sn) references items (sku, sn) 
); 

insert into availability values 
('1', '1', '2011-01-01', 1), -- reserved by customer_id 1 
('1', '1', '2011-01-02', 1), 
('1', '1', '2011-01-03', 1), 
('1', '1', '2011-01-04', NULL), -- not yet reserved 
('1', '1', '2011-01-05', NULL), 
('1', '1', '2011-01-06', NULL), 
('1', '1', '2011-01-07', NULL), 
('1', '1', '2011-01-08', NULL), 
('1', '1', '2011-01-09', NULL), 
('1', '1', '2011-01-10', NULL), 
('1', '2', '2011-01-01', NULL), 
('1', '2', '2011-01-02', 2), 
('1', '2', '2011-01-03', 2), 
('1', '2', '2011-01-04', 3), 
('1', '2', '2011-01-05', 3), 
('1', '2', '2011-01-06', NULL), 
('1', '2', '2011-01-07', NULL), 
('1', '2', '2011-01-08', NULL), 
('1', '2', '2011-01-09', NULL), 
('1', '2', '2011-01-10', NULL); 

(對於生產,我會建立一個存儲過程來填充可用表。)

現在它只是死的簡單選擇一個給定的SKU日期最早可以追溯到。

select sku, sn, av_date, customer_id 
from availability 
where sku = '1' and customer_id is null 
order by av_date asc 
limit 1 
+0

這些都是來自每個人的奇妙建議。感謝您分享你的知識。我會閱讀它們並嘗試理解每一個,以便我可以決定下一步該做什麼。 – Daitod 2011-03-04 18:50:47

+0

我理解這個解決方案,但是如果我有幾十個SKU x幾十個序列號x數千個未來日期......那麼產生的表格是不是怪物?什麼時候MySQL表中的行數變得太多了? – Daitod 2011-03-04 19:05:18

+0

@Daitod:數百萬行並不少見。但是在你提交之前你應該測試幾種不同的解決方案。 – 2011-03-04 19:40:34

2

以下內容應該可以幫助您。你可能想調整我的「Current_Date()」函數的樣本,無論你的預訂開始日期和外出這麼多天是什麼......

這在查詢中使用MySQL內聯變量。內部查詢是基於某個開始日期(current_date())的預留(@r)變量的簡單準備,並加入到項目表中。通過不加入連接條款,否則它會爲每個項目獲取一個日期。在我的情況下,我只考慮30天外出,所以我已經應用了前30項的限制。除了給我足夠的記錄外,沒有其他的基礎,所以我不必創建一個包含30條記錄的臨時表(或者你想出去的天數很多)。這將創建一個別名查詢「JustDates」,並具有一個「OpenDate」列。這是測試日期範圍的基礎。

這是現在加入到物品表,但沒有條件創建笛卡兒說每個日期,比較每個項目...根據WHERE子句,我只關心具有「ABC123」天氣的SKU項目他們有10個序列號或100.這現在會給我一個可能的300或3000(10個連續項目30天,或100個連續項目30天)

現在,我有一個「範圍」序列號和可能的日子來檢查可用性,我現在可以查詢預訂系統。因此,通過一個子選擇,而不是對於一個給定的匹配SKU,SERIAL#和在預訂中找到的POSSIBLE日期,我只想保留那些沒有找到給定OpenDate的地方。我已經模擬了你的桌子結構,並放入了少數幾個項目,多個序列號和錯誤的預約日期範圍,並且它的效果很好...

顯然,我會確保sku/serial的性能指標。我可能做出的唯一額外更改是在查詢預訂時,排除任何結束日期早於您的查詢的開始日期之前的預訂,並且可以選擇沒有開始日期>您正在考慮的最後日期。如果你有多年的保留時間,那些關心古代事物的人,或者在相關日期範圍內的某種方式。

select items.sku, 
     items.serial_number, 
     JustDates.OpenDate 
    from 
     (SELECT 
       @r:= date_add(@r, interval 1 day) OpenDate 
      FROM 
       (select @r := current_date()) vars, 
       items limit 30) JustDates, 
     items 
    where 
      sku = "ABC123" 
     and sku not in (select sku from Reservations 
          where items.sku = reservations.sku 
           and items.serial_number = reservations.serial_number 
           and justDates.OpenDate >= reservations.start_date 
           and justDates.OpenDate <= reservations.end_date) 
    order by 
     items.serial_number, 
     justDates.OpenDate