您好,我在编写查询时遇到问题。 我需要用有效的[DateFrom]日期写当前价格。如果折扣覆盖数据范围,则需要写折扣[DateFrom],如果折扣在下一次价格更改之前结束,则为价格,我需要返回第1天为DateFrom DateFrom
的上一个价格源数据
DateFrom DateTo Price Type
--------------- --------------- ----------- ------
2019-05-25 2019-12-31 1000 Price
2019-05-26 2019-08-31 800 Discount
2020-01-01 2020-12-31 1100 Price
2020-07-05 2020-09-30 900 Discount
所需结果
DateFrom Price Type
--------------- ----------- ------
2019-05-25 1000 Price
2019-05-26 800 Discount
2019-09-01 1000 Price -- back go original price
2020-01-01 1100 Price
2020-07-05 900 Discount
2019-10-01 1000 Price -- back go original price
还有我当前的查询
declare @Day date
declare @MinDate date
declare @MaxDate date
declare @Result table (
id int PRIMARY KEY IDENTITY(1,1),
DateFrom date,
Price decimal(18,2),
Type varchar(10) )
IF OBJECT_ID('tempdb..#temp', 'U') IS NOT NULL DROP TABLE #temp
select
ROW_NUMBER() OVER (ORDER BY DateFrom, PriceType Desc /*1st discount*/) as RowNumber,
cast(DateFrom as date) as DateFrom,
cast(DateTo as date) as DateTo,
--LEAD(DateFrom, 1) OVER (ORDER BY DateFrom) as NextDate1,
LAG(DateTo, 1) OVER (ORDER BY DateFrom) as PrevDate2,
--DATEDIFF(dd, DateTo, LEAD(DateFrom, 1) OVER (ORDER BY DateFrom)) as NextDate1Diff,
--LEAD(DateTo, 1) OVER (ORDER BY DateFrom) as NextDate2,
CASE WHEN DateTo>LEAD(DateFrom, 1) OVER (ORDER BY DateFrom) THEN 'yes' ELSE 'no' END as overlaped,
CASE WHEN PriceType=568 THEN 'Price'
WHEN PriceType=3146 THEN 'Discount' END as Type,
--LEAD(CASE WHEN PriceType=568 THEN 'Price'
--WHEN PriceType=3146 THEN 'Discount' END, 1) OVER (ORDER BY DateFrom) as NextType,
LAG(CASE WHEN PriceType=568 THEN 'Price'
WHEN PriceType=3146 THEN 'Discount' END, 1) OVER (ORDER BY DateFrom) as PrevType,
LAG(DecimalColumn3) OVER (ORDER BY DateFrom) as PrevPrice,
H_DecimalColumn1, --as [Dicount value],
DecimalColumn3 as Price
INTO #temp
from Table where PriceType in (568,3146)
order by DateFrom
select * from #temp
select @MinDate=MIN(DateFrom), @Day=MIN(DateFrom) from #temp
select @MaxDate=MAX(DateTo) from #temp
--Select @MinDate, @MaxDate,@Day
--select DATEDIFF(dd, DateTo, LEAD(DateFrom, 1) OVER (ORDER BY DateFrom)) as NextDate2Diff,
--* from #temp where Type='Discount'
--select * from #temp where Type='Price'
WHILE @Day<@MaxDate
BEGIN
if exists(select * from #temp where DateFrom=@Day or DateTo=@Day)
begin
if exists(select * from #temp where @Day=DateFrom)
BEGIN
select 'D1-T', @Day, overlaped,
DATEADD(dd, 1,PrevDate2) as PrevDate1More, CASE WHEN Type='Price' and overlaped='yes' and PrevType='Discount' THEN ISNULL(DATEADD(dd, 1,PrevDate2),DateFrom) ELSE DateFrom END as DayG,
CASE WHEN Type='Price' and overlaped='yes' and PrevType='Discount' THEN ISNULL(PrevPrice,Price) ELSE Price END as Price
,DateFrom, DateTo
from #temp where @Day=DateFrom /*or @Day=DateTo*/
ORDER BY DateFrom, Type Desc
INSERT INTO @Result(Od, Price, Type)
select CASE WHEN Type='Price' and overlaped='yes' and PrevType='Discount' THEN ISNULL(DATEADD(dd, 1,PrevDate2),DateFrom) ELSE DateFrom END as DayG,
Price, Type from #temp where @Day=DateFrom /*or @Day=DateTo*/ ORDER BY DateFrom, Type Desc
END
else /* @Day=DateTo */
BEGIN
--IF Discount
select 'D2-FR', @Day, overlaped, CASE WHEN Type='Discount' THEN DATEADD(dd, 1,DateTo) ELSE DateTo END as day, PrevPrice, *
from #temp where DateTo=@Day and Type='Discount'
INSERT INTO @Result(Od, Price, Type)
select CASE WHEN Type='Discount' THEN DATEADD(dd, 1,DateTo) ELSE DateTo END as day,
PrevPrice, PrevType
from #temp where DateTo=@Day and Type='Discount'
--IF Price
/*
select 'D2-FC', @Day, overlaped, CASE WHEN Type='Price' THEN DATEADD(dd, 1,DateTo) ELSE DateTo END as day, PrevPrice, *
from #temp where DateTo=@Day and Type='Price'
INSERT INTO @Result(Od, Price, Type)
select CASE WHEN Type='Discount' THEN DATEADD(dd, 1,DateTo) ELSE DateTo END as day,
Price, Type
from #temp where DateTo=@Day and Type='Price'
*/
END
end
SELECT @Day=DATEADD(dd, 1, @Day) -- increment
END
select distinct Od, Price, Type, ROW_NUMBER() OVER (PARTITION BY Od ORDER BY Od, Type DESC) as Rank from @Result
;WITH CTE AS
(
select distinct Od, Price, Type, ROW_NUMBER() OVER (PARTITION BY Od ORDER BY Od, Type DESC) as Rank from @Result
)
SELECT * FROM CTE WHERE Rank=1
答案 0 :(得分:2)
这很棘手。我认为最好的解决方案是取消数据透视,然后使用逻辑和窗口函数进行排列。
假设您始终有全价,那么这应该可行:
select v.dte as datefrom, dateadd(day, -1, lead(v.dte) over (order by v.dte)) as dateto, v.price, v.type
from t join
t tfull
on tfull.type = 'Price' and
tfull.datefrom <= dateadd(day, 1, t.dateto) and
tfull.dateto >= dateadd(day, 1, t.dateto) cross apply
(values (t.datefrom, t.price, t.type),
(dateadd(day, 1, t.dateto), tfull.price, tfull.type)
) v(dte, price, type)
order by dte
Here是db <>小提琴。
编辑:
当折扣和全价在同一日期结束时,以上版本有一些不必要的行。唉。这样可以解决该问题:
select t.*
from (select v.dte as datefrom, dateadd(day, -1, lead(v.dte) over (order by v.dte)) as dateto, v.price, v.type
from t join
t tfull
on tfull.type = 'Price' and
tfull.datefrom <= dateadd(day, 1, t.dateto) and
tfull.dateto >= dateadd(day, 1, t.dateto) cross apply
(values (t.datefrom, t.price, t.type),
(dateadd(day, 1, t.dateto), tfull.price, tfull.type)
) v(dte, price, type)
) t
where dateto >= datefrom
order by dateto;
还有db<>fiddle。
答案 1 :(得分:1)
提供的Discount
不成对出现,而仅在“价格”之后出现
-- test data
with tbl as (
select DateFrom, DateTo, Price, Type
from (
values
( cast('2019-05-25' as date),cast('2019-12-31' as date),1000,'Price')
,( cast('2019-05-26' as date),cast('2019-08-31' as date),800 ,'Discount')
,( cast('2020-01-01' as date),cast('2020-12-31' as date),1100,'Price')
,( cast('2020-07-05' as date),cast('2020-09-30' as date),900 ,'Discount')
) tbl (DateFrom, DateTo, Price, Type)
)
-- the query
select t2.DateFrom, t2.DateTo, t2.Price, t2.Type
from (
select DateFrom, DateTo, Price, Type
, lag(DateTo) over (order by DateFrom) prevTo
, lag(Price) over (order by DateFrom) prevPrice
from tbl
) t
cross apply(
select DateFrom, DateTo, Price, Type
union
select DATEADD(dd,1, DateTo) DateFrom, prevTo DateTo, prevPrice Price, 'back' type
where t.Type = 'Discount' and t.prevTo > t.DateTo
) t2;
EDIT (已更正DateTo
逻辑。