2017-08-29 113 views
2

我的表在這個結構中:重疊獲取客房價格日期

id accom_id room_type_id date_from date_to  price_per_room 
3 1   2    2017-09-01 2017-09-10  70.00  
5 1   2    2017-09-11 2017-09-20  100.00 

可以說,我想遠離2017年9月7日至2017年9月15日。因此,對於DATEDIFF,我需要計算價格爲70天和價格爲100天的天數。最後,我要顯示總價。

任何人都可以幫我建立這個查詢嗎?我希望它明確地問什麼!

+0

請不要使用不適用於您的問題的標籤。我刪除了數據庫標記,因爲它不清楚你實際使用了哪一個。請添加僅*的標籤*您實際使用的數據庫 –

+4

在[所以]您應該嘗試**自己編寫代碼**。後** [做更多的研究](//meta.stackoverflow.com/questions/261592)**如果你有問題,你可以**發佈你已經嘗試**與清楚的解釋是什麼是'工作**並提供[** Minimal,Complete和Verifiable示例**](// stackoverflow.com/help/mcve)。我建議閱讀[問]一個好問題和[完美問題](http://codeblog.jonskeet.uk/2010/08/29/writing-the-perfect-question/)。另外,一定要參加[遊覽]並閱讀[this](// meta.stackoverflow.com/questions/347937/)**。 –

+0

我們保證要查詢的所有日期將覆蓋行並且不存在重疊行(即從未需要提供默認值或用於消除行歧義的規則)? –

回答

2

假設沒有重疊範圍定義,並且假設所有給定的意在爲包括性的範圍的,我們可以使用獲得的數據CTE然後一個簡單的聚合問題:

declare @t table (date_from date,date_to date, price_per_room int) 
insert into @t (date_from,date_to,price_per_room) values 
('20170901','20170910',70.00), 
('20170911','20170920',100.00) 
declare @Start date 
declare @End date 
select @Start = '20170907',@End = '20170915' 

;With IncludedPeriods as (
    select 
     CASE WHEN @Start > date_from THEN @Start ELSE date_from END as fromDT, 
     CASE WHEN @End < date_to THEN @End ELSE date_to END as ToDT, 
     price_per_room 
    from 
     @t 
    where 
     date_from <= @End and 
     @Start <= date_to 
) 
select 
    SUM(price_per_room * (1 + DATEDIFF(day,fromDT,ToDT))) 
from 
    IncludedPeriods 

注意,我們要添加一個到DATEDIFF結果,因爲它計算過渡,但我假設一段「20170911」 「20170911」應該算作一天,同樣更長的時間。

不像其中一些試圖枚舉各種「箱子」爲重疊其他的答案的,這裏採用的簡單的規則 - 兩個週期重疊,如果第二前的第一次啓動結束如果第一端部之前的第二開始 - 這是CTE內where條款中應用的邏輯。爲了確定重疊的範圍,我們選取​​兩個開始日期中較晚的一個和兩個結束日期中較早的一個 - 這就是CASE表達式正在做的事情。如果我們在日期上使用了標量MINMAX函數,我寧願使用這些函數,但沒有內置到SQL Server中的函數。

-1

您可以使用日曆或日期表來處理這類事情。

如果不考慮創建一個表的實際步驟中,您可以使用日期的即席表,並common table expression像這樣:

declare @fromdate date = '20170907'; 
declare @thrudate date = '20170915'; 
;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n)) 
, dates as (
    select top (datediff(day, @fromdate, @thrudate)+1) 
     [Date]=convert(date,dateadd(day,row_number() over(order by (select 1))-1,@fromdate)) 
    from n as deka cross join n as hecto cross join n as kilo 
       cross join n as tenK cross join n as hundredK 
    order by [Date] 
) 
select total_price = sum(price_per_room) 
from dates d 
    inner join t 
    on d.date >= t.date_from 
    and d.date <= t.date_to 

rextester演示:http://rextester.com/MCF52261

回報:

+-------------+ 
| total_price | 
+-------------+ 
|   780 | 
+-------------+ 

有關價格和價格的更詳細的細分日期,您可以交換上述select這一個:

select 
    fromdate = min(date) 
    , thrudate = max(date) 
    , days = count(*) 
    , price_per_room = avg(price_per_room) 
    , total = sum(price_per_room) 
from dates d 
    inner join t 
    on d.date >= t.date_from 
    and d.date <= t.date_to 
group by grouping sets ((price_per_room),()) 

rextester演示:http://rextester.com/NKZD1468

回報:

+------------+------------+------+----------------+-------+ 
| fromdate | thrudate | days | price_per_room | total | 
+------------+------------+------+----------------+-------+ 
| 2017-09-07 | 2017-09-10 | 4 | 70    | 280 | 
| 2017-09-11 | 2017-09-15 | 5 | 100   | 500 | 
| 2017-09-07 | 2017-09-15 | 9 | 86    | 780 | 
+------------+------------+------+----------------+-------+ 


號碼和日曆表參考:

-1

我會建議使用日期表或派生表來填充這些日期(含所有日期表)(你可以在網上很容易找到它)是這樣的:

SELECT p.id,p.room_type_id,sum(p.price_per_room) 
FROM(
    SELECT t.date,s.price_per_room,s.id,s.room_type_id 
    FROM (DATES QUERY \ DATE_TABLE) t 
    LEFT JOIN s.yourTable 
    ON(t.date between s.date_from and s.date_to)) p 
WHERE p.id = YourID and p.room_type_id = YourTypeId 
AND p.date between yourStartDate and yourEndDate 
GROUP BY p.id,p.room_type_id 

用於填充行對於每一日期在價格的日期範圍內,所以它會知道每天的價格是多少,然後在所需的日期之間對價格進行總結。

0

在SQL Server中,你可以這樣做:

select dateadd(d, number, '20170801') 
from master.dbo.spt_values 
where type='P' and (number <= datediff(d, '20170801', '20170810')) 

計算的總天數(在where子句中),你從0到總天數(master.dbo.spt_values選擇號碼是SQL一個有用的表服務器)。否則,您可以創建一個從0到?的升序數字的表格)。然後你添加到開始日期的數字。所以,你得到了預訂的所有天:

2017-08-01 
2017-08-02 
2017-08-03 
2017-08-04 
2017-08-05 
2017-08-06 
2017-08-07 
2017-08-08 
2017-08-09 
2017-08-10 

然後你就可以加入你給price_table上date_from和DATE_TO,你可以計算出你的總和。

編輯:只是爲了完成它... :-)

SELECT SUM(price_per_room) 
FROM master.dbo.spt_values 
    LEFT OUTER JOIN room_prices AS rp ON (date_from <= DATEADD(d, number, my_start_date) AND DATEADD(d, number, my_start_date) <= date_to) 
WHERE type='P' AND (number <= DATEDIFF(d, my_start_date, my_end_date)) 
+0

我認爲在這個答案的介紹中缺少一些東西 - 「在SQL Server中(如果有的話)......」 - 我認爲這是一個標籤爲[tag:sql-server]的問題。不清楚你要說什麼,所以無法修復自己。 –

+0

對不起,我沒有看到標籤。我編輯了我的答案。謝謝。 – user8527410

-1

使用UNION ALL所有四種可能的情況下,可以做的工作,以及

SELECT SUM(x.p) 
FROM 
(
    SELECT (DATEDIFF(DAY, @from, date_to)+1)* price p 
    FROM tab 
    WHERE date_to BETWEEN @from AND @to AND NOT date_from BETWEEN @from AND @to 
     UNION ALL 
    SELECT ISNULL(SUM((DATEDIFF(DAY, date_from, date_to)+1)* price), 0) p 
    FROM tab 
    WHERE date_to BETWEEN @from AND @to AND date_from BETWEEN @from AND @to 
     UNION ALL 
    SELECT (DATEDIFF(DAY, date_from, @to)+1)* price p 
    FROM tab 
    WHERE date_from BETWEEN @from AND @to AND NOT date_to BETWEEN @from AND @to 
     UNION ALL 
    -- in the case that the (@from, @to) interval is completely in one row interval 
    SELECT (DATEDIFF(DAY, @from, @to)+1)* price p 
    FROM tab 
    WHERE date_from <= @from AND date_to >= @to  
)x; 

sqlfiddle demo

+0

如果'@ from'和'@ to'完全包含在一行的週期內(所以'date_from' <'@ from'和'date_to'>'@ to')呢?這就是爲什麼我不想試圖通過分析單獨案例來定義重疊。 –

+0

@Damien_The_Unbeliever是真的,我已經更新瞭解決方案。我承認你的解決方案比較乾淨,這是我提高它的原因;) –