How to run sql n times increasing variable and after joining results - sql

I've a transact table (historical) with a CreatedDate, this transact is related to employee transact table. (inner join in transact_id)
This being said, comes the problem: I need to query these table and get the state by month , because during the year, the CreatedDate can change. e.g. An employee update in July will create a new line, but this shouldn't affect the March total.
The solution looks like a forech, but how can I join all lines at the end? The result should be something like:
January - $123
February - $234
March - $123
...
I get the last state of each employee with this:
select AllTransact.id_employee, AllTransact.id_department from (
select id_employee, id_department, rank() over (partition by id_employee order by created_date desc) desc_rank
from Transact_Employee TransEmployee
inner join Transact on TransEmployee.ID_Transact = Transact.ID_Transact
and Transact.Status = 8
and Transact.Created_Date < #currentMonth) AllTransact
where desc_rank = 1
*I don't want to copy and past all the code 12 times. :)

You can partition over many columns. rank() OVER (partition BY [id_employee],datepart(month,[Created_Date]) ORDER BY [Created_Date] DESC) will give you what you have now but for each month (and it doesn't care what year that month is in so you either need to partition by year too or add limit on created_date).

Related

group by category to show difference by month in SQL

I have a view that brings the total number of members in each class for each month however I want to show the growth by subtracting the total_count of the previous month with the current month in a separate column. For example, I would like to view the data as mentioned in the attached image. Here on that table, you can see the total count for a membership class "doctor" in the month of December is 5 however in January it's 4 so when I look at this report on February I would like to have a separate column called "Growth" which will subtract the January total member class from December total member class and show the growth. When we move to March it will do the same by subtracting the total member class of February with January and show the difference in the growth column. Any help on how can I achieve it through a query would be greatly appreciated. I'm using MS SQL.
As I mentioned, if you were on a supported version of SQL Server (2008 has been completely unsupported for 18~ months) this would be very simple:
SELECT JoinedDate,
MembershipClass,
TotalCount,
TotalCount - LAG(TotalCount) OVER (PARTITION BY MembershipClass ORDER BY JoinedDate ASC) AS Growth
FROM dbo.YourTable;
Instead, you'll need to use ROW_NUMBER, and a self join, which will be far less performant:
WITH RNs AS(
SELECT JoinedDate,
MembershipClass,
TotalCount,
ROW_NUMBER() OVER (PARTITION BY MembershipClass ORDER BY JoinedDate ASC) AS RN
FROM dbo.YourTable)
SELECT RN1.JoinedDate,
RN1.MembershipClass,
RN1.TotalCount,
RN1.TotalCount - RN2.TotalCount AS Growth
FROM RNs RN1
LEFT JOIN RNs RN2 ON RN1.MembershipClass = RN2.MembershipClass
AND RN1.RN = RN2.RN + 1;

SQL - calculating hours since the earliest date in a partition

I have the following SQL code:
select
survey.ContactId,
survey.CommId,
survey.CommCreatedDate,
survey.CommIdStatus,
br.[Value],
null as HoursPastSinceFirstActiveSurvey,
row_number() over (partition by survey.ContactId order by survey.CommCreatedDate desc) as [row]
from
Survey_Completed survey
inner join
Business_Rules br on br.Name = 'OPT_OUT_TIME'
where
survey.CommIdStatus = 'Active'
Which produces the following result set:
What I need help with is filling out HoursPastSinceFirstActiveSurvey. The logic here should be as follows:
Calculate the total number of hours that has passed since the earliest (by CommCreatedDate) record in the partition for consecutive (by day) records. In order to address the "consecutive" part, I was thinking perhaps it might be possible to add to the partitioning logic to only partition if the days are consecutive. I'm not entirely sure if that's possible though. So for example, look at the last two records. They are grouped as a partition and the dates are consecutive and the earliest date/time on this partition is Nov 11 2020 12:00 AM. So I would want to perform the following in order to populate HoursPastSinceFirstActiveSurvey for these two records:
Today's date minus Nov 11 2020 12:00 AM.
This would be the value for those two records in the partition for HoursPastSinceFirstActiveSurvey. I am not sure where to even start with this!! Thank you all.
I was able to solve for this by the following query. Feedback is entirely WELCOME!
select
Q2.ContactId,
min(Q2.CommCreatedDate) as MinDate,
max(Q2.CommCreatedDate) as MaxDate,
Q2.Consecutive,
datediff(hour, min(Q2.CommCreatedDate), max(Q2.CommCreatedDate)) AS HoursPassed
from
(select
Q1.ContactId,
Q1.CommId,
Q1.CommCreatedDate,
Q1.CommIdStatus,
Q1.[Value],
Q1.Consecutive,
Q1.[row],
Q1.countOfPartition
from
(select
survey.ContactId,
survey.CommId,
survey.CommCreatedDate,
survey.CommIdStatus,
br.[Value],
CAST(dateadd(day,-row_number() over (partition by survey.ContactId order by survey.CommCreatedDate), survey.CommCreatedDate) as Date) as Consecutive,
row_number() over (partition by survey.ContactId order by survey.CommCreatedDate desc) as [row],
count(*) over (partition by survey.ContactId) as countOfPartition
from
Survey_Completed survey
inner join
Business_Rules br on br.Name = 'OPT_OUT_TIME'
where
survey.CommIdStatus = 'Active') Q1
where
Q1.countOfPartition <> 1) Q2
group by
Q2.ContactId, Q2.Consecutive, Q2.[Value]
having
datediff(hour, min(Q2.CommCreatedDate), max(Q2.CommCreatedDate)) > Q2.[Value]

Is there a way to count how many strings in a specific column are seen for the 1st time?

**Is there a way to count how many strings in a specific column are seen for
Since the value in the column 2 gets repeated sometimes due to the fact that some clients make several transactions in different times (the client can make a transaction in the 1st month then later in the next year).
Is there a way for me to count how many IDs are completely new per month through a group by (never seen before)?
Please let me know if you need more context.
Thanks!
A simple way is two levels of aggregation. The inner level gets the first date for each customer. The outer summarizes by year and month:
select year(min_date), month(min_date), count(*) as num_firsts
from (select customerid, min(date) as min_date
from t
group by customerid
) c
group by year(min_date), month(min_date)
order by year(min_date), month(min_date);
Note that date/time functions depends on the database you are using, so the syntax for getting the year/month from the date may differ in your database.
You can do the following which will assign a rank to each of the transactions which are unique for that particular customer_id (rank 1 therefore will mean that it is the first order for that customer_id)
The above is included in an inline view and the inline view is then queried to give you the month and the count of the customer id for that month ONLY if their rank = 1.
I have tested on Oracle and works as expected.
SELECT DISTINCT
EXTRACT(MONTH FROM date_of_transaction) AS month,
COUNT(customer_id)
FROM
(
SELECT
date_of_transaction,
customer_id,
RANK() OVER(PARTITION BY customer_id
ORDER BY
date_of_transaction ASC
) AS rank
FROM
table_1
)
WHERE
rank = 1
GROUP BY
EXTRACT(MONTH FROM date_of_transaction)
ORDER BY
EXTRACT(MONTH FROM date_of_transaction) ASC;
Firstly you should generate associate every ID with year and month which are completely new then count, while grouping by year and month:
SELECT count(*) as new_customers, extract(year from t1.date) as year,
extract(month from t1.date) as month FROM table t1
WHERE not exists (SELECT 1 FROM table t2 WHERE t1.id==t2.id AND t2.date<t1.date)
GROUP BY year, month;
Your results will contain, new customer count, year and month

Grouping Start Dates

Example of what I am trying to do:
I have 10 employees. They all started on different days throughout the year. Each get paid once a week. I want to query their first paycheck and call that week 1 for all employees. Then each subsequent paycheck will be 2...3...through 13. So basically I want to see what each of their first 13 weeks on the job looked like stacked against each other. I would expect my output to look something like this:
You can use row_number():
select
row_number() over(partition by EmployeeId order by PaycheckDate) week,
EmployeeId,
PaycheckDate,
Amount
from mytable
order by week, EmployeeId
If you want just the first 13 weeks per employee, then:
select *
from (
select
row_number() over(partition by EmployeeId order by PaycheckDate) week,
EmployeeId,
PaycheckDate,
Amount
from mytable
) t
where week <= 13
order by week, EmployeeId

Get name of person having activity in every month - Oracle SQL

I have log table where there is are records with user id and the date for a specific activity done. I want to get names of users having activity every month. I am using the following query
select distinct(employeeid) from transactions
where eventdate between '01-OCT-13' AND '23-OCT-13'
and eventdate between '01-SEP-13' AND '01-OCT-13'
and eventdate between '01-AUG-13' AND '01-SEP-13'
and eventdate between '01-JUL-13' AND '01-AUG-13';
But this is doesn't work. Can someone please suggest any improvement?
Edit:
Since my questions seems to be a little confusing, here is an example
EmployeeID | Timestamp
a | 01-Jul-13
b | 01-Jul-13
a | 01-Aug-13
c | 01-Aug-13
a | 01-Sep-13
d | 01-Sep-13
a | 01-Oct-13
a | 01-Oct-13
In the above table, we can see that employee "a" has activity in all the months from July till October. So I want to find a list of all such employees.
You can use COUNT as analytical function and get the number of months for each employee and total number of months. Then select only those employees where both counts match.
select distinct employeeid
from (
select employeeid,
count(distinct trunc(eventdate,'month')) --count of months for each employee
over (partition by employeeid) as emp_months,
count(distinct trunc(eventdate,'month')) --count of all months
over () as all_months,
from transactions
)
where emp_months = all_months;
Wish I could give you the code, but i'm in a bit of a hurry, so this is more of a suggestion.
Have you tried extracting the distinct months (from eventdate), for every user, and if that has 10 rows (assuming it is October, you could dynamically change this), then the employee must of had an event every month.
By very inefficient, I think you mean it doesn't work. The same value can't be both in september, in october, etc.
Anyway, using #LaggKing suggestion, you could try this query:
SELECT employeeid
FROM (
SELECT DISTINCT employeeid, MONTH(eventdate)
FROM transactions
)
HAVING COUNT(*) = MONTH(NOW())
EDIT: You need to take year into account.
SELECT employeeid
FROM (
SELECT DISTINCT employeeid, MONTH(eventdate)
FROM transactions
WHERE YEAR(eventdate) = YEAR(NOW())
)
HAVING COUNT(*) = MONTH(NOW())