MSSQL Calculate Date Difference in same column - sql-server

My data is as follows:
ID DATE
1 2014-02-01 09:00:00.00
1 2014-03-01 11:00:00.00
1 2014-01-01 11:00:00.00
2 2010-12-01 05:00:00.00
2 2011-10-01 03:30:00.00
2 2012-09-01 02:40:00.00
I need to calculate the date difference(day or hours difference is fine) between each row. The first row can be 0. I have tried:
date - coalesce(lag(date) over(order by id, date) as day_difference
daydiff(date - coalesce(lag(date) over(order by id, date)) as day_difference
both variants are not working(gives incorrect syntax error).
Please help.

You were close:
datediff(day, date, coalesce(lag(date) over(order by id, date))) as day_difference
But also, you might want to partition by the ID:
datediff(day, date, coalesce(lag(date) over(partition by ID order by id, date))) as day_difference

Related

Get date field based on Month and Year

I've got two fields, Period and YR with period representing the month. I would like to be able to select these records as a date field with the assumption that the day is the last day of the month. For example:
YR Period Date
2017 1 2017-01-31
2017 2 2017-02-28
Etc
I'm at a loss on how to go about doing this. Thanks for any help you can provide.
SELECT YR, Period, EOMONTH(DATEFROMPARTS(YR, Period, 1)) AS [Date]
FROM <<table>>
This is how you could do it using "basic" functions:
; with data as (
select 2017 as yr, 1 as period
union all
select 2017 as yr, 2 as period
)
, temp as (
select
yr,
period,
dateadd(day, -1, dateadd(month, 1,
convert(datetime, cast(yr*10000 + period*100 + 1 as varchar))
)
) as test
from data
)
select yr, period, convert(varchar(10), test, 126) from temp
Here is another query:
WITH tb(YR,Period)AS(
SELECT 2017,1 UNION ALL
SELECT 2017,2 UNION ALL
SELECT 2017,3
)
SELECT DATEADD(DAY,-1,DATEADD(MONTH,tb.Period+1, DATEADD( YEAR, YR-1900,0))) FROM tb
-----------------------
2017-02-28 00:00:00.000
2017-03-31 00:00:00.000
2017-04-30 00:00:00.000

Get count of row and sum group by quarter of date, if another column doesnt exits a value in SQL Server

I have some sample data:
Date Status OfferNum Amount
------------------------------------------------------
2016/10/30 - 1 - 2000 - 1000,00
2016/08/25 - 0 - 2000 - 1100,00
2016/07/12 - 0 - 2001 - 1200,00
2016/08/30 - 0 - 2001 - 1300,00
2016/07/12 - 1 - 2002 - 1400,00
2016/08/30 - 1 - 2002 - 1500,00
2016/08/30 - 1 - 2003 - 1600,00
I don't want to count if one of offerNum status value has 1 and in the same quarter(if it has 1 but it isnt same quarter it has to be count). But I want to sum all of the amount(it isnt depends status column)
Here is the result that I want:
Quarter Count TotalAmount
----------------------------------------------------
2016/Q3 2 (offerNum 2002 and 2003) 8100,00
2016/Q4 1 (offerNum 2000) 1000,00
Here is the sqlfiddle : http://sqlfiddle.com/#!6/eac9d
You can use a subquery to compute the status of each offer, then compute the final result aggregated by quarter. Notice that the GROUP BY year is important, otherwise result will contain data coming from the same quarter of the previous years.
--
-- Answer updated according to SQL Fiddle.
-- Check: http://sqlfiddle.com/#!6/709ff/9
--
WITH offers AS
(
SELECT
CONCAT(DATEPART(yy, date), '/Q', DATEPART(qq, date)) AS Quarter,
offer,
MAX(status) AS status,
SUM(amount) AS TotalAmount
FROM temp
GROUP BY
DATEPART(yy, date),
DATEPART(qq, date),
offer
)
SELECT
Quarter,
SUM(status) AS Count,
SUM(TotalAmount) AS TotalAmount
FROM offers
GROUP BY Quarter
Are you locking for this:
SELECT
CONCAT(DATEPART(yy, [date]), '/Q', DATEPART(qq, [date])) AS Quarter,
COUNT(case [status] when 1 THEN 1 ELSE NULL END) AS [Count],
SUM([Amount]) AS TotalAmount
FROM [dbo].[temp]
group by DATEPART(yy, [date]), DATEPART(qq, [date])
You can query like this
;WITH cte
AS (SELECT
concat(YEAR(date), '/Q', DATEPART(q, date)) AS q,
amount,
SUM(status) OVER (PARTITION BY concat(YEAR(date), '/Q', DATEPART(q, date))) AS OfferStatusSum,
status
FROM temp)
SELECT
q, COUNT(DISTINCT status),
SUM(CASE WHEN OfferStatusSum >= 1 THEN amount
ELSE 0
END)
FROM cte
GROUP BY q

Select all days of the current week

Good Day! I am working on a chart where I need to display all the days of the current week to show the sales per Week. So far, I am able to display all the days of the current week, I'm just having a trouble in displaying the sales for each day of the week.Since there are no records in the database for the days of the week, it the TOTAL_SALES column should all return a Null value. Instead, it returns the total sales recorded in the database. Here is my Stored Procedure query so far.
WITH DAYSOFTHEWEEK AS
(
SELECT 0 DAY
UNION ALL
SELECT DAY + 1 FROM DAYSOFTHEWEEK WHERE DAY < 6
)
SELECT DATEADD(DAY, DAY, DATEADD(DAY, 2-DATEPART(WEEKDAY, CONVERT (date, GETDATE())), CONVERT (date, GETDATE()))) AS DAY_OF_THE_WEEK,
SUM([ORDER].NET_AMOUNT) AS TOTAL_SALES
FROM DAYSOFTHEWEEK, [ORDER]
GROUP BY DAYSOFTHEWEEK.DAY
I tried adding this condition statement,
WHERE DAYSOFTHEWEEK.DAY IN ([ORDER].ORDER_DATE)
But it returns this error
Operand type clash: date is incompatible with int
Can someone help me out on this?Is there a work around with the code that I already have? Thanks in advance!
What I think you're after is a SUM of each day's sales for the current week with NULL if there are no sales. The secret is to left join your date list onto your data:
-- Setup some fake sales data
WITH TestData(N, Order_Date, Net_Amount) AS (
SELECT 1 N, CAST(GETDATE() AS DATE) Order_Date, RAND() * 100 Net_Amount
UNION ALL
SELECT N+1 N, CAST(GETDATE()-N/5 AS DATE) Order_Date, RAND(CHECKSUM(NEWID())) * 100 Net_Amount FROM TestData
WHERE N < 20
)
SELECT TestData.Order_Date, TestData.Net_Amount INTO #Order FROM TestData
--Set the first day of the week (if required)
SET DATEFIRST 7 --Sunday
;WITH Days(N,DayOfTheWeek) AS (
SELECT 1 N, DATEADD(DAY, 1-DATEPART(WEEKDAY, GETDATE()), CONVERT(DATE,GETDATE())) DayOfTheWeek
UNION ALL
SELECT N+1 N,DATEADD(DAY, 1, DayOfTheWeek) DayOfTheWeek FROM Days
WHERE N < 7
)
SELECT d.DayOfTheWeek, SUM(Net_Amount) TotalAmount
FROM Days d
LEFT JOIN #Order ON d.DayOfTheWeek = Order_Date
GROUP BY d.DayOfTheWeek
DayOfTheWeek TotalAmount
------------ ----------------------
2016-08-07 219.036784917497
2016-08-08 273.319570812461
2016-08-09 271.148114731087
2016-08-10 194.780039228967
2016-08-11 NULL
2016-08-12 NULL
2016-08-13 NULL
Here is every day this week, starting at your datefirst date, which can be temporarily varied for the query with SET DATEFIRST if you need to have some other week start date
I think you have some sales table there that you haven't shown us, you need to join to that on date, then group by
WITH DAYSOFTHEWEEK AS
(
SELECT cast(dateadd(
day,
-datepart(weekday,getdate()) + 1 ,
GETDATE()
)
as date) [DAY], 0 as cnt
UNION ALL
SELECT dateadd(day,1,[DAY]), cnt + 1 FROM DAYSOFTHEWEEK WHERE cnt < 6
)
select DAYSOFTHEWEEK.[day], SUM([ORDER].NET_AMOUNT) AS TOTAL_SALES from daysoftheweek
JOIN
SalesTable on
CAST(SalesTable.SalesDate date) = DAYSOFTHEWEEK.[day]
GROUP BY DAYSOFTHEWEEK.[day]
A little over complicated for me:
To get name of the week use, for example
SELECT DATENAME(dw,getdate())
But you really need something like this:
SELECT ProductName,Sum(Sales) From NameOfTable GROUP BY
DATENAME(ww,salesDate)

trying to get the first visited date

I am trying to do daily analysis on a particular set of data. The table looks like this:
custNo visitTime FirstVisit
1234 2013-01-31 20:15
1234 2013-01-31 22:30
1234 2013-02-15 02:30
1234 2013-02-15 06:30
1234 2013-02-15 11:30
1234 2013-02-15 21:30
I am trying to do some Daily analysis using custNo. As you can see above the customer number repeats itself. One day is 2013-01-31 1:00am to 2013-02-01 00:59am. I am trying to come up with a query for FirstVistTime. So for31st Jan, it should be 2013-01-31 20:15 and for 15th Feb it should be 2013-02-15 02:30.
So far I came up with this query:
select custNo, visitTime, FirstVisit=(select MIN(c.visitTime) FROM customer c where
(c.custNo=ct.custNo and c.visitTime >= '01/01/2013 01:00' and c.visitTime < '03/01/2013
01:00')
from customer ct
where visitTime >= '01/01/2013 01:00'
and visitTime < '03/01/2013 01:00'
The problem with this is - if the custNo repeats it takes all the rows into account and calculates the minimum date, which in the above case would be 2013-01-31 20:15. I tried to use min(visitTime)over(partition by custNo,visitTime). Well it is a subquery that returns two values.
try this:
select custNo, min(visitTime) from customer
group by custNo, CAST(visitTime AS date)
order by custNo
or:
select t1.custNo, t1.visitTime, t2.minVal
from customer t1 left join
(
select custno, min(visitTime) as minVal from customer
group by custno, CAST(visitTime AS date)
) t2 on t1.custNo = t2.custNo and CAST(t2.minVal as date) = CAST(t1.visitTime as date)
order by t1.custNo
Actually, you should just be able to group by customer and date, and select the minimum visit time for each customer and date:
SELECT custNo, MIN(visitTime)
FROM customer c
GROUP BY custNo, CONVERT(DATE, visitTime, 112)
ORDER BY custNo, MIN(visitTime)
Is this what you're looking for?
SELECT custno, min(visit)
FROM visitors
GROUP BY custno, CONVERT(DATE, VISIT)
ORDER BY custno, min(visit)
Here is a SQLFiddle

Determine consecutive date count in SQL Server

I have some data that looks like this:
id date
--------------------------------
123 2013-04-08 00:00:00.000
123 2013-04-07 00:00:00.000
123 2013-04-06 00:00:00.000
123 2013-04-04 00:00:00.000
123 2013-04-03 00:00:00.000
I need to return a count of the most recent consecutive date streak for a given ID, which in this case would be 3 for id 123. I have no idea if this can be done in SQL. Any suggestions?
The way to do this is to subtract a sequence of numbers and take the difference. This is a constant for a sequence of dates. Here is an example to get the length of all sequences for an id:
select id, grp, count(*) as NumInSequence, min(date), max(date)
from (select t.*,
(date - row_number() over (partition by id order by date)) as grp
from data t
) t
group by id, grp
To get the longest one, I would use row_number() again:
select t.*
from (select id, grp, count(*) as NumInSequence,
min(date) as mindate, max(date) as maxdate,
row_number() over (partition by id order by count(*) desc) as seqnum
from (select t.*,
(date - row_number() over (partition by id order by date)) as grp
from data t
) t
group by id, grp
) t
where seqnum = 1

Resources