TSQL- Finding the difference in days of multiple records in SQL Server - sql

Is it possible to find the difference of days of different records in SQL Server 2008 R2?
SELECT OrderDate FROM OrdersTbl WHERE SKU='AA0000' ORDER BY ORDERDATE DESC
OrderDate
-----------------------
2009-12-03 00:00:00.000
2009-04-03 00:00:00.000
2008-02-22 00:00:00.000
2008-02-21 00:00:00.000
2007-02-18 00:00:00.000
2007-01-27 00:00:00.000
2006-10-13 00:00:00.000
I would like a way to get how many days in between there are for each order date so that I could find the average frequency. Thanks in advance.

You can do it with a common table expression and ROW_NUMBER:
WITH OrderDates AS (
SELECT
ROW_NUMBER() OVER (ORDER BY OrderDate DESC) AS RowNumber,
OrderDate
FROM OrdersTable
WHERE SKU = 'AA0000'
)
SELECT
AVG(DATEDIFF(DD, O2.OrderDate, O1.OrderDate)) AS AverageFrequency
FROM OrderDates O1
LEFT JOIN OrderDates O2
ON O2.RowNumber = O1.RowNumber + 1

Sucks there's no LEAD/LAG support in SQL Server:
SELECT z.orderdate,
z.prev_date,
DATEDIFF(dd, z.prev_date, z.orderdate)
FROM (SELECT OrderDate,
(SELECT MAX(y.orderdate)
FROM ORDERSTBL y
WHERE y.orderdate < x.orderdate
AND y.sku = x.sku) AS prev_date
FROM OrdersTbl x
WHERE x.sku ='AA0000') z
ORDER BY z.orderdate DESC

;With cteDifference as (
Select SKU, OrderDate, Row_Number() OVER (Partition by SKU Order by OrderDate) as RowNumber
from OrdersTbl
)
select cur.SKU,
cur.OrderDate as CurrentDate,
prev.OrderDate as PreviousDate,
DATEDIFF(DD,prev.OrderDate, cur.OrderDate) as DaysDifference
from cteDifference cur
left join cteDifference prev
on cur.SKU = prev.SKU
and cur.RowNumber = prev.RowNumber + 1
where cur.SKU = 'AA0000'
order by cur.OrderDate desc

Related

Average price change over a period of time SQL

Trying to get the average price change for several items. This is my first time using SQL server, coming from some light experience in Oracle SQL and MySQL. The table is set up like this:
ProductID
StartDate
EndDate
StandardCost
707
5/31/11
5/29/12
12.2
707
5/30/12
5/29/13
13
707
5/30/13
null
13.5
708
5/31/11
5/29/12
10
708
5/30/12
5/29/13
11
708
5/30/13
null
12
I would like it to return this:
ProductID
Difference
707
1.3
708
2
with a as
(
select
productID, standardcost, startDate, ISNULL(endDate, GETDATE())
from
production.ProductCostHistory
where (productID, endDate) in (select
productID, max(endDate)
from
Production.ProductCostHistory
group by
productID
)
),
b as
(
select
productID, standardcost, startDate, startDate
from
production.ProductCostHistory
where (productID, startDate) in (select
productID, min(StartDate)
from
Production.ProductCostHistory
group by
productID
)
)
select
a.productID, (a.standardcost - b.standardcost) difference
from
a join b
on a.ProductID = b.ProductID and
a.startDate = b.startDate and
a.EndDate = b.EndDate
The idea is to first get the price with the most recent end date, then subtract the price from the oldest start date, to get the change in cost over that period of time. I understand that the where ... in does not work like in Oracle SQL, but I have not found a way to use exists the way that I need it to work. The averaging will be done in PowerBI, so I'm not worried about doing that in the Query. I would appreciate any help. Thanks.
You can try calculating the Standardcosts corresponding to the first startdate, and latest enddate (for each product) using an analytic function FIRST_VALUE.
select
productid,
max(fv) as value_at_first_startdate,
max(lv) as value_at_latest_enddate,
diff = max(lv) - max(fv)
from (
select
productid,
first_value(standardcost)
over (partition by productid
order by startdate) as fv,
first_value(standardcost)
over (partition by productid
order by case when enddate is null then 0 else 1 end
, enddate desc) as lv
from cte
) t
group by productid
Assuming your SQL is supposed to return correct result:
with minmax (productId, minStart, maxEnd) as
( select
productID, min(startDate),max(endDate)
from
Production.ProductCostHistory
group by productID
),
a as
(
select
p.productID, standardcost, startDate, ISNULL(endDate, GETDATE())
from production.ProductCostHistory p
inner join minmax m on m.productId = p.productId AND
m.maxEnd = p.endDate
),
b as
(
select
p.productID, standardcost, startdate, startdate
from production.ProductCostHistory p
inner join minmax m on m.productId = p.productId AND
m.minStart = p.startDate
)
select
a.productID, (a.standardcost - b.standardcost) difference
from
a join b
on a.ProductID = b.ProductID and
a.startDate = b.startDate and
a.EndDate = b.EndDate

How to get current and last order from Northwind db using Correlated queries

Using the northwind db on mssql, i am trying to retrieve the customer's last two order dates and calculate the time between the two orders.
So something like
select c.CompanyName, o.OrderDate, o2.OrderDate,
DateDiff(d, o.OrderDate, o2.OrderDate) as TimeElapsed
unfortunately not sure how to construct it from there.
i have something like this but it's still wrong.
select c.CompanyName, o.OrderDate, o2.OrderDate,
DateDiff(d, o.OrderDate, o2.OrderDate) as TimeElapsed
from Orders o
INNER JOIN Customers ON c.CustomerID = o.CustomerID
INNER JOIN (
select OrderID, OrderDate
FROM Orders
order by OrderDate
OFFSET 1 ROWS
FETCH NEXT 1 ROW ONLY
) as o2 ON o.OrderID = o2.OrderID;
can anyone assist.
Thank you
Northwind has been obsolete for years; even AdventureWorks has been replaced. The following uses the latter but you should be able to easily translate it to your schema. Two different approaches. The last 2 select statements are used to verify the results. Notice that customer 30099 has only one order.
set nocount on;
with cte as (select SalesOrderID, OrderDate, CustomerID, row_number () over (partition by CustomerID order by OrderDate desc) as rn
from Sales.SalesOrderHeader)
select top 10 * from cte
where rn <= 2
order by CustomerID, rn;
with cte as (select SalesOrderID, OrderDate, CustomerID, row_number () over (partition by CustomerID order by OrderDate desc) as rn
from Sales.SalesOrderHeader)
select cte.CustomerID, min(cte.OrderDate) as mindate, max(cte.OrderDate),
case when min(cte.OrderDate) = max(cte.OrderDate) then cast(null as int)
else datediff(day, min(cte.OrderDate), max(cte.OrderDate)) end as dif
from cte
where rn <= 2
group by cte.CustomerID
order by CustomerID;
with cte as (select SalesOrderID, OrderDate, CustomerID, row_number () over (partition by CustomerID order by OrderDate desc) as rn
from Sales.SalesOrderHeader)
select cte.CustomerID, minr.OrderDate as mindate, cte.OrderDate as maxdate,
datediff(day, minr.OrderDate, cte.OrderDate) as dif
from cte left join cte as minr on cte.CustomerID = minr.CustomerID and minr.rn = 2
where cte.rn = 1
order by cte.CustomerID;
select top 2 CustomerID, OrderDate from Sales.SalesOrderHeader where CustomerID = 30118 order by OrderDate desc;
select top 2 CustomerID, OrderDate from Sales.SalesOrderHeader where CustomerID = 30099 order by OrderDate desc;

SQL Server 2008 calculating data difference when we have only one date column

I have a date column Order_date and I am looking for ways to calculate the date difference between customer last order date and his recent previous ( previous form last) order_date ....
Example
Customer : 1, 2 , 1 , 1
Order_date: 01/02/2007, 02/01/2015, 06/02/2014, 04/02/2015
As you can see customer # 1 has three orders.
I want to know the date difference between his recent order date (04/02/2015) and his recent previous (06/02/2014).
For SQL Server 2012 & 2014 you could use LAG with a DATEDIFF to see the number of days between them.
For older versions, a CTE would probably be your best bet:
;WITH CTE AS
(
SELECT CustomerID,
Order_Date,
rn = ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY Order_Date DESC)
)
SELECT c1.CustomerID,
DATEDIFF(d, c1.Order_Date, c2.Order_Date)
FROM CTE c1
INNER JOIN CTE c2 ON c2.rn = c1.rn + 1
In SQL Server 2012+, you can use lag() to get the difference between any two dates:
select t.*,
datediff(day, lag(order_date) over (partition by customer order by order_date),
order_date) as days_dff
from table t;
If you have an older version, you can do something similar with correlated subqueries or outer apply.
EDIT:
If you just want the difference between the two most recent dates, use conditional aggregation instead:
select customer,
datediff(day, max(case when seqnum = 2 then order_date end),
max(case when seqnum = 1 then order_date end)
) as MostRecentDiff
from (select t.*,
row_number() over (partition by customer order by order_date desc) as seqnum
from table t
) t
group by customer;
If you're using SQL Server 2008 or later, you can try CROSS APPLY.
SELECT [customers].[customer_id], DATEDIFF(DAY, MIN([recent_orders].[order_date]), MAX([recent_orders].[order_date])) AS [elapsed]
FROM [customers]
CROSS APPLY (
SELECT TOP 2 [order_date]
FROM [orders]
WHERE ([orders].[customer_id] = [customers].[customer_id])
) [recent_orders]
GROUP BY [customers].[customer_id]
SELECT DATEDIFF(DAY, Y.PrevLastOrderDate, Y.LastOrderDate) AS PreviousDays
FROM
(
SELECT X.LastOrderDate
, (SELECT MAX(OrderDate) FROM dbo.Orders SO WHERE SO.CustomerID=1 AND SO.OrderDate < X.LastOrderDate) AS PrevLastOrderDate
FROM
(
select MAX(OrderDate) AS LastOrderDate
FROM dbo.Orders O
WHERE O.CustomerID=1
)X
)Y
drop table #Invoices
create table #Invoices ( OrderId int , OrderDate datetime )
insert into #Invoices (OrderId , OrderDate )
select 101, '01/01/2001' UNION ALL Select 202, '02/02/2002' UNION ALL Select 303, '03/03/2003'
UNION ALL Select 808, '08/08/2008' UNION ALL Select 909, '09/09/2009'
;
WITH
MyCTE /* http://technet.microsoft.com/en-us/library/ms175972.aspx */
( OrderId,OrderDate,ROWID) AS
(
SELECT
OrderId,OrderDate
, ROW_NUMBER() OVER ( ORDER BY OrderDate ) as ROWID
FROM
#Invoices inv
)
SELECT
OrderId,OrderDate
,(Select Max(OrderDate) from MyCTE innerAlias where innerAlias.ROWID = (outerAlias.ROWID-1) ) as PreviousOrderDate
,
[MyDiff] =
CASE
WHEN (Select Max(OrderDate) from MyCTE innerAlias where innerAlias.ROWID = (outerAlias.ROWID-1) ) iS NULL then 0
ELSE DATEDIFF (mm, OrderDate , (Select Max(OrderDate) from MyCTE innerAlias where innerAlias.ROWID = (outerAlias.ROWID-1) ) )
END
, ROWIDMINUSONE = (ROWID-1)
, ROWID as ROWID_SHOWN_FOR_KICKS , OrderDate as OrderDateASecondTimeForConvenience
FROM
MyCTE outerAlias
ORDER BY outerAlias.OrderDate Desc , OrderId

How to pull the whole row which has the latest date in SQL?

I’m trying to select the pair of product – distribution center attached with the most recent order (based on order date). For one order I can have multiple products, but the whole order will be shipped from one specific distribution center.
How do I select the specific product-distribution center attached with the latest order?
My structure is basically like this:
data.orderdetail table has ordernum, orderdate, distributioncenter
I tried to pull like this, but it doesn’t give me the desired result. I’m using sql server 2008:
SELECT DISTINCT y.OrderNum, y.Product, y.DistributionCenter
, CAST(y.OrderDate AS DATE) AS Orderdate
FROM (SELECT OrderNum, MAX(CAST(Orderdate AS date)) AS orderdate
FROM data.OrderDetail
GROUP BY OrderNum) AS x
INNER JOIN data.OrderDetail AS y
ON y.OrderNum = x.OrderNum
It looks as if you need one more clause in your join Condition
You've got
ON y.OrderNum = x.OrderNum
Which will return all the orders that match the Order number in the subquery
But you'll need
ON y.OrderNum = x.OrderNum
AND y.OrderDate = x.orderdate
Which will return all the orders that match the Order number in the subquery and the maximum date for that order number
SELECT DISTINCT
y.OrderNum,
y.Product,
y.DistributionCenter,
CAST(y.OrderDate AS DATE) AS Orderdate
FROM (
SELECT
OrderNum,
MAX(CAST(Orderdate AS date)) AS orderdate
FROM data.OrderDetail
GROUP BY OrderNum
) AS x
INNER JOIN
data.OrderDetail AS y
ON y.OrderNum = x.OrderNum
AND y.OrderDate = x.orderdate
I believe what you are looking for is row_number. This will partition your result set by OrderNum then rank the sets by the OrderDate. You can then filter off the extra rows in another where clause.
select result.*,
CAST(result.OrderDate as date) as Orderdate,
from (
select y.*,
row_number() over (
partition by y.OrderNum order by CAST(y.OrderDate as date) desc
) rank_
from (
select OrderNum,
MAX(CAST(Orderdate as date)) as orderdate
from data.OrderDetail
group by OrderNum
) as x
inner join data.OrderDetail as y on y.OrderNum = x.OrderNum
) result
where result.rank_ = 1;
select * from
(
SELECT OrderNum, Product, DistributionCenter, OrderDate
, ROW_NUMBER() over (partition by OrderNum order by OrderDate desc) as rownum
FROM OrderDetail
) as xxx
where xxx.rownum = 1
ROW_NUMBER (Transact-SQL)
Try this.
; WITH CTE1
AS (
SELECT
od.OrderNum
, od.Product
, od.DistributionCenter
, CAST(od.OrderDate AS DATE) AS OrderDate
, RowNumber = ROW_NUMBER() OVER (PARTITION BY od.Product, od.DistributionCenter ORDER BY CAST(od.OrderDate AS DATE) DESC)
FROM data.OrderDetail od
)
SELECT
OrderNum
, Product
, DistributionCenter
, OrderDate
FROM CTE1
WHERE RowNumber = 1

Basic SQL query help needed

I have a table with 3 colums. Here is an example with just a few entries to demo. The table represents the dates that an item's price changes. I need a query that will tell me the prices for all the items on a specific date. The specific date may be between price changes. The price changes at midnight, so the date of the change, that is the price from then until and on the day before the previous change:
itemCode datePriceEffective price
AB 2012-01-01 9.99
AB 2012-03-02 10.50
XY 2011-09-20 34.99
I wish to get all the items prices for a given date. There is not an entry for every date, just the dates that the price changes.
so 2012-03-05 would return
AB 10.50
XY 34.99
and 2012-02-27 would return:
AB 9.99
XY 34.99
The SQL query needed to get this escapes me. Answers appreciated.
Edited as answers are going in wrong direction see italics for edit.
This retrieves first record by descending order of datePriceEffective per itemCode.
select top 1 with ties *
from ATable
where datePriceEffective <= #givenDate
order by row_number() over (partition by itemCode
order by datePriceEffective desc)
SELECT itemCode,price FRom TableNameHere WHERE datePriceEffective <= '2012-03-05'
Edit after more info - a 'simple' answer to hopefully make it easy to follow.
You're getting thelatest date for the item that is valid in your required date range and then joining the table to itself to get the price at that date
SELECT t1.itemCode,t1.price FROM
(
SELECT itemCode,MAX(datePriceEffective) AS datePriceEffective
FROM TableNameHere
WHERE datePriceEffective <= '2012-03-05'
) a
INNER JOIN TableNameHere t1 ON t1.itemCode = a.itemCode AND t1.datePriceEffective = a.datePriceEffective
You will need to join back to the table as follows:
declare #effdate datetime
set #effdate = CONVERT(datetime,'2012-02-27')
;WITH CTE_DATA as (
select itemCode='AB', datePriceEffective = CONVERT(Datetime,'2012-01-01'), price = 9.99
union all select itemCode='AB', datePriceEffective = CONVERT(Datetime,'2012-03-02'), price = 10.50
union all select itemCode='XY', datePriceEffective = CONVERT(Datetime,'2011-09-20'), price = 34.99
)
select
d.itemcode,
price
from
CTE_DATA d
join (
select
itemcode,
effdate = MAX(datepriceeffective)
from CTE_DATA sub where sub.datepriceeffective <= #effdate
group by itemcode
) x
on x.itemCode = d.itemCode
and x.effdate = d.datePriceEffective
Note that the CTE is just for this example, you should swap it for your real table.
UPDATE: An alternative approach is to use ROW_NUMBER and PARTITION as follows:
SELECT
itemcode,
price
FROM
(
SELECT
itemcode,
price,
rowno = ROW_NUMBER() over (partition by itemcode order by datePriceEffective desc)
from
CTE_DATA
where datePriceEffective <= #effdate
) x
where
rowno = 1
(Substitute this select for the one in the previous query to try it out on the data)
declare #date datetime = '2012-03-05'
select distinct itemcode,
(
select top(1) itemprice
from mytable mt2
where
mt1.itemcode = mt2.itemcode and
mt2.datepriceeffective <= #date
order by datepriceeffective desc
) as itemprice
from
mytable mt1
where
datepriceeffective <= #date
SELECT b.itemCode,
(SELECT Price FROM dbo.tblProducts a WHERE datePriceEffective =
(SELECT MAX(a.datePriceEffective) FROM dbo.tblProducts a WHERE a.itemCode = b.itemCode)) AS Price
FROM dbo.tblProducts b
WHERE b.datePriceEffective <= '2012-03-05'
GROUP BY b.itemCode
I have tested it! It will give you the most updated price for each Item
Assuming that you have another column called 'GivenDate', below is the query.
SELECT itemCode, price
FROM tblName
WHERE GivenDate= '2012-03-05'
This works on sql2000
SELECT s.itemCode
, ( SELECT TOP 1 price
FROM #MyTable
WHERE itemCode = s.itemCode
AND datePriceEffective < #SearchDate ) AS price
FROM (
SELECT DISTINCT itemCode
FROM #MyTable
) s