Sliding Window Average For Multiple Time Periods - SQL Server - sql

I have a SQL query that returns the average time to signup for our users who signed up in the last 30 days:
select avg(datediff(dd, acquisitiontime,createdate)) from users where
createdate > getdate() - 30 and
acquisitionmedium = 'cpc' and
acquisitionsource = 'google' and
acquisitiontime is not null
I want to watch how this has changed over time.
How do I change this query so that I can spit out a table with (Month, Avg Time to Signup for that Month)?

select
DATEADD(month, -n.number, getdate()) OneMonthFromThisDate,
avg(datediff(dd, acquisitiontime, createdate)) AverageInThisMonth
from users
join master..spt_values n on n.type='P' and n.number between 1 and 24
where createdate > DATEADD(month, -n.number, getdate())
and createdate <= DATEADD(month, 1-n.number, getdate())
and acquisitionmedium = 'cpc'
and acquisitionsource = 'google'
and acquisitiontime is not null
group by n.number, DATEADD(month, -n.number, getdate())
order by n.number
This puts the most recent first.

Related

How to go back two days from a date in sql?

I wrote an SQL query that allows me to get the sales of certain stores.
My query runs every mornings and I would like to get the sales from 2 days ago at runtime.
For example if my query runs tomorrow morning, on 08/12, I would like to have the sales whose value in the column "GP_HEURECREATION" starts with "20200612", to have all the sales of the whole day.
The GP_HEURECREATION column has a format like this: "20200612 00:00:00" and is of the DATE type.
I tried with NOW() and DATEADD() but I have 2018 values that stand out for example.
How can I get the values only two days before the query is executed?
SELECT
T_ETABLISSEMENT, ET1.ET_LIBELLE AS C1, GL_ETABLISSEMENT,
GP_HEURECREATION, GP_REFINTERNE, GL_CODEARTICLE,
LIBDIM2, LIBDIM1, GL_QTEFACT, GL_PUTTC,
(GL_TOTALHT * GP_COTATIONDOS) AS TOTALHTDEV, GL_DPR, GL_DEVISE,
GL_NATUREPIECEG, GA_LIBELLE
FROM
GCLIGNEARTDIM
LEFT OUTER JOIN
PGI_LOOKUP(TTETABLISSEMENT) ET1 ON GL_ETABLISSEMENT = ET1.ET_ETABLISSEMENT
WHERE
(GP_HEURECREATION <= DATEADD(day, -2, GETDATE())
AND (GL_NATUREPIECEG = "FFO")
AND GL_ETABLISSEMENT = "20897", "10519", "20267", "26451", "20269", "26078", "28047", "20900", "28085", "24984", "27113", "20268", "19994", "28450", "26876", "24063", "18066", "3220"
ORDER BY
GP_REFINTERNE
The syntax of your existing query suggests SQL Server. If you want records that belong to day -2, you can do:
where gp_heurecreation >= dateadd(day, -2, convert(date, getdate()))
and gp_heurecreation < dateadd(day, -1, convert(date, getdate()))
If gp_heurecreation has no time component (in SQL Server, that's a date datatype), this is simpler:
where gp_heurecreation = dateadd(day, -2, convert(date, getdate()))

How to code a Date Range in SQL QUERY to go back 3 weeks from the current date and and Go forward 1 week from the current date

-- This code only pulls due dates within the next 7 days,it's ignoring the last 21 days
--How to code a Date Range in SQL QUERY to go back 3 weeks from the current date and and Go forward 1 week from the current date
select top 10 D.VendID as Customer , D.DueDate, sum(CuryTranAmt) as Amount, C.CpnyName Company
from APTran A
left join APDoc D
on A.RefNbr = D.RefNbr
inner join [SIVSYS].[dbo].[Company] C
on D.CpnyID = C.CpnyID
where
A.trantype NOT IN ('CK', 'HC')
and A.DrCr like 'C'
and (D.DueDate BETWEEN GETDATE() AND DATEADD(DAY, -21, GETDATE())) OR (D.DueDate BETWEEN GETDATE() AND DATEADD(DAY, +7, GETDATE()))
and D.DocBal <> '0'
group by
D.VendID
,C.CpnyName
,D.DueDate
,A.CuryTranAmt
,D.RefNbr
,D.BatNbr
order by (A.CuryTranAmt) desc
You first condition has bounds of between inverted: the lowest bound is greater than the upper bound, so no date can match on that.
I think that you just want:
where d.dueDate
between dateadd(day, -21, getdate())
and dateadd(day, 7, getdate())
Possibly, you want the entire days, so:
where
d.dueDate >= dateadd(day, -21, cast(getdate() as date))
and d.dueDate < dateadd(day, 6, cast(getdate() as date))

SQL Conditional Return HAVING

I have been unable to find the WHERE or HAVING condition that helps me return the following:
If a user has activity logged within the past month, I want to return records for the past six (6) months for those users. I have been using the following query so far...
SELECT
USER,
CAST(ACTIVITY AS DATE),
COUNT(DISTINCT ACTIONS),
SUM(RESULTS)
FROM
TABLE
WHERE
ACTIVITY >= DATEADD(MONTH, -6, GETDATE())
GROUP BY
[conditions]
ORDER BY
[conditions]
I have attempted to use
HAVING
(COUNT(USER) * CAST(DATEADD(MONTH, -1, GETDATE()) AS DECIMAL)) > 0
but I am getting records returns from inactive users who have only logged action within the past six (6) months, not the current or most recent month.
You could use the exists operator with a subquery for the users with activity in the last month:
SELECT
USER,
CAST(ACTIVITY AS DATE),
COUNT(DISTINCT ACTIONS),
SUM(RESULTS)
FROM
TABLE a
WHERE
ACTIVITY >= DATEADD(MONTH, -6, GETDATE()) AND
EXISTS (SELECT *
FROM TABLE b
WHERE a.USER = b.USER AND
ACTIVITY >= DATEADD(MONTH, -1, GETDATE()))
GROUP BY
USER
ORDER BY
[conditions]
From my understanding,
create table #date ( id int, logdate date)
insert #date values
(1,'2018-08-03') -- last month
, (1,'2018-05-03') -- before 4 month
, (1,'2018-03-03') -- before 6 month
, (1,'2018-02-03') -- before 7 month
, (2,'2018-09-03') -- logged on this month
, (2,'2018-05-03') -- before 4 month
, (3,'2018-07-03') -- before 2 month
select *, 'Who logged on before 6 months from last month'
from #date
WHERE DATEPART(m, logdate) <= DATEPART(m, DATEADD(m, -1, getdate())) -- logged date on last month
and DATEPART(m, logdate) >= DATEPART(m, DATEADD(m, -6, getdate())) -- logged date on before 6 months
and id in ( --
select id from #Date where DATEPART(m, logdate) = DATEPART(m, DATEADD(m, -1, getdate())) --
) -- Ids who Logged in past month
/* User 1, who logged on past month. So query gets his past 6 (3,4,5,6,7,8) month's logged date */
Revert me, if query will need update.

SQL Select between 2 times that cross over days

Hi i have been trying to put an SQL query together to pull data from 20:00 last night to 8 am today
what i currntly have is however this only selects between 20:00 and 24 because it's only selecting last night what would be the best way to get the results i am looking for?
SELECT COUNT(CardID) AS CardCOUNT
FROM ReaderData
WHERE (controllerID = 28) AND (ReaderTime BETWEEN '20:00:00' AND '08:00:00') AND (CardID = 'fffffff0') AND (DATEDIFF(DAY, DATEADD(DAY, - 1,
CURRENT_TIMESTAMP), dtReading) = 0)
You have split the time from the date so you have to check one time interval for yesterday and another for today.
If you are on SQL Server 2008 and have stored only the date part in dtReading you could use something like this.
select count(R.CardID) as CardCount
from ReaderData as R
where controllerID = 28 and
(
(
R.dtReading = cast(dateadd(day, -1, getdate()) as date) and
R.ReaderTime >= '20:00:00'
) or
(
R.dtReading = cast(getdate() as date) and
R.ReaderTime < '08:00:00'
)
)
Update
With the time values in dtReading it is easier.
Remove the time part from getdate() by casting to date then add the number of hours you want to create the datetime values you want to compare against.
select count(R.CardID) as CardCount
from ReaderData as R
where controllerID = 28 and
R.dtReading >= dateadd(hour, 20, dateadd(day, -1, cast(cast(getdate() as date) as datetime))) and
R.dtReading < dateadd(hour, 8, cast(cast(getdate() as date) as datetime))

MsSQL / Classic ASP - Select statement from time a to time b

I have quite a complex query that i need to expand but am not sure how to go about it.
At the moment, im using the following query to output a few values.
SELECT CONVERT(CHAR(8), pay.PaidUntil, 10) as LastDay,
COUNT(*) As PaymentsDue,
SUM(sales.Amount) As TotalDue
FROM UserPaidUntil pay INNER JOIN Sales sales
ON pay.Sales_ID = sales.Sales_ID
WHERE pay.PaidUntil > getDate()
AND pay.PaidUntil < DateAdd(day, 10, getDate())
AND pay.Billing_ID = 2
GROUP BY CONVERT(CHAR(8), pay.PaidUntil, 10)
ORDER BY CONVERT(CHAR(8), pay.PaidUntil, 10)
At the moment, this script get values between 2 dates, 10 days apart and then groups them by their date.
Now what i need to do is change the sql so that each day is actually from 10:01am on day A through to 10:00am on day B
The UserPaidUntil.PaidUntil is the field that has the dates
Im not sure where to start so i thought i would ask if anyone could help me.
Cheers
I don't have a tester for this statement.. It will be something like this :
SELECT CONVERT(CHAR(8), DateAdd(hour, 10, pay.PaidUntil), 10) as LastDay,
COUNT(*) As PaymentsDue,
SUM(sales.Amount) As TotalDue
FROM UserPaidUntil pay INNER JOIN Sales sales
ON pay.Sales_ID = sales.Sales_ID
WHERE DateAdd(hour, 10, pay.PaidUntil) > getDate()
AND DateAdd(hour, 10, pay.PaidUntil) < DateAdd(day, 10, getDate())
AND pay.Billing_ID = 2
GROUP BY CONVERT(CHAR(8), DateAdd(hour, 10, pay.PaidUntil), 10)
ORDER BY CONVERT(CHAR(8), DateAdd(hour, 10, pay.PaidUntil), 10)