Counting orders per hour in a month defined by WHERE clause - sql

I'm hoping to count orders per hour for every day in the last month.
I have this WHERE clause from another report (1), which determines the correct month 'last month' from the point it is run.
I'd like to ideally have hours as my 'leftmost' column, rather than the date.
I thought I could get distinct days within the WHERE and then count datepart where hour = 1, 2 etc. However, this code below (2) leads to over 300 records.
(1)
WHERE YEAR(Bookings.PICKUP_DATE)
= YEAR(DATEADD(mm, -1, DATEADD(m, DATEDIFF(m, 0, getdate()), 0)))
AND MONTH(Bookings.PICKUP_DATE)
= MONTH(DATEADD(mm, -1, DATEADD(m, DATEDIFF(m, 0, getdate()), 0)))
(2)
select
distinct(datepart(dd,b.pickup_date)) as DAYOFTHEMONTH
,COUNT(CASE WHEN DATEPART(HH,B.PICKUP_DATE) = 1 THEN 1 ELSE 0 END)

Apologies for not being clear before. I've worked this out now.
The reason I had too many records was simply that my GROUP BY clause did not have the DAY function applied.
My dataset is now correct and I get all days in the date range with:
distinct(datepart(dd,timestamp)) as DAYOFTHEMONTH
The count of orders for an hour (In this case midnight) is:
count(case when datepart(hh,timestamp) = 0 then timestamp else null end) as '00:00'
My WHERE clause is giving all data for the month before the present one:
WHERE
YEAR(timestamp) = YEAR(DATEADD(mm,-1,DATEADD(m,DATEDIFF(m,0,getdate()),0)))
AND
MONTH(timestamp) = MONTH(DATEADD(mm,-1,DATEADD(m,DATEDIFF(m,0,getdate()),0)))
Lastly, I get the correct grouping with DAY applied to the GROUP BY
GROUP BY day(timestamp)
Sorry to have been unclear. Hope this will prove useful to somebody out there in the future.
Thanks for the edit/help too guys, I'll ensure any other questions I ask are correct:)

Related

SQL Server Group a promotion by last 24 hours, last week and last month and sort by week descending

I'm trying to look at how successful different promotions have been in the last 24 hours, week and month. To get the amount by promotion for the last 24 hours I've used this code but I don't understand how to get another two columns for the last week and the last month. And then finally I want to order it by the amount in the last week descending. I want to be able to run this query at any point during the month. Please help me.
SELECT Promotion
, Sum(Amount) AS Last_24
FROM dbo.CustomerPayment
WHERE Started >= DATEADD(day, - 1, GETDATE())
GROUP
BY Promotion
You can do it in a single query :
SELECT Promotion
, Sum(CASE WHEN Started >= DATEADD(day, -1, GETDATE()) THEN Amount ELSE 0 END) AS Last_24
, Sum(CASE WHEN Started >= DATEADD(day, -7, GETDATE()) THEN Amount ELSE 0 END) AS Last_Week
, Sum(Amount) AS Last_Month
FROM dbo.CustomerPayment
WHERE Started >= DATEADD(day, - 31, GETDATE())
GROUP
BY Promotion
ORDER BY Last_Week DESC
Note that this part :
WHERE Started >= DATEADD(day, - 31, GETDATE())
as te be clarified following your own interpretation of "Last Month" concept.
Use conditional aggregation -- that is, move the conditions to the select:
SELECT Promotion,
SUM(case when Started >= DATEADD(day, - 1, GETDATE()) then Amount end) AS Last_1_day,
SUM(case when Started >= DATEADD(day, - 7, GETDATE()) then Amount end) AS Last_7_day,
. . .
FROM dbo.CustomerPayment
GROUP BY Promotion;
One possible issue, though. GETDATE() -- despite its name -- returns a time component to the date. I suspect that you might actually want to treat this as a date, not a datetime:
SELECT Promotion,
SUM(case when Started >= DATEADD(day, - 1, CONVERT(DATE, GETDATE())) then Amount end) AS Last_1_day,
SUM(case when Started >= DATEADD(day, - 7, CONVERT(DATE, GETDATE())) then Amount end) AS Last_7_day,
. . .
FROM dbo.CustomerPayment
GROUP BY Promotion;
I was looking for month / week. Not 7 / 30 days.
If you wish those, just use variables to have that query readable.
declare #monthstart date,
#weekstart date
;
select #monthstart=datefromparts(year(current_timestamp),month(current_timestamp),1)
select cast(DATEADD(d,1-DATEPART(WEEKDAY,current_timestamp),CURRENT_TIMESTAMP) as date) as Sunday,
cast(DATEADD(d,2-case when DATEPART(WEEKDAY,current_timestamp)=1 then 8 else DATEPART(WEEKDAY,current_timestamp) end,CURRENT_TIMESTAMP) as date) as Monday
;

What is -1 and 0 doing in date add function?

dateadd(mm, DATEPART(MONTH, DATE) - 1, 0) + DATEPART(DAY, DATE) - 1
OUTPUT date is in the year for example 1990-12-02 00:00:00:000
Full query is below:
SELECT dateadd(yy, (
DATEPART(YEAR, GETDATE()) + (
CASE
WHEN DATEPART(MONTH, GP_DATE) > 10
THEN 0
ELSE 1
END
) - 1900
), 0) + dateadd(mm, DATEPART(MONTH, GP_DATE) - 1, 0) + DATEPART(DAY, GP_DATE) - 1 GP_DATE
from table
I am trying to convert this query into snowflake syntax and snowflake syntax dateadd function does not allow 1, 0.
In SQL Server, there are some rather ugly implicit conversions available between datetimes and integers.
0, when converted to a date, becomes 1900-01-01.
You're also allowed to do maths on dates. Adding or subtracting 1 adds or subtracts 1 day from the date. Putting these facts together, we have:
dateadd(yy, (
DATEPART(YEAR, GETDATE()) + (
CASE
WHEN DATEPART(MONTH, GP_DATE) > 10
THEN 0
ELSE 1
END
) - 1900
), 0)
Which is taking the current year, and subtracting 1900 from it (or 1899 if the month is less than 11, for whatever reason). We then take that number and add it back to the date 0 (which as stated above is 1900-01-01). The result is that we get the first of January of next year or this year, depending on the month of GP_DATE. Call this D1.
Moving on:
dateadd(mm, DATEPART(MONTH, GP_DATE) - 1, 0)
is taking the month of GP_DATE, subtracting 1 from it and adding that number of months to the date 0 (1900-01-01). The result is a the 1st of whichever month GP_DATE is in, but in 1900. Let's call this D2.
When we add D1 and D2 together, we approximately get a date of the 1st of whichever month GP_DATE is in, in either this year or next year. Note, however, that this goes wrong if the D1 year is a leap year, we get it wrong by a day for months after February.
Finally, we take DATEPART(DAY, GP_DATE) - 1, where we take the day of the month from GP_DATE, subtract 1, and add that on to our result so far. This should set the final date to be on the same day of the month as GP_DATE, except for the error mentioned above.
So, it appears that the code is trying to take GP_DATE and get the same date in either this year or next year, depending on how late in the year GP_DATE is. However, it also appears it was never tested with consideration for leap years.
A far more likely correct version of this query would be this instead:
SELECT
DATEADD(year,
DATEDIFF(year,GP_DATE,CURRENT_TIMESTAMP) +
CASE WHEN DATEPART(month,GP_DATE)>10 THEN 0 ELSE 1 END
,GP_DATE)

SQL getdate issue with month

i need help on my little problem.
SELECT FORMAT(ServiceDate, 'dd-MM-yyy") AS ServiceDate
FROM Services
WHERE Day(ServiceDate) BETWEEN '1' AND Day(getdate() -2)
AND Month(ServiceDate) =
CASE
WHEN Day(getdate()) <=2
THEN Month(getdate() -1
ELSE Month(getdate())
END
AND Year(ServiceDate) = Year(getdate())
Now the problem is the first and the second of the Month.
The query don't use the last month. It shows the actual month.
I hope its clear what i need.
if we have the 01-06-2016 and i need minus 2, so the query must give me back to the day 30-05-2016
big THX
the output for today with this query
output query
Assuming you are using sql-server, you need to use DATEADD(Day, -2, GETDATE()) for subtracting 2 days from current date.
I think I understand the logic now:
If the current day is the 1st of the month, get all the records from the start of previous month, until 2 days before it ends.
If the current day is the 2nd of the month, get all the records from the start of the previous month until one day before it ends.
If the current day is the 3rd of the month or higher, get all the records from the beginning of the current month until 2 days ago.
Since you are using the FORMAT() function that was introduced in 2012 version, you can also use the EOMONTH() function that was introduced in the same version.
This function returns the date of the end of the month of the date it receives as an argument, and also have a useful optional second argument that specifies the numbers of months to add to the date passed to the function.
Using this function will allow you to write your query without using any functions on the ServiceDate column, thus enabling the use of any indexes defined on this column.
DECLARE #Now datetime = GETDATE()
SELECT FORMAT(ServiceDate, 'dd-MM-yyy') AS ServiceDate
FROM Services
WHERE (
DAY(#Now) <= 2
AND ServiceDate >= DATEADD(DAY, 1, EOMONTH(#Now, -2))
AND ServiceDate < DATEADD(DAY, -(DAY(#Now)-1), EOMONTH(#Now, -1))
)
OR
(
DAY(GETDATE()) > 2
AND ServiceDate >= DATEADD(DAY, 1, EOMONTH(#Now, -1))
AND ServiceDate < DATEADD(DAY, -2, #Now)
)
Compute enddate as 2 days before getdate() and select data in interval from enddate's first of month and enddate.
SELECT FORMAT(ServiceDate, 'dd-MM-yyy") AS ServiceDate
FROM Services
CROSS APPLY (SELECT enddate = DATEADD(D,-2,getdate()) x
WHERE ServiceDate BETWEEN DATEADD(MONTH,DATEDIFF(MONTH,0,x.enddate),0) AND x.enddate

Find the sum of amount between dates

I have the following scenario:
There is a table that contains data loaded weekly and last day of the month for each customer and product.
I need to get the data sum for the data loaded on the last day of the month for each product (let's say) - that consolidates it for all the customers.
Input is 2 dates - start and end of the period and I need to get this done in a single SQL query.
Below is the query that I am using. Period is a datetime field.
SELECT
Period
,sum([Amount]) as 'Amount'
from tableA
where Period between convert(datetime,'201110'+'01',121) and dateadd(second,-1,dateadd(month,1,convert(datetime,'201201'+'01',121)))
and cond1 = .....
and cond2 = ....
group by
Period
The query above results in data as shown below.
I need to find out the amount on the last day of each month, i.e. one for 31-Oct-11, 30-Nov-11, 31-Dec-11 and so on.
The final result should look as below (as opposed to what I am getting currently - above):
Can you please help !!
If you just want the values for the last day of each month in the period I think adding a condition like this should work:
AND Period = DATEADD(d, -1, DATEADD(m, DATEDIFF(m, 0, period) + 1, 0))
The query would look something like this:
SELECT
Period,
SUM([Amount]) AS 'Amount'
FROM tableA
WHERE Period BETWEEN CONVERT(DATETIME,'201110'+'01',121) AND DATEADD(SECOND,-1,DATEADD(MONTH,1,CONVERT(DATETIME,'201201'+'01',121)))
AND Period = DATEADD(d, -1, DATEADD(m, DATEDIFF(m, 0, period) + 1, 0))
AND cond1 = .....
AND cond2 = ....
GROUP BY Period
If your period datetime has a time value you will have to remove that part to get the match with the last day date that the condition provides like this:
AND DATEADD(dd, DATEDIFF(dd, 0, Period), 0) =
DATEADD(d, -1, DATEADD(m, DATEDIFF(m, 0, period) + 1, 0))

SQL trend over time

I have a table with two columns, date and score. I want to find something like:
Sum as of 7 days ago
Sum as of 6 days ago
...
Sum as of today
An individual thing could be found with
select sum(score) from my_table
where date <= DateAdd("d", -1, getdate)
But I would like to not have to run a new query every time.
(I am using django, but pure SQL solutions are fine too.)
Use case statements to sum each value you care about.
SELECT
(CASE WHEN date <= DateAdd("d", -1, getdate) THEN score ELSE 0 END) as sum1,
(CASE WHEN date <= DateAdd("d", -2, getdate) THEN score ELSE 0 END) as sum2, etc.