Group the application within the following time frames - sql

UserName | Time Frame | No of Applications
Daniel | Week to date | 3
Daniel | Month to date | 10
Daniel | Year to date |400
Please help me get the above format, below is my statement and output.
select j.UserName, i.App_Date as "Time Frame", count(*) as "Num. of Applications"
from tblApplication as i, tblUsers as j
where i.User_ID = j.User_ID
group by j.UserName, i.App_Date
union
select distinct a.UserName, b.App_Date, count(b.User_ID)
from tblUsers as a left join tblApplication as b on a.User_ID = b.User_ID
where b.User_ID is null
group by a.UserName, b.App_Date
Output:
UserName Time Frame Num. of Applications
----------- ------------------ --------------------
Daniel 3
Daniel 12/31/2012 12:00:00 AM 1
Daniel 1/1/2013 12:00:00 AM 1
Daniel 2/17/2013 10:37:15 AM 1
Daniel 2/18/2013 10:37:15 AM 1
Daniel 2/19/2013 10:37:15 AM 1
Daniel 2/20/2013 10:37:15 AM 1
Daniel 2/21/2013 10:37:15 AM 1
Daniel 2/22/2013 10:37:15 AM 1

To see the results on separate rows for different date ranges, try:
select u.UserName, d.TimeFrame, count(a.User_ID)
from
(select dateadd(d, 1-datepart(dw,getdate()), dateadd(dd, datediff(dd,0, getDate()), 0)) StartDate,
'Week to date' TimeFrame union all
select dateadd(d, 1-datepart(dd,getdate()), dateadd(dd, datediff(dd,0, getDate()), 0)),
'Month to date' union all
select dateadd(d, 1-datepart(dy,getdate()), dateadd(dd, datediff(dd,0, getDate()), 0)),
'Year to date') d
cross join tblUsers as u
left join tblApplication as a
on u.User_ID = a.User_ID and d.StartDate <= a.App_Date
group by u.UserName, d.TimeFrame
order by u.UserName, max(d.StartDate) desc
SQLFiddle here.

Your query needs improvement in several ways. Learn how to use proper join syntax. The join conditions belong in an on clause rather than in the where clause. Also, use reasonable aliases for tables. i and j don't mean anything. a and u make more sense (abbreviations for the table names).
The following puts this logic into three columns for each user:
select u.UserName,
sum(case when date(now() - dayofweek(now())) = date(app_date - dayofweek(app_date)) then 1 else 0 end) as WeekToDate,
sum(case when MONTH(now()) = month(app_date) then 1 else 0 end) as MonthToDate,
sum(case when year(now()) = year(app_date) then 1 else 0 end) as YearToDate
from tblApplication a join
tblUsers u
on a.User_Id = u.User_id
group by u.UserName;

Related

How to combine 3 separate SQL statements into 1 set of results

I have a SQL query that I am running 3 times (3 changing only the date range) and want to combine the result into one table, instead of running 3 different queries and trying to join outside of SQL. I am trying to find amount of times something has occurred per day/month/year. I'm running this in SQL Server.
I have 2 tables; one has the date of the transaction, and the other has the information I need (first 3 characters of the InventoryNumber table) so I am having to join these tables. I then want to group by the first 3 characters of the inventory number, and add the count in the column.
The end goal is to have something that looks like this:
InvNum | DayCount | MonthCount | YearCount
abc | 2 | 10 | 40
def | 0 | 2 | 6
xyz | 0 | 0 | 2
Here is my query for the single day one. This works exactly like I want it to. But now, I want to add on there the counts for the Month, and then the counts for the year also. The only thing that would change between this query and the other 2 is the count column name, and then the date.:
SELECT
LEFT(LINEITEM.InventoryNumber, 3) AS InvNum,
COUNT(*) AS DailyCount
FROM
INVOICE
INNER JOIN
LINEITEM ON INVOICE.InvoiceID = LINEITEM.InvoiceID
WHERE
InventoryNumber IS NOT Null
AND InventoryNumber != 'Misc'
AND DateCreated > '5-20-2022'
GROUP BY
LEFT(LINEITEM.InventoryNumber, 3)
ORDER BY
InvNum ASC;
I have looked through some of the other questions similar to this, but their queries were much simpler and I was not able to replicate the same thing with my queries.
Any help is appreciated.
Without knowing enough here, you should consider a conditional aggregation
Declare #D Date='2022-05-20';
SELECT InvNum = LEFT(LINEITEM.InventoryNumber, 3)
,DayCount = sum( case when DateCreated = #D then 1 else 0 end )
,MonthCount = sum( case when month(DateCreated) = month(#D) then 1 else 0 end )
,YearCount = sum( case when year(DateCreated) = year(#D) then 1 else 0 end )
FROM INVOICE
INNER JOIN LINEITEM ON INVOICE.InvoiceID = LINEITEM.InvoiceID
WHERE InventoryNumber IS NOT Null
AND InventoryNumber <> 'Misc'
AND DateCreated >= format(#D,'yyyy-01-01')
GROUP BY LEFT(LINEITEM.InventoryNumber, 3)
ORDER BY InvNum ASC;
Looks like you need conditional aggregation with three different start dates.
DECLARE #D date = '2022-05-20';
DECLARE #M date = '2022-04-21';
DECLARE #Y date = '2021-05-21';
SELECT InvNum = LEFT(li.InventoryNumber, 3)
,DayCount = COUNT(CASE WHEN i.DateCreated >= #D THEN 1 END)
,MonthCount = COUNT(CASE WHEN i.DateCreated >= #M THEN 1 END)
,YearCount = COUNT(*)
FROM INVOICE i
INNER JOIN LINEITEM li ON i.InvoiceID = li.InvoiceID
WHERE li.InventoryNumber <> 'Misc'
AND i.DateCreated >= #Y
GROUP BY
LEFT(li.InventoryNumber, 3)
ORDER BY
InvNum;
Note that <> 'Misc' also excludes nulls, and that ASC is the default.
You can also calculate those start dates dynamically
DECLARE #D date = DATEADD(day, -1, CAST(GETDATE() AS date));
DECLARE #M date = DATEADD(month, -1, CAST(GETDATE() AS date));
DECLARE #Y date = DATEADD(year, -1, CAST(GETDATE() AS date));
This maybe will do the work for you:
SELECT ISNULL(DailyQuery.InvNum, ISNULL(MonthlyQuery.InvNum, YearlyQuery.InvNum)) as InvNum,
ISNULL(DailyCount,0) as DailyCount,
ISNULL(MonthlyCount,0) as MonthlyCount,
ISNULL(YearlyCount,0) as YearlyCount
FROM
(SELECT
LEFT(LINEITEM.InventoryNumber, 3) AS InvNum,
COUNT(*) AS DailyCount
FROM
INVOICE
INNER JOIN
LINEITEM ON INVOICE.InvoiceID = LINEITEM.InvoiceID
WHERE InventoryNumber != 'Misc'
AND DateCreated > DATEADD(day, DATEDIFF(day, 0, GETDATE()-1), 0) --first hour day before
GROUP BY
LEFT(LINEITEM.InventoryNumber, 3)
) DailyQuery
FULL JOIN
(SELECT
LEFT(LINEITEM.InventoryNumber, 3) AS InvNum,
COUNT(*) AS MonthlyCount
FROM
INVOICE
INNER JOIN
LINEITEM ON INVOICE.InvoiceID = LINEITEM.InvoiceID
WHERE InventoryNumber != 'Misc'
AND DateCreated > DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0) --first day of current month
GROUP BY
LEFT(LINEITEM.InventoryNumber, 3) ) MonthlyQuery ON DailyQuery.InvNum = MonthlyQuery.InvNum
FULL JOIN
(SELECT
LEFT(LINEITEM.InventoryNumber, 3) AS InvNum,
COUNT(*) AS YearlyCount
FROM
INVOICE
INNER JOIN
LINEITEM ON INVOICE.InvoiceID = LINEITEM.InvoiceID
WHERE InventoryNumber != 'Misc'
AND DateCreated > DATEADD(year, DATEDIFF(year, 0, GETDATE()), 0) --first day of current month
GROUP BY
LEFT(LINEITEM.InventoryNumber, 3) ) YearlyQuery ON MonthlyQuery.InvNum = YearlyQuery.InvNum
you need to write three queries each query results in these tables based on the column and date in the where clause
just change the column and date value in the where clause for each table
first query result
InvNum | DayCount
abc | 2
def | 0
xyz | 0
second query result:
InvNum | MonthCount
abc | 10
def | 2
xyz | 0
third query result:
InvNum | YearCount
abc | 40
def | 6
xyz | 2
and then join these three tables on InvNum column

How can I get distinct data from one col

I need to get member personal data for all our members whose subscriptions have lapsed i.e. have a subscription end date before 31/03/2020, however I want to show one member record only (distinct by membership number) ideally the most recent one
I've tried a ROW_NUMBER() solution SQL - Distinct One Col, Select Multiple other? and a cross apply solution sql distinct, getting 2 columns but I can't get it to work.
SELECT membershipnumber AS Id,
subscription.enddate
FROM [dbo].[userprofile]
INNER JOIN dbo.subscription
ON userprofile.id = subscription.userprofileid
INNER JOIN dbo.subscriptiontype
ON subscriptiontype.id = subscription.subscriptiontypeid
Output is
Id Enddate
1 2006-04-01 00:00:00.000
1 2001-04-01 00:00:00.000
1 1999-04-01 00:00:00.000
1 1998-04-01 00:00:00.000
1 2008-04-01 00:00:00.000
1 2007-04-01 00:00:00.000
1 2011-04-01 00:00:00.000
1 2005-04-01 00:00:00.000
1 2000-04-01 00:00:00.000
1 1997-04-01 00:00:00.000
2 1999-04-01 00:00:00.000
2 2012-04-01 00:00:00.000
2 2004-04-01 00:00:00.000
2 2001-04-01 00:00:00.000
2 2018-04-01 00:00:00.000
2 2009-04-01 00:00:00.000
2 2005-04-01 00:00:00.000
2 1997-04-01 00:00:00.000
Desired output
Id Enddate
1 2011-04-01 00:00:00.000
2 2018-04-01 00:00:00.000
Solved sql answer
;WITH cte
AS (SELECT membershipnumber AS Id,
subscription.enddate,
Row_number()
OVER (
partition BY membershipnumber
ORDER BY subscription.enddate DESC) AS rownumber
FROM [dbo].[userprofile]
INNER JOIN dbo.subscription
ON userprofile.id = subscription.userprofileid
INNER JOIN dbo.subscriptiontype
ON subscriptiontype.id = subscription.subscriptiontypeid
)
SELECT *
FROM cte
WHERE rownumber = 1
https://stackoverflow.com/a/6841644/5859743
Not sure if I got your question right.
but you can use DISTINCT in the SELECT, that would show only one record for each member.
SELECT DISTINCT Membershipnumber as Id
,'P' as PartyType
,'A' as Status
,case
when Name = 'Standard Membership paid annually.' and EndDate > '2020-03-31' then 'Member'
when Name = 'Lapsed subscription renewal' and EndDate > '2020-03-31' then 'Member'
when Name = '3 Year Subscription (members outside of UK and Ireland, Jersey, Guernsey and the Channel Islands)' and EndDate > '2020-03-31' then 'Overseas member'
when Name = '1 Year Subscription (members outside of UK and Ireland, Jersey, Guernsey and the Channel Islands).' and EndDate > '2020-03-31' then 'Overseas member'
when Name = 'Lapsed subscription renewal' and EndDate > '2020-03-31' then 'Member'
when Name = 'Lifetime membership' then 'Lifetime member'
when Name = 'Retired membership paid annually' and EndDate > '2020-03-31' then 'Retired member'
else 'Non member'
end As MemberType
,Title as NamePrefix
,FirstName as FirstName
,Surname as LastName
,DateOfBirth as BirthDate
,'Home' as AddressPurpose
,'Default' as CommunicationReasons
,AddressLine1
,AddressLine2
,AddressLine3
,Addressline4 as CityName
,'' as CountrySubEntityName
,Country as CountryCode
,'' as CountryName
,Postcode as PostalCode
,EmailAddress as Email
FROM [dbo].[UserProfile]
inner join dbo.Subscription on
UserProfile.Id = Subscription.UserProfileId
inner join dbo.SubscriptionType on
SubscriptionType.id = Subscription.SubscriptionTypeId```
If you are getting as above mentioned output. Then from that, your desired output will easily get using distinct.
; with cte as (
----- query which gives you above mentioned output
)
select distinct id, max(Enddate) as Enddate from cte
I suspect you want something like this:
select *
from (select . . ., -- all the columns you want
row_number() over (partition by Membershipnumber as Id order by s.Enddate) as seqnum
from [dbo].[UserProfile] up inner join
dbo.Subscription s
on up.Id = s.UserProfileId inner join
dbo.SubscriptionType st
on st.id = s.SubscriptionTypeId
) x
where seqnum = 1;

SQL Join two tables by unrelated date

I’m looking to join two tables that do not have a common data point, but common value (date). I want a table that lists the date and total number of hired/terminated employees on that day. Example is below:
Table 1
Hire Date Employee Number Employee Name
--------------------------------------------
5/5/2018 10078 Joe
5/5/2018 10077 Adam
5/5/2018 10078 Steve
5/8/2018 10079 Jane
5/8/2018 10080 Mary
Table 2
Termination Date Employee Number Employee Name
----------------------------------------------------
5/5/2018 10010 Tony
5/6/2018 10025 Jonathan
5/6/2018 10035 Mark
5/8/2018 10052 Chris
5/9/2018 10037 Sam
Desired result:
Date Total Hired Total Terminated
--------------------------------------
5/5/2018 3 1
5/6/2018 0 2
5/7/2018 0 0
5/8/2018 2 1
5/9/2018 0 1
Getting the total count is easy, just unsure as the best approach from the standpoint of "adding" a date column
If you need all dates within some window then you need to join the data to a calendar. You can then left join and sum flags for data points.
DECLARE #StartDate DATETIME = (SELECT MIN(ActionDate) FROM(SELECT ActionDate = MIN(HireDate) FROM Table1 UNION SELECT ActionDate = MIN(TerminationDate) FROM Table2)AS X)
DECLARE #EndDate DATETIME = (SELECT MAX(ActionDate) FROM(SELECT ActionDate = MAX(HireDate) FROM Table1 UNION SELECT ActionDate = MAX(TerminationDate) FROM Table2)AS X)
;WITH AllDates AS
(
SELECT CalendarDate=#StartDate
UNION ALL
SELECT DATEADD(DAY, 1, CalendarDate)
FROM AllDates
WHERE DATEADD(DAY, 1, CalendarDate) <= #EndDate
)
SELECT
CalendarDate,
TotalHired = SUM(CASE WHEN H.HireDate IS NULL THEN NULL ELSE 1 END),
TotalTerminated = SUM(CASE WHEN T.TerminationDate IS NULL THEN NULL ELSE 1 END)
FROM
AllDates D
LEFT OUTER JOIN Table1 H ON H.HireDate = D.CalendarDate
LEFT OUTER JOIN Table2 T ON T.TerminationDate = D.CalendarDate
/* If you only want dates with data points then uncomment out the where clause
WHERE
NOT (H.HireDate IS NULL AND T.TerminationDate IS NULL)
*/
GROUP BY
CalendarDate
I would do this with a union all and aggregations:
select dte, sum(is_hired) as num_hired, sum(is_termed) as num_termed
from (select hiredate as dte, 1 as is_hired, 0 as is_termed from table1
union all
select terminationdate, 0 as is_hired, 1 as is_termed from table2
) ht
group by dte
order by dte;
This does not include the "missing" dates. If you want those, a calendar or recursive CTE works. For instance:
with ht as (
select dte, sum(is_hired) as num_hired, sum(is_termed) as num_termed
from (select hiredate as dte, 1 as is_hired, 0 as is_termed from table1
union all
select terminationdate, 0 as is_hired, 1 as is_termed from table2
) ht
group by dte
),
d as (
select min(dte) as dte, max(dte) as max_dte)
from ht
union all
select dateadd(day, 1, dte), max_dte
from d
where dte < max_dte
)
select d.dte, coalesce(ht.num_hired, 0) as num_hired, coalesce(ht.num_termed) as num_termed
from d left join
ht
on d.dte = ht.dte
order by dte;
Try this one
SELECT ISNULL(a.THE_DATE, b.THE_DATE) as Date,
ISNULL(a.Total_Hire,0) as Total_Hire,
ISNULL (b.Total_Terminate,0) as Total_terminate
FROM (SELECT Hire_date as the_date, COUNT(1) as Total_Hire
FROM TABLE_HIRE GROUP BY HIRE_DATE) a
FULL OUTER JOIN (SELECT Termination_Date as the_date, COUNT(1) as Total_Terminate
FROM TABLE_TERMINATE GROUP BY HIRE_DATE) a
ON a.the_date = b.the_date

Select overlapping holidays per department

I'm trying to check if any of the employees at my company are requesting overlapping holidays. It's the policy that only 1 person per department is allowed to be off at once.
What query should I use? (I am a noob, so tell me if you need more information).
An Example of the table I want to use:
Request ID Employee ID Department ID Start Date End Date
1 10 1 2015-12-20 2016-12-27
2 10 1 2016-06-01 2015-06-14
3 11 1 2015-12-26 2015-12-27
4 11 1 2016-06-09 2016-06-23
5 12 2 2015-12-26 2015-12-26
6 12 2 2016-07-01 2016-07-14
Results:
Request ID Status
1 Not Approved, overlapping 26-27/12
2 Not Approved, overlapping 09-14/06
3 Not Approved, overlapping completely
4 Not Approved, overlapping 09-14/06
5 Approved, not overlapping in this department
6 Approved, not overlapping in this department
In the second phase, I want to compare if the holidays requested, are within a week, containing a bank holiday (I will have a different table with the bank holidays).
Thanks in advance!
One way is with exists:
select e.*,
(case when exists (select 1
from example e2
where e2.departmentid = e.departmentid and
e2.employeeid <> e.employeeid and
e2.startdate <= e.enddate and
e2.enddate >= e.startdate
)
then 'Overlapping'
else 'NotOverlapping'
end) as Status
from example e;
Getting your full message is trickier and depends on the database. The problem are multiple overlaps.
Actually, we can get more information without too much problem:
select e.RequestId,
(case when count(e2.RequestId) = 0
then 'Approved, not overlapping in this department'
when count(e2.RequestId) = 1
then (case when min(e2.startdate) <= e.startdate and
max(e2.enddate) >= e.enddate
then 'Not Approved, overlapping completely'
else 'Not Approved, overlapping partially'
end)
else 'Not Approved, multiple overlaps'
end) as Status
from example e left join
example e2
on e2.departmentid = e.departmentid and
e2.startdate <= e.enddate and
e2.enddate >= e.startdate and
e2.employeeid <> e.employeeid
group by e.RequestId, e.startdate, e.enddate;
Getting the actual dates is trickier, without knowing the database.
create table #holidays(RequestID int, EmployeeID int, DepartmentID int, StartDate date, EndDate date)
insert into #holidays
select 1, 10, 1, '2015-12-20', '2016-12-27'
union select 2, 10, 1, '2016-06-01', '2015-06-14'
union select 3, 11, 1, '2015-12-26', '2015-12-27'
union select 4, 11, 1, '2016-06-09', '2016-06-23'
union select 5, 12, 2, '2015-12-26', '2015-12-26'
union select 6, 12, 2, '2016-07-01', '2016-07-14'
with CTE
as (
select T1.RequestID,max(T2.RequestID) as T2RequestID, count(*) as cnt
from #holidays T1
join #holidays T2 on
T1.DepartmentID = T2.DepartmentID
and T1.StartDate < T2.EndDate and T1.EndDate > T2.StartDate
and T1.RequestID <> T2.RequestID
group by T1.RequestID
)
select H.*,
case
when isnull(CTE.cnt,0) = 0 then 'Approved, not overlapping in this department'
else 'Not Approved, overlapping ' + convert(nvarchar(50),H2.StartDate) + ' - ' + convert(nvarchar(50),H2.EndDate)
end as Res
from #holidays H
left join CTE on H.RequestID = CTE.RequestID
left join #holidays H2 on H2.RequestID = CTE.T2RequestID
Btw, first employer have too big holidays - more than 1 year long :)
Another StartDate > EndDate (what is it ?)
Result

MySQL Weekday/Weekend count - Part II

I have posted about this before, which helped to give me the following SQL:
SELECT fname, MONTH( eventDate ) , IF( WEEKDAY( eventDate ) <5, 'weekday', 'weekend' ) AS
DAY , COUNT( * )
FROM eventcal AS e
LEFT JOIN users AS u ON e.primary = u.username
GROUP BY fname, MONTH( eventDate ) , IF( WEEKDAY( eventDate ) <5, 'weekday', 'weekend' ) ;
And that gives me the following results:
fname MONTH( eventDate ) DAY COUNT( * )
Kevin 7 weekday 3
Kevin 7 weekend 1
Missy 7 weekday 3
Missy 7 weekend 1
I'm having some trouble trying to achieve the following format:
fname MONTH( eventDate ) Weekday COUNT WEEKEND COUNT
Kevin 7 3 1
Missy 7 3 1
Can anyone offer some help? I would greatly appreciate it...
You can see my schemas for 'user' and 'eventcal' at: MySQL/PHP Algorithm for Weekday/Weekend count (per month)
SELECT
fname,
MONTH(eventDate),
SUM(IF(WEEKDAY(eventDate) < 5,1,0)) AS WeekdayCount,
SUM(IF(WEEKDAY(eventDate) >= 5,1,0)) AS WeekendCount
FROM eventcal AS e
LEFT JOIN users AS u ON e.primary = u.username
GROUP BY fname, MONTH(eventDate);
You want to do your aggregations (SUM in this case) in the SELECT, and GROUP BY how you want them totaled (by fname, by MONTH).