Count Distinct Persons Per Year, but Only Once - sql-server

How would I select distinct persons per year, but only count each person once.
An example of my data is:
ID Date
1 20NOV2018
2 06JUN2017
2 29JUL2011
3 05MAY2014
4 04APR2002
4 25APR2009
I want my output to look like:
2002 1
2009 0
2011 1
2014 1
2017 0
2018 1

Use sub-selects to left join the distinct years with the first year an id occurs and count the ids from that.
data have;
input
id date date9.; format date date9.; datalines;
1 20NOV2018
2 06JUN2017
2 29JUL2011
3 05MAY2014
4 04APR2002
4 25APR2009
run;
proc sql;
create table want as
select each.year, count(first.id) as appeared_count
from
( select distinct year(date) as year
from have
) as each
left join
( select id, min(year(date)) as year
from have group by id
) as first
on each.year = first.year
group by each.year
order by each.year
;

Hope this Code Works Fine for Your case:
SELECT YEAR(M.DATE) AS DATE,COUNT(S.ID)
FROM #TAB M
LEFT JOIN (SELECT MIN(YEAR(DATE)) AS DATE ,ID
FROM #TAB GROUP BY ID) S ON YEAR(M.DATE)=S.DATE GROUP BY YEAR(M.DATE) ORDER BY YEAR(M.DATE)

Related

Need to generate rows with missing data in a large dataset - SQL

We are comparing values between months over multiple years. As time moves on the number of years and months in the dataset increases. We are only interested in months where there were values for every year, i.e. a full set.
Consider the following example for 1 month (1) over 3 years (1,2,3) and two activities (101, 102)
Dataset:
Activity Month year Count
------- ---- ------ ------
101 1 1 2
101 1 2 3
101 1 3 1
102 1 1 1
102 1 2 1
In the example above only activity 101 will come into consideration as it satisfies the condition that there must be a count for the activity for month 1 IN year 1, 2 and 3.
Activity 102 doesn't qualify for further analysis as it has no record for year 3.
I would like to generate a record with which I can then evaluate this. The record will effectively generate the new record with the missing row (in this case 102, 1, 3 , 0) to complete the dataset
Activity Month year Count
------- ---- ------ ------
102 1 3 0
We find the problem difficult as the data keeps in growing, the number of activities keep expanding and it is a combination of activity, year and month that need to be evaluated.
An elegant solution will be appreciated.
As I mention in my comment, presumably you have both an Activity table and some kind of Calendar table with details of your activities and the years in your system. As such you can therefore do a CROSS JOIN between these 2 objects and then LEFT JOIN to your table to get the data set you want:
--Create sample objects/data
CREATE TABLE dbo.Activity (Activity int); --Obviously your table has more columns
INSERT INTO dbo.Activity (Activity)
VALUES (101),(102);
GO
CREATE TABLE dbo.Calendar (Year int,
Month int);--Likely your table has more columns
INSERT INTO dbo.Calendar (Year, Month)
VALUES(1,1),
(2,1),
(3,1);
GO
CREATE TABLE dbo.YourTable (Activity int,
Year int,
Month int,
[Count] int);
INSERT INTO dbo.YourTable (Activity,Month, Year, [Count])
VALUES(101,1,1,2),
(101,1,2,3),
(101,1,3,1),
(102,1,1,1),
(102,1,2,1);
GO
--Solution
SELECT A.Activity,
C.Month,
C.Year,
ISNULL(YT.[Count],0) AS [Count]
FROM dbo.Activity A
CROSS JOIN dbo.Calendar C
LEFT JOIN dbo.YourTable YT ON A.Activity = YT.Activity
AND C.[Year] = YT.[Year]
AND C.[Month] = YT.[Month]
WHERE C.Month = 1; --not sure if this is needed
If you don't have an Activity and Calendar table (I suggest, however, you should), then you can use subqueries with a DISTINCT, but note this will be far from performant with large data sets:
SELECT A.Activity,
C.Month,
C.Year,
ISNULL(YT.[Count],0) AS [Count]
FROM (SELECT DISTINCT Activity FROM dbo.YourTable) A
CROSS JOIN (SELECT DISTINCT Year, Month FROM dbo.YourTable) C
LEFT JOIN dbo.YourTable YT ON A.Activity = YT.Activity
AND C.[Year] = YT.[Year]
AND C.[Month] = YT.[Month]
WHERE C.Month = 1; --not sure if this is needed

I want to get data if records are not present in specific month

I wrote a sql query to get all records happen in specific month
select month(loggingdate),Count(id) from communicationlogs
where clientid=20154 and month(loggingdate) in (1,2,3,4,5,6,7,8,9)
group by month(loggingdate)
7 65
8 5
here records are present in 7th and 8th month. I want to get 0 value for other month numbers like-
1 0
2 0
3 0
4 0
...
This is a standard problem where a calendar table comes in handy. A calendar table, as the name implies, is a table which just stores a sequence of dates. In your particular case, we only need the digits corresponding to the 12 months. Begin the query with the calendar table and then left join to your aggregation query as a subquery.
Note the use of COALESCE below. If a given month appears nowhere in your original query, then its count would show up as NULL in the join, in which case we report zero for that month.
WITH calendar_month AS (
SELECT 1 AS month
UNION ALL
SELECT month +1
FROM
calendar_month
WHERE month +1 <= 12
)
SELECT
t1.month,
COALESCE(t2.cnt, 0) AS cnt
FROM calendar_month t1
LEFT JOIN
(
SELECT
MONTH(loggingdate) as month,
COUNT(id) AS cnt
FROM communicationlogs
WHERE
clientid = 20154 AND
MONTH(loggingdate) IN (1,2,3,4,5,6,7,8,9)
GROUP BY MONTH(loggingdate)
) t2
ON t1.month = t2.month

Combine two results in one row

EmpID Name Date Earn
1 A 7/1/2014 2
1 A 7/1/2014 4
1 A 7/2/2014 1
1 A 7/2/2014 2
2 B 7/1/2014 5
2 B 7/2/2014 5
I would like combine two results in one row as below.here is my statement but i want to find the solution to get the Total_Earn?. Thank
"SELECT EmpID, Name, Date, Sum(earn) FROM employee WHERE Date between DateFrom and DateTo
GROUP BY EmpID, Name, Date"
EmpID Name Date Earn Total_Earn
1 A 7/2/2014 3 9
2 B 7/2/2014 5 10
It looks like you want the Max date and the Sum of Earn for each employee. Assuming you want one record for each ID/Name, you would do this:
select EmpID, Name, Max(Date), Sum(Earn)
from YourTableName
group by EmpID, Name
Try this. Substitute the date for whatever value you want.
SELECT table1.EmpID, table1.Name, table1.Date, table1.Earn, table2.Total_Earn
FROM
(SELECT EmpID, Name, Date, Earn
FROM yourtablename
WHERE Date = "2014-07-02"
GROUP BY EmpID) table1
LEFT JOIN
(SELECT EmpID, SUM(Earn)
FROM yourtablename
WHERE Date <= "2014-07-02"
GROUP BY EmpID) table2
ON table1.EmpID = table2.EmpID
This will perform two SELECTs and join their results. The first select (defined as table1) well select the employee ID and earnings for the specified date.
The second statement (defined as table2) will select the total earnings for an employee up to and including that date.
The two statements are then joined together according to the employee ID.

Loop through month and year till date while using a merge statement

I have 2 tables with the following datas in them:-
Company
CompanyId CompanyName
1 Company1
2 Company2
3 Company3
Employees
EmployeeId EmployeeName CompanyId StartDate
1 Employee1 1 12/21/2011
2 Employee2 1 01/20/2012
3 Employee3 2 03/23/2012
4 Employee4 2 07/15/2012
5 Employee5 2 01/20/2013
6 Employee6 3 12/17/2013
Now i want to check, How many people were recruited in the team in the specified month and year? I have the storage table as follows:-
RecruiterIndicator
CompanyId Year Month EmployeeRecruited
1 2011 12 1
1 2012 1 1
2 2012 3 1
2 2012 7 1
2 2013 1 1
3 2013 12 1
This should be a merge stored procedure that should update the data if it is present for the same month year and company and insert if that is not present? The loop would start from a particular date that can be an parameter and it would loop through the current month.
Please help me with this
Thanks
Vishal
SELECT YEAR(StartDate) AS [Year], MONTH(StartDate) AS [Month], COUNT(*) EmpTotal
FROM Employees
GROUP BY YEAR(StartDate), MONTH(StartDate)
If you want to see the Total Employees by company as well you can do something like this
SELECT YEAR(StartDate) AS [Year], MONTH(StartDate) AS [Month]
,C.CompanyName , COUNT(E.EmployeeId) EmpTotal
FROM Employees E INNER JOIN Company C
ON E.CompanyId = C.CompanyId
GROUP BY YEAR(StartDate), MONTH(StartDate) ,C.CompanyName

SQL How to show '0' value for a month, if no data exists in the table for that month

First of all my result looks like this:
KONTONR
Month
SELSKAPSKODE
BELOP
459611
1
BAGA
156000
459611
2
BAGA
73000
459611
4
BAGA
217000
459611
5
BAGA
136000
459611
1
CIVO
45896
459611
3
CIVO
32498
459611
4
CIVO
9841
330096
1
BAGA
42347
330096
3
BAGA
3695
I'm trying to show month 2 month bookings on several accounts, per account (KONTONR) there are several codes (SELSKAPSKODE) on which bookings are recorded (the sum of the bookings as BELOP). I would like to give an overview of the sum of the bookings (BELOP) per account (KONTONR) per month per code (SELSKAPSKODE). My problem is the codes don't show in a month if no bookings are made on that code. Is there a way to fix this? I understand why the codes don't show, since they're simply not in the table I'm querying. And I suspect that the solution is in making a 'fake' table which I then join (left outer join?) with 'another' table.
I just can't get it to work, I'm pretty new to SQL. Can someone please help?
My query looks like this (I only inserted the 'nested' query to make a set-up for a join, if this makes sense?!):
SELECT TOP (100) PERCENT KONTONR, Month, SELSKAPSKODE, BELOP
FROM (
SELECT SELSKAPSKODE, KONTONR, SKIPS_KODE, MONTH(POSTDATO) AS Month, SUM(BELOP) AS BELOP
FROM dbo.T99_DETALJ
WHERE (POSTDATO >= '2012-01-01') AND (BILAGSART = 0 OR BILAGSART = 2)
GROUP BY SELSKAPSKODE, KONTONR, SKIPS_KODE, MONTH(POSTDATO)
) AS T99_summary
GROUP BY KONTONR, SELSKAPSKODE, Month, BELOP
ORDER BY KONTONR, SELSKAPSKODE, Month
So concluding I would like to 'fill up' the missing months (see table at the start), for instance for account (KONTONR) 459611 month 3 is 'missing'. I would like to show month 3, with the sum of the bookings (BELOP) as '0'. Any help is greatly appreciated, thanks in advance!
You can query a table with the values 1-12 and left outer join your result.
Here is a sample using a table variable instead of your query and a CTE to build a table with numbers.
declare #T table
(
Month int
)
insert into #T values(1)
insert into #T values(1)
insert into #T values(1)
insert into #T values(3)
insert into #T values(3)
;with Months(Month) as
(
select 1
union all
select Month + 1
from Months
where Month < 12
)
select M.Month,
count(T.Month) Count,
isnull(sum(T.Month), 0) Sum
from Months as M
left outer join #T as T
on M.Month = T.Month
group by M.Month
Result:
Month Count Sum
----------- ----------- -----------
1 3 3
2 0 0
3 2 6
4 0 0
5 0 0
6 0 0
7 0 0
8 0 0
9 0 0
10 0 0
11 0 0
12 0 0
if you don't want to do all that you could also modify this: SUM(BELOP) with this:
Sum (case when BELOP is not null then 1 else 0 end)
You can also add in the year if you have a creation date for the interactions you are counting which may be helpful if your interactions span the course of many years.
with Months(Month) as
(
select 1
union all
select Month + 1
from Months
where Month < 12
)
select M.Month, year(CreatedOn) as Year,
count(amount) Count,
isnull(sum(amount), 0) Sum
from Months as M
left outer join Charge as C
on M.Month = (month(CreatedOn))
group by M.Month, year(CreatedOn) order by year(CreatedOn)

Resources