Count of new users by Year SQL Query - sql

We have a subscription based business and a table with the account holders details and the signup date
I want to do a query that gets the count of new signups for each year.
I.E.
Table
USER / SIGNUPDATE
User 1 06/08/2013
User 2 06/08/2013
User 3 06/08/2014
User 4 06/08/2014
User 5 06/08/2014
User 6 06/08/2014
User 7 06/08/2014
User 8 06/08/2015
Returning record set
CountOfNewUsers2013 / CountOfNewUsers2014 / CountOfNewUsers2015
2 / 5 / 1
I can get the count for each year individually but not sure how or if I can group them together in one query.

select year(signupdate), count(*) as newusers
from tablename
group by year(signupdate)
You have to group by year of signupdate column.

I noticed you are trying to display the results in one row horizontally. This is not the way this data is typically displayed. it can be done that way, it's just a lot more work. I am assuming you are using SQL Server because you haven't mentioned which system. Here is how to do it with multiple rows (in two columns):
SELECT year(SIGNUPDATE) as [Year]
, count(USER) as CountOfNewUsers
FROM IDontKnowYourTableNameSorry
GROUP BY year(SIGNUPDATE)
Group by and count are the key features here if you want to look up their documentation.

Related

Get open cases counts for particular user in specific date range

I'm creating a SSRS report and I want to get the open cases for particular user in specific date range like below.
I have table called User from there I'm getting user info(User1,User2,User3).
I have open cases in the table management under description table.
I have c_date column in class table.
And I have 3 parameters user, startdate and enddate
And I need to use c_date between startdate and enddate.
If User enters startdate as 2019-01-01 and enddate as 2019-31-01, then I want to display the User1 who has open count.
For 0-5days and User1 who has open count for 6-11 days and same thing for user2 also.
Expected output:
User 0-5days 6-11days
---- ------- -------
User1 2 1
User2 1 4
User3 5 0
Explanation: User 1 has 2 open cases between 0-5 days means when I enter date range consider 2019-01-01 and 2019-31-01 so I have 2 open cases between first 0-5 days(2019-01-01 and 2019-05-01) and 1 open cases between next 6-11 days(2019-06-01 and 2019-11-01) etc.
Can I get result like this?
You should probably do this in the dataset query if possible. Use CASE and DATEDIFF to group your data something like
SELECT
[User],
[AnyOtherColumns],
CASE
WHEN DATEDIFF(d, #startdate, c_date) BETWEEN 0 AND 5 THEN '0-5'
WHEN DATEDIFF(d, #startdate, c_date) BETWEEN 6 AND 11 THEN '6-11'
ELSE 'older'
END AS [Age]
FROM myTable
WHERE [User] = #user
AND c_date BETWEEN #startdate AND #enddate
(done from memory so may not be perfect)
In your report you can use [User] on your row group, [Age] as your column group and then simply count any of the columns to give you the actual count of records.
You could do the counting in SQL too but I'm not sure if you need the detail for something else.
Considering you have two columns,
My approach would be
Have 3 parameters, one for user and other for To and from date.
Now selecting these parameters, add them to your dataset query as filter
Note you can apply filter on ssrs dataset as well but I would prefer on query level so that you have data been filtered and loaded only req one.
Then you can apply summing and grouping based on user and play around with Ssrs tablix to get the desired results.
https://www.mssqltips.com/sqlservertip/3453/sql-server-reporting-services-reports-with-optional-query-parameters/
https://reportsyouneed.com/ssrs-tip-put-parameters-in-your-query-not-your-filter/

MS Access Query to get multiple counts from the same field

I'm querying imported data that has a date/time field that I can't format as date in the table.
Sample:
Ticket Name Date
INC000101 User1 9/5/2016 10:00:34AM
INC000102 User2 9/5/2016 12:02:00PM
INC000103 User1 9/7/2016 3:34:00PM
INC000104 User2 10/1/2016 9:30:23AM
INC000105 User1 10/5/2016 10:20:00AM
INC000106 USer2 10/6/2016 4:56:00PM
I'm trying to get a count of how many tickets each user has per month. Because the Date field comes from the database as a text field, I can't seem to make that format as date/time so I use "left" to filter by month. This is what I've used to get a return on a single User item for the month of October.
SELECT COUNT(*)
FROM 2016YTD
WHERE [Name]='User1' AND left(Date,3) = '10/';
I would like to add counts for User2 through UserX per month so that I can get a count row or column for each the quantity of tickets for each user each month in one report. Everything I've tried won't save the query due to syntax errors in one form or another. I've tried variations of the following query help post as well without success.
SELECT a.distributor_id,
(SELECT COUNT(*) FROM myTable WHERE level='personal' and distributor_id = a.distributor_id) as PersonalCount,
(SELECT COUNT(*) FROM myTable WHERE level='exec' and distributor_id = a.distributor_id) as ExecCount,
(SELECT COUNT(*) FROM myTable WHERE distributor_id = a.distributor_id) as TotalCount
FROM myTable a ;
I'm sure the answer is staring at me, just not sure what at the moment.
Thanks for reading
John
This is only an answer to your first question about how to deal with dates that are stored in text fields.
To get the count for all users for every month you can do:
SELECT [Name], Format([Date],'mmmm') AS Month, COUNT(*) as Count
FROM 2016YTD
GROUP BY [Name], Format([Date],'mmmm')
A text field containing a date that is always in the same format can be treated as a date with Format() so Format([Date],'mmmm') returns the full month name for each date.
you should just need conditional aggregation. I haven't looked at access in a while but probably just something like this:
SELECT
a.distributor_id
,Format([Date],'mmmm') as Month
,SUM(IIF(level='personal',1,0)) as PersonalCount
,SUM(IIF(level='exec',1,0)) as ExecCount
,COUNT(*) as TotalCount
FROM
myTable a
GROUP BY
a.distributor_id
,Format([Date],'mmmm')

How to create SQL query

I have data(result / output) in a table like this:
Project code project name associates time efforts in days
1 Analytics amol,manisha,sayali,pooja (21+17+20+17)=57
I need to calculate the time efforts in days. I have done it for February and I have added each persons days he has worked in that month. I mean I have all days minus absentee of any day of all associates.
So, I need to do this by SQL queries.
I have one table which contains all the associates present with dates.
Like this:
UID username date
So can any one give me a suggestion how I could do this?
It will be a better design to have a separate table to store projectid, team member id and his/her efforts in days. so that you can write a simple join query to achieve what you want.
Here is what I would do. Change you tables so you have:
projects
project_code project_name
1 Analytics
users
UID username date
1 amol
2 manisha
3 sayali
projects_users
project_code uid effort
1 1 21
1 2 17
1 3 20
Now you can query the result you asked for like this:
SELECT
p.project_code,
p.project_name,
GROUP_CONCAT(DISTINCT u.username SEPARATOR ', ') AS associates,
SUM(pu.effort) effort
JOIN users AS u
JOIN projects_users AS pu
FROM projects p
GROUP BY project_code

General approach when needing to calculate values between rows

For the following table :
Id Timestamp AssignedTo
1 2012-01-01 User1
2 2012-01-02 User2
3 2012-01-10 User3
4 2012-01-15 User1
what would be the general approach in MS SQL Server to calculating how many days/hours/minutes the entity was assigned to a specific user?
As a developer (with basic SQL knowledge), I've always opted for Functions or Stored procedures when doing these kind of queries (these kind = queries including results based on the difference between two rows in a set).
In this example, I'd have a cursor iterating over the items, keeping the previous one in a variable, and then calculating the difference. However, I've been told that this is a serious performance concern, especially on large sets.
EDIT: Sample results
User TotalTime
User1 23d
User2 8d
User3 5d
i.e. the total time that an item was assigned to a specific user. User1's TotalTime is 23 days because it has been assigned to him since 2012-01-15 (and it's 2012-02-06 now), along with the first day it was assigned to him.
In this example I'd use a subquery within the select statement to get the end date for each row, then use this end date to get the time assigned to a specific user. The below is SQL Server syntax but the same principal can be applied whatever the RDBMS.
SELECT AssignedTo,
SUM(DATEDIFF(DAY, TimeStamp, ISNULL(EndDate, GETDATE()))) [Days]
FROM ( SELECT ID,
[TimeStamp],
AssignedTo,
( SELECT MIN(TimeStamp)
FROM [YOURTABLE] b
WHERE b.TimeStamp > a.TimeStamp
) [EndDate]
FROM [YOURTABLE] a
) a
GROUP BY AssignedTo

Sql Query - Limiting query results

I am quite certain we cannot use the LIMIT clause for what I want to do - so wanted to find if there are any other ways we can accomplish this.
I have a table which captures which user visited which store. Every time a user visits a store, a row is inserted into this table.
Some of the fields are
shopping_id (primary key)
store_id
user_id
Now what I want is - for a given set of stores, find the top 5 users who have visited the store max number of times.
I can do this 1 store at a time as:
select store_id,user_id,count(1) as visits
from shopping
where store_id = 60
group by user_id,store_id
order by visits desc Limit 5
This will give me the 5 users who have visited store_id=60 the max times
What I want to do is provide a list of 10 store_ids and for each store fetch the 5 users who have visited that store max times
select store_id,user_id,count(1) as visits
from shopping
where store_id in (60,61,62,63,64,65,66)
group by user_id,store_id
order by visits desc Limit 5
This will not work as the Limit at the end will return only 5 rows rather than 5 rows for each store.
Any ideas on how I can achieve this. I can always write a loop and pass 1 store at a time but wanted to know if there is a better way
Using two user variable and counting the same consecutive store_id, you can replace <= 5 with whatever limit you want
SELECT a.*
FROM (
SELECT store_id, user_id, count(1) as visits
FROM shopping
WHERE store_id IN (60,61,62,63,64,65,66)
GROUP BY store_id, user_id
ORDER BY store_id, visits desc, user_id
) a,
(SELECT #prev:=-1, #count:=1) b
WHERE
CASE WHEN #prev<>a.store_id THEN
CASE WHEN #prev:=a.store_id THEN
#count:=1
END
ELSE
#count:=#count+1
END <= 5
Edit as requested some explanation :
The first subquery (a) is the one that group and order the data so you will have data like:
store_id | user_id | visits
---------+---------+-------
60 1 5
60 2 3
60 3 1
61 2 4
61 3 2
the second subquery (b) init the user variable #prev with -1 and #count with 1
then we choose all data from the subquery (a) verifying the condition in the case.
verify that the previous store_id (#prev) we have seen is different from the current store_id.
Since the first #prev is equal to -1 there is nothing that match the current store_id so the condition <> is true we enter then is the second case who just serve to change the value #prev with the current store_id. This is the trick so i can change the two user variable #count and #prev in the same condition.
if the previous store_id is equal to #prev just increment the #count variable.
we check that the count is within the value we want so the <= 5
So with our test data the:
step | #prev | #count | store_id | user_id | visits
-----+-------+--------+----------+---------+-------
0 -1 1
1 60 1 60 1 5
2 60 2 60 2 3
3 60 3 60 3 1
4 61 1 61 2 4
5 61 2 61 3 2
Major concern over here is number of times you query a database.
If you query multiple times from your script. Its simply wastage of resources and must be avoided.
That is you must NOT run a loop to run the SQL multiple times by incrementing certain value. In your case 60 to 61 and so on.
Solution 1:
Create a view
Here is the solution
CREATE VIEW myView AS
select store_id,user_id,count(1) as visits
from shopping
where store_id = 60
group by user_id,store_id
order by visits desc Limit 5
UNION
select store_id,user_id,count(1) as visits
from shopping
where store_id = 61
group by user_id,store_id
order by visits desc Limit 5
UNION
select store_id,user_id,count(1) as visits
from shopping
where store_id = 62
group by user_id,store_id
order by visits desc Limit 5
Now use
SELECT * from MyView
This is limited because you cant make it dynamic.
What if you need 60 to 100 instead of 60 to 66.
Solution 2:
Use Procedure.
I wont go into how to write a procedure cuz its late night and I got to sleep. :)
Well, procedure must accept two values 1st inital number (60) and 2nd Count (6)
Inside the procedure create a temporary table (cursor) to store data then run a loop from initial number till count times
In your case from 60 to 66
Inside the loop write desired script Replacing 60 with a looping variable.
select store_id,user_id,count(1) as visits
from shopping
where store_id = 60
group by user_id,store_id
order by visits desc Limit 5
And append the result in the temporary table (cursor).
Hope this will solve your problem.
Sorry I couldn't give you the code. If you still need it plz send me a message. I will give it to you when I wake up next morning.
UNION may be what you are looking for.
-- fist store
(select store_id,user_id,count(1) as visits
from shopping
where store_id = 60
group by user_id,store_id
order by visits desc Limit 5)
UNION ALL
-- second store
(select store_id,user_id,count(1) as visits
from shopping
where store_id = 61
group by user_id,store_id
order by visits desc Limit 5)
...
http://dev.mysql.com/doc/refman/5.0/en/union.html
If you will not save data about when a user visited a store or something like this, you could simply update the table each time a user visits a store instead of appending a new row.
Something like this:
INSERT INTO `user_store` (`user_id`, `store_id`, `visits`) VALUES ('USER', 'SHOP', 1)
ON DUPLICATE KEY UPDATE `visits` = `visits` + 1
But I think this would not work, because neither user_id nor store_id are unique. You have to add a unique primary key like this: user#store or something else.
Another opinion would be to save this data (how often a user was in a store) in a separate table containing of ID, user_id, store_id, visits and increment visits everytime you also add a new row to you existing table.
To get the Top5 you can then use:
SELECT `visits`, `user_id` FROM `user_store_times` WHERE `store_id`=10 ORDER BY `visits` DESC LIMIT 5
The simplest way would be to issue 10 separate queries, one for each store. If you use parameterized queries (e.g. using PDO in PHP) this will be pretty fast since the query will be part-compiled.
If this still proves to be too resource-intensive, then another solution would be to cache the results in the store table - i.e. add a field that lists the top 5 users for each store as a simple comma-separated list. It does mean your database would not be 100% normalised but that shouldn't be a problem.