简体   繁体   中英

SQL Server: Select rows with dates that correspond to end of year and calculate price

I have a table of data:

  ProductNum |   ProductVariation |   Past_Price  | Current_Price  |     Order_Date       
 ------------  ------------------    ------------  ---------------  --------------------- 
       1                 33              96.05          100.10       2014-01-01 00:00:00  
       1                 33              97.65          100.10       2014-12-03 12:34:52  
       1                 33              98.98          100.10       2015-01-02 05:50:32  
       1                 33              99.98          100.10       2016-03-02 06:50:43  
       1                 33              100.01         100.10       2016-12-12 06:05:43  
       1                 33              100.05         100.10       2017-01-02 05:34:43 

I was wondering if its possible to query for the rows such that we get the row that has the closest date to Dec 31,{Year} ?

So the output would be :

ProductNum  | ProductVariation  | Past_Price |  Current_Price   |  Order_Date       
------------ ------------------ ------------   ---------------    --------------------- 
       1                 33        98.98          100.10           2015-01-02 05:50:32  
       1                 33        99.98          100.10           2016-03-02 06:50:43  
       1                 33       100.01          100.10           2017-01-02 05:34:43  

Each order being the closest to Dec 31,{Year} for Years: 2014,2015,2016

You can sort by the date difference and get the top 1 row for each year.
For SqlServer :

DECLARE @year2014 datetime2 = '2014-12-31 12:00:00';
DECLARE @year2015 datetime2 = '2015-12-31 12:00:00';
DECLARE @year2016 datetime2 = '2016-12-31 12:00:00';

select * from (
  select top(1) * from products
  order by abs(datediff(second, @year2014, Order_Date))
) as p    
union all
select * from (
  select top(1) * from products
  order by abs(datediff(second, @year2015, Order_Date))
)as p    
union all
select * from (
  select top(1) * from products
  order by abs(datediff(second, @year2016, Order_Date))
) as p

Change the time of the 31st of December as you like.
For MySql :

set @year2014 = '2014-12-31 12:00:00';
set @year2015 = '2015-12-31 12:00:00';
set @year2016= '2016-12-31 12:00:00';

select * from (
  select * from products
  order by abs(TIMESTAMPDIFF(second, @year2014, Order_Date)) limit 1
) as p    
union all
select * from (
  select * from products
  order by abs(TIMESTAMPDIFF(second, @year2015, Order_Date)) limit 1
)as p    
union all
select * from (
  select * from products
  order by abs(TIMESTAMPDIFF(second, @year2016, Order_Date)) limit 1
) as p

Get row_number() s for each year ordered by the absolute datediff() between the order date and 31-12 of the year. Then select all where one of the row numbers equals 1 .

SELECT *
       FROM (SELECT *,
                    row_number() OVER (ORDER BY abs(datediff(second, '2014-12-31', t.order_date))) rn2014,
                    row_number() OVER (ORDER BY abs(datediff(second, '2015-12-31', t.order_date))) rn2015,
                    row_number() OVER (ORDER BY abs(datediff(second, '2016-12-31', t.order_date))) rn2016
                    FROM elbat t) x
       WHERE 1 IN (x.rn2014,
                   x.rn2015,
                   x.rn2016);

db<>fiddle

You can use this. This will avoid hard coding years and copying pasting unions.

declare @currDate datetime;
select @currDate = '12/31/2019';

while @currDate > '12/31/2013'

begin
select *
   from Product
   where abs(datediff(second, OrderDate, @currDate))
   = (select min(
       abs(datediff(second, OrderDate, @currDate))
   )
   from Product )

 select @currDate = dateadd(year,-1,@currDate);
end

I used the following fiddle:

create table Product (ProdNum int, ProdVar int, PastPrice decimal, CurrentPrice decimal, OrderDate datetime);
insert into Product values (1, 33, 96.05, 100.10, '2014-01-01 00:00:00');
insert into Product values (1, 33, 97.65, 100.10, '2014-12-03 12:34:52');
insert into Product values (1, 33, 98.98, 100.10, '2015-01-02 05:50:32');
insert into Product values (1, 33, 99.98, 100.10, '2016-03-02 06:50:43');
insert into Product values (1, 33, 100.01, 100.10, '2016-12-12 06:05:43');
insert into Product values (1, 33, 100.05, 100.10, '2017-01-02 05:34:43');

You seem to actually want the first date after the end of the year:

select top (1) with ties t.*
from t
order by row_number() over (partition by year(order_date) order by order_date asc);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM