SQL trend over time - sql

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.

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
;

SQL Server query to get data for last two months

SELECT
DAY(table_A.PaymentDate) as date1 ,
(CASE
WHEN MONTH(table_A.PaymentDate) = MONTH(CURRENT_TIMESTAMP)
THEN CAST(SUM(table_A.Total_Amount) As INT)
ELSE 0
END) AS This_month_CNT,
(CASE
WHEN MONTH(table_A.PaymentDate) = MONTH(CURRENT_TIMESTAMP) - 1
THEN CAST(SUM(table_A.Total_Amount) AS INT)
ELSE 0
END) AS last_month_CNT
FROM
Tbl_Pan_Paymentdetails table_A
FULL OUTER JOIN
Tbl_Pan_Paymentdetails table_B ON table_A.PaymentDate = table_B.PaymentDate
WHERE
YEAR(table_A.PaymentDate) = YEAR(CURRENT_TIMESTAMP)
AND table_A.PaymentDate >= DATEADD(MONTH, -2, GETDATE())
GROUP BY
DAY(table_A.PaymentDate),
MONTH(table_A.PaymentDate)
ORDER BY
DAY(table_A.PaymentDate) ;
Not sure I fully understand.
WHERE YEAR(table_A.PaymentDate) = YEAR(CURRENT_TIMESTAMP) AND
table_A.PaymentDate >= DATEADD(MONTH, -2, GETDATE())
Here you are (1) comparing the Year elements of your payment date with CURRENT_TIMESTAMP, and (2) making sure the payment date is greater than the last 2 months based on GETDATE()?
Not sure why you are using both CURRENT_TIMESTAMP and GETDATE(). Either way, I think the second part of that WHERE statement does what you want.
If the current date is January 31, 2015, your currently logic will not return any records from December 2014. The first part of your where statement is filtering them out. If you really want the last 2 months, remove the following from the WHERE statement
YEAR(table_A.PaymentDate) = YEAR(CURRENT_TIMESTAMP) AND

Counting orders per hour in a month defined by WHERE clause

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:)

How do I search and group by a date column into sets of duration ranges?

I have a table like this;
jobID - jobTitle - jobCreatedDate
I want to make it possible for visitors to search in Jobs table and list it by grouping like this and I want to do it with just one SQL query:
Date Added
- AnyTime (20)
- 1 day ago (5)
- 2-7 days ago (2)
- 8-14 days ago (0)
- 15-30 days ago (7)
I tried Group By "jobCreatedDate" with no success and I couldn't understand the logic of the necessary query.
Here is an example what I'm trying to do:
Thanks for help.
You need to find the date difference between today and the field JobCreated. Then based on the difference in the value days, you need to classify the output accordingly into various categories to meet your requirements.
I hope that is what you are looking for.
SELECT SUM(1) AS [AnyTime]
, SUM(CASE WHEN DayCount = 1 THEN 1 ELSE 0 END) AS [1 day ago]
, SUM(CASE WHEN DayCount BETWEEN 2 AND 7 THEN 1 ELSE 0 END) AS [2-7 days ago]
, SUM(CASE WHEN DayCount BETWEEN 8 AND 14 THEN 1 ELSE 0 END) AS [8-14 days ago]
, SUM(CASE WHEN DayCount BETWEEN 15 AND 30 THEN 1 ELSE 0 END) AS [15-30 days ago]
FROM
(
SELECT JobID
, DATEDIFF(d, JobCreatedDate, GETDATE()) AS DayCount
FROM dbo.Jobs
) Jobs
Screenshot shows sample data and the query output.
Use the DATEADD tsql method.
Select ...
From [Table]
Where JobCreatedDate between DATEADD(dd, #NumDays, GetDate()) and GetDate()
In this query #NumDays is a parameter representing the number of days to subtract from the current date. Make sure you pass a negative number to the query. If you are trying to create non inclusive ranges, you'll need to use two DATEADD calls passing two parameters to the query.
EDIT
I misunderstood what you were trying to do. This may not be the most elegant solution, but you could accomplish your goal using a union query.
Select sum(OneDay) as OneDay, sum(SevenDays) as SevenDays
From
(select 1 as OneDay, 0 as SevenDays
From [table]
Where JobCreatedDate between DATEADD(dd, -1, GetDate()) and GetDate())
UNION
(select 0 as OneDay, 1 as SevenDays
From[table]
Where JobCreatedDate between DATEADD(dd, -7, GetDate()) and DATEADD(dd, -2, GetDate()))

Time difference in SQL between record and "a specific time on the day"

I have a tabel in a relation database which contains a lot of dates.
I my application logic I have divided one day into 4 parts of 6 hours each, starting at: 00:00, 06:00, 12:00 and 18:00.
Now I would like to find the time difference of the earliest record in the database for each quater of a day, and the beginning og the peiod. How can I do that?
In psuedo-sql i guess it looks like
select min(created_at - ROUND_DOWN_TO_6_HOURS(created_at)) from mytabel group by day_quater;
The problem is how to calculate "ROUND_DOWN_TO_6_HOURS". So if "created_at" is 19:15 it will be rounded down to 18:00 and "created_at - ROUND_DOWN_TO_6_HOURS(created_at)" will return 1:15 hourd
I'm working with psql
If you're just trying to locate the records that match these ranges, you could just use that in the WHERE clause like
select * from myTable
where datepart(hh, created_at) between 0 and 6
If your trying to create a computed field that will have the 00 or 06 ... then you could use the "DatePart()" function in sql to pull the hour... DATEPART ( hh, date )... This would return a numeric value of 0, 1, 2, 3, ... 23 and you can compute a field based on this value being between 2 of your hours listed...
Here's a sample...
select
case
when datepart(hh, add_dt) between 0 and 6 then 1
when datepart(hh, add_dt) between 7 and 12 then 2
when datepart(hh, add_dt) between 13 and 18 then 3
when datepart(hh, add_dt) between 19 and 24 then 4
end
from myTable
where add_dt is not null
You could use CASE in conjunction with your date column and datetime functions to establish the quarter-of-day (1,2,3,4) and extract the day part from the datetime value, group by day, quarter, and then use the MIN(yourdatecolumn) to grab the earliest time within each quarter grouping.
Not sure what you mean by "beginning of the period". but you can measure the difference between any arbitrary datetime and your set of earliest times per day-quarter which was instantiated in the manner above.
http://www.postgresql.org/docs/8.2/static/functions-datetime.html
select
record::time - (case
when record::time >= '18:00' then '18:00'
when record::time >= '12:00' then '12:00'
when record::time >= '6:00' then '6:00'
else '0:00' end
)::time as difference
from my_table
My PostgreSQL is a little rusty, but something like this:
select
date_trunc('day',CreatedOn) [Day],
min(case when date_part('hour',TIMESTAMP CreatedOn) < 6 then '00:00'
when date_part('hour',TIMESTAMP CreatedOn) < 12 then '06:00'
when date_part('hour',TIMESTAMP CreatedOn) < 18 then '12:00'
else '18:00'
end) [Quarter]
from MyTable
group by date_trunc('day',CreatedOn)
order by date_trunc('day',CreatedOn)