SQL Conditional Return HAVING - sql

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.

Related

How to return values of two date ranges, from the same date column and value column, in two different columns as a result?

I have following data in my table,
Table = BillHeader
Sales column = Sales
Date column = CreateDate
Location name = Location
Result needed:
Location
Sum_of_Sale_1
Sum_of_Sale_2
Sum_of_Sale_1 = Sum of Sales up to yesterday for this month.
Sum_of_Sale_2 = Sum of Sales up to same date range as Sum_of_Sale_1 during last month.
For example, if today is 20th of June, Sum_of_Sale_1 = Sum of sales from 1st June to 19th of June
and Sum_of_Sale_2 = Sum of sales from 1st May to 19th of May.
Basically what I need is these two results of different date ranges, which should be selected form the same three columns, should appear next to each other in the result. I want to know how the sales performance was last month's same date range as to this month's date range (up to yesterday for this month).
Thanks!!
EDIT - 1
Here is the actual current working code:
SET #FDM = DATEADD(mm, DATEDIFF(mm, 0, GETDATE()), 0)
SELECT sum ([LAB_TRN_BillHeader].[AmountToBePaid]) as Total_Sale
,LAB.dbo.[LAB_TRN_BillHeader].[CollectingCenterCode]
,LAB.dbo.[LAB_Comm_MST_CollectingCenter].[Name]
,LAB.dbo.[LAB_Comm_MST_Branch].[BranchName]
FROM Lab.dbo.[LAB_TRN_BillHeader]
INNER JOIN LAB.dbo.[LAB_Comm_MST_CollectingCenter] on LAB.dbo.[LAB_TRN_BillHeader].[CollectingCenterCode] = LAB.dbo.[LAB_Comm_MST_CollectingCenter].[CollectingCenterCode]
INNER JOIN LAB.dbo.[LAB_Comm_MST_Branch] on LAB.dbo.[LAB_TRN_BillHeader].[BranchCode] = LAB.dbo.[LAB_Comm_MST_Branch].[BranchCode]
WHERE Date between #FDM and DATEADD(day,0, CAST(GETDATE() AS date)) and {{select_Laboratory}} and LAB.dbo.[LAB_TRN_BillHeader].[IsVoid] = '0' and LAB.dbo.[LAB_TRN_BillHeader].[CollectingCenterCode] in ('URCR022','MRPMC','KUCC','KOCC','EHECC')
GROUP BY LAB.dbo.[LAB_TRN_BillHeader].[CollectingCenterCode], LAB.dbo.[LAB_Comm_MST_CollectingCenter].[Name], LAB.dbo.[LAB_Comm_MST_Branch].[BranchName]
Current Result:
|Total_Sale|CollectingCenterCode|Name|BranchName|
|xxx |xxx |x |xx |
Required Result:
|Total_Sale|Total_Sale2|CollectingCenterCode|Name|BranchName|
|xxx |xxx |xx |x |xx |
Total_Sale = Sale of current month up to yesterday
Total_Sale2 = Sale of Last month up to current month's yesterday's date.
-- MSSQL Version - 2014
-- <Create_Date> is a time stamp in the table in <Create_Date> column. The date/time is obtained from that timestamp. Each transaction is saved with a respective timestamp at it's time of occurrence.
-- {{select_Laboratory}} is a field filter alias in Metabase (this code was copied from a Metabase dashboard). The actual code is LAB.dbo.[LAB_TRN_BillHeader].[BranchCode] = '001'
Considering a sales CreateDate is likely of type Datetime or Datetime2, a safe approach would be:
DECLARE #yesterday DATE = GETDATE();
DECLARE #lastMonth DATE = DATEADD(MONTH, -1, #yesterday);
DECLARE #firstDayOfThisMonth DATE = DATEADD(DAY, 1 - DAY(#yesterday), #yesterday);
DECLARE #firstDayOfLastMonth DATE = DATEADD(DAY, 1 - DAY(#lastMonth), #lastMonth);
SELECT #yesterday,
#firstDayOfThisMonth,
#lastMonth,
#firstDayOfLastMonth;
SELECT [locationId],
SUM( CASE
WHEN CreateDate >= #firstDayOfThisMonth
AND CreateDate < #yesterday THEN
AmountToBePaid
END
) AS Sum_of_Sale_1,
SUM( CASE
WHEN CreateDate >= #firstDayOfLastMonth
AND CreateDate < #lastMonth THEN
AmountToBePaid
END
) AS Sum_of_Sale_2
FROM BillHeader
GROUP BY [locationId];
EDIT: Note that in dates like March 31,30 previous month's end date could be Feb 28, 29.
You could use conditional aggregation with the following date functions:
DATEADD(Day, 1, EOMONTH(GETDATE(), -1)) gets the first date of the current month, i.e. current month is Jan-2023 it will return '2023-01-01'.
CAST(GETDATE() AS DATE) gets today's date.
DATEADD(Day, 1, EOMONTH(GETDATE(), -2)) gets the first date of the previous month, i.e. current month is Jan-2023 it will return '2022-12-01'.
DATEADD(Month, -1, CAST(GETDATE() AS DATE) gets the date of the day one-month pre today's date.
SELECT Location,
SUM(CASE
WHEN CreateDate >= DATEADD(Day, 1, EOMONTH(GETDATE(), -1)) AND
CreateDate < CAST(GETDATE() AS DATE)
THEN Sales END) Sum_of_Sale_1,
SUM(CASE
WHEN CreateDate >= DATEADD(Day, 1 ,EOMONTH(GETDATE(), -2)) AND
CreateDate < DATEADD(Month, -1, CAST(GETDATE() AS DATE))
THEN Sales END) Sum_of_Sale_2
FROM BillHeader
GROUP BY Location
See demo
There are different ways of doing the calculations and I don't know if this logic will seem more straightforward or as concise. Also you might not be able to use variables. Lastly, you didn't specify which version you're running.
Although you can incorporate this into an existing query that covers a wider range of dates, here is a stand-alone option that should restrict the execution to a narrower range of dates. The case logic, as written, does assume that rows have already been filtered so the only thing left to determine is whether the sale comes from current month or prior month.
select Location,
sum(case when month(CreateDate) <> month(getdate()) then Sales end) as Sales1,
sum(case when month(CreateDate) = month(getdate()) then Sales end) as Sales2
from BillHeader
where
-- go back enough days to guarantee covering last two months
-- this may be able to utilize an index
SalesDate between dateadd(day, -30 - day(getdate()), cast(getdate() as date))
and getdate()
-- now eliminate extra dates that are not relevant
and month(getdate()) - month(CreateDate) in (0, 1, -11) /* year might roll over */
and day(getdate()) > day(CreateDate)
group by Location;
For a YOY comparison over the same calendar month:
select Location,
sum(case when year(CreateDate) <> year(getdate()) then Sales end) as Sales1,
sum(case when year(CreateDate) = year(getdate()) then Sales end) as Sales2
from BillHeader
where
-- go back enough days to guarantee covering last 13 months
-- (or rewind as 396 days via parallel logic from earlier)
SalesDate between
dateadd(year, -1, dateadd(day, 1 - day(getdate()), cast(getdate() as date)))
and getdate()
and month(getdate()) = month(CreateDate)
and day(getdate()) > day(CreateDate)
group by Location;
This might be better done as a union with two different date ranges combined together:
-- ...
where
SalesDate between
dateadd(year, -1, dateadd(day, 1 - day(getdate()), cast(getdate() as date)))
and dateadd(year, -1, getdate())
-- ... union all ...
where
SalesDate between
dateadd(day, 1 - day(getdate()), cast(getdate() as date))
and getdate()
-- ...

Looking for a getdate/dateadd statement to do 1 year and +/- 15 days

-- This is my current code which will allow for me to see all our work orders that have been submitted within the past week, and lets me know if any of the same work orders have appear 6 months ago.
SELECT
A.tagnumber,
count(*) AS CountTotal
FROM
v_workorder A
WHERE
--Date range Within Today and 6 months ago
wo_requestDate BETWEEN DATEADD(month, -6, GETDATE()) AND GETDATE()
AND
EXISTS
( -- Date range Within Today and 7 days ago
select
tagnumber
FROM
v_workorder
WHERE
wo_requestDate BETWEEN DATEADD(DAY,-7,GETDATE()) AND GETDATE()
)
AND
A.wc_description = 'Corrective'
AND
A.itemtype_name = 'Building'
GROUP BY A.tagnumber
ORDER BY CountTotal DESC
--However, Now I would like for my first variable of the getdate/adddate. To check back 1 year ago, +/- 15 days. So essentially 1 year and 15 days back instead of 6 months.
For past 1 year +/- 15 Days
SELECT A.tagnumber, count(*) AS CountTotal
FROM v_workorder A
WHERE wo_requestDate BETWEEN DATEADD(day, -15, DATEADD(year, -1, GETDATE())) AND DATEADD(day, 15, DATEADD(year, -1, GETDATE()))
AND
EXISTS ( select tagnumber FROM v_workorder WHERE wo_requestDate BETWEEN DATEADD(DAY,-7,GETDATE()) AND GETDATE() )
AND
A.wc_description = 'Corrective' AND A.itemtype_name = 'Building'
GROUP BY A.tagnumber
ORDER BY CountTotal DESC
For 1 year
SELECT ...
FROM ...
WHERE wo_requestDate BETWEEN DATEADD(year, -1, GETDATE()) AND GETDATE()
AND...;
For 15 Days
SELECT ...
FROM ...
WHERE wo_requestDate BETWEEN DATEADD(day, -15, GETDATE()) AND GETDATE()
AND...;
Other possible options of DATEADD()
year
quarter
month
dayofyear
day
week
weekday
hour
minute
second
millisecond
See more here.
.
To eliminate issues with the time component of datetime:
CAST(GETDATE() AS DATE
Find the date from a year ago:
SELECT DATEADD(YEAR, -1, CAST(GETDATE() AS DATE));
From there, subtract 15 days and add 15 days in your end points.
...
WHERE
wo_requestDate >= DATEADD(DAY, -15, DATEADD(YEAR, -1, CAST(GETDATE() AS DATE)))
AND
wo_requestDate < DATEADD(DAY, 15, DATEADD(YEAR, -1, CAST(GETDATE() AS DATE)))
I prefer >= and < to BETWEEN, especially with dates, just to avoid any ambiguity with the time component, so you may want to add 16 days to the last parameter if you want the range to include the 15th day out.

Select all where date in Last month sql [duplicate]

This question already has answers here:
Get the records of last month in SQL server
(23 answers)
Closed 9 years ago.
How can I get last month date like
select * from table where date in ( last month )
I dont want the last 30 days
AND how can I get last month automatically
Assuming you want all items where the date is within the last month i.e. between today and 30/31 days ago:
Select *
From Table
Where Date Between DATEADD(m, -1, GETDATE()) and GETDATE()
You can use this
Select * from table where date between #startdate and #enddate
Or
SELECT * FROM DATE_SAMPLE WHERE
DATEPART(YEAR, SAMPLE_DATE) = '2013' AND
DATEPART(MONTH,SAMPLE_DATE) = '01' AND
DATEPART(DAY, SAMPLE_DATE) = '01'
Is it usefull for you?
select * from table
where month(date)=month(getdate())-1
Edit
if you mean last month from today. or previous month from a specific date then you need to do something like this
SELECT DATEPART(MONTH, DATEADD(MONTH, -1, [Date]))
Or to get records from previous month of the year you can do something like this
SELECT * FROM Table
WHERE MONTH(Date) = DATEPART(MONTH, DATEADD(MONTH, -1, [Date]))
AND YEAR(Date) = DATEPART(YEAR, DATEADD(MONTH, -1, [Date])) --<-- or pass year for which year you are checking
To make your aquery SARGable (Suggested by t-clausen.dk)
select * from table
where date >=dateadd(m, datediff(m, 0, current_timestamp)-1, 0)
and date < dateadd(m, datediff(m, 0, current_timestamp)-1, 0)
Read here more about sargable Queries when working with date/datetime datatypes.
You can try to use the between statement to get the specific dates:
Select * from table where date between '01-01-2014' and '14-01-2014'

SQL - Display running count of appointments grouped by time frame

I have a table
tblAppointment {
App_ID,
App_Date,
User_ID }
I currently have a statement that returns number of appointments grouped by year and month
SELECT
YEAR(App_Date) AS Year,
MONTH(App_Date) AS Month,
count(*) AS "No of Appointments"
FROM
tblapplication
GROUP BY
YEAR(App_Date),
MONTH(App_Date)
Im not sure how to write a select statement to return it with headings {time frame, No of applications}, and then have data in
row 1: time frame = week thus far, no of app = x.
row 2: time frame = month thus far, no of app = y.
ro3 3: time frame = year so far, no of app - z.
I would like to know how many appointments there are for 1. the current week, 2. the current month. 3. the current year, And have each result in its own row.
Any help in the right direction would be greatly appreciated. The actual problem is much greater than this but believe I have simplified it to the crux of the matter for now.
If you're okay with the results on one row, it's relatively easy:
select count(case when datepart(wk, App_Date) = datepart(wk, getdate())
then 1 end) as WeekSofFar
, count(case when datepart(m, App_Date) = datepart(m, getdate())
then 1 end) as MonthSofFar
, count(*) as YearSoFar
from tblApplications
where datepart(y, App_Date) = datepart(y, getdate())
If the separate rows are a must-have, try something like:
select 'WeekSoFar' as Period
, (
select count(*)
from tblApplications
where datepart(y, App_Date) = datepart(y, getdate())
and datepart(wk, App_Date) = datepart(wk, getdate())
) as NumberOfApps
union all
select 'MonthSoFar'
, (
select count(*)
from tblApplications
where datepart(y, App_Date) = datepart(y, getdate())
and datepart(m, App_Date) = datepart(m, getdate())
)
union all
select 'YearSoFar'
, (
select count(*)
from tblApplications
where datepart(y, App_Date) = datepart(y, getdate())
)
I assumed SQL 2008 as you didn't specify.
SELECT
X.TimePeriod,
Count(
CASE X.Which
WHEN 3 THEN
CASE
WHEN App_Date > DateAdd(Day, -DatePart(Weekday, GetDate()), GetDate())
THEN 1
END
WHEN 2 THEN CASE WHEN Month(App_Date) = Month(GetDate()) THEN 1 END
ELSE 1 END
) [No of Appointments]
FROM
tblApplication
CROSS JOIN (
VALUES (1, 'Year to date'), (2, 'Month to date'), (3, 'Week to date')
) X (Which, TimePeriod)
WHERE
App_Date < Convert(date, GetDate() + 1)
AND App_Date >= DateAdd(Year, DateDiff(Year, '19000101', App_Date), '19000101')
GROUP BY
X.Which,
X.TimePeriod
ORDER BY
X.Which
If you have a lot of data in your table and an index on App_Date, this query will perform hugely better than one using date functions on the entire table without filtering.
I also have an embedded assumption that your App_Date values have no time portion (they are all set to 12am). If this is not true please let me know so I can modify case 3 to be correct.
If anyone wants to try the code here's some setup:
CREATE TABLE tblApplication (
App_Date datetime
)
INSERT tblApplication
VALUES
('2/1/2012'), ('2/5/2012'), ('2/10/2012'), ('1/2/2012'), ('1/9/2012'),
('1/15/2012'), ('1/28/2012'), ('12/1/2012'), ('12/5/2012'), ('12/10/2012'),
('11/2/2012'), ('11/9/2012'), ('11/15/2012'), ('11/28/2012')
Sorry about not using 'YYYYMMDD', I wasn't thinking when I typed it out.

Sliding Window Average For Multiple Time Periods - SQL Server

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.