SQL - Count of a column until specific result - mysql

I have a table containing info on call attempts on contacts. The relevant fields are below:
Contact Date Result
John Smith 1/8/2013 VM
John Smith 1/9/2013 VM
John Smith 1/10/2013 Busy Signal
John Smith 1/11/2013 Hang Up <--- Connect
Jane Smith 1/8/2013 VM
Jane Smith 1/9/2013 Scheduled Call Back <--- Connect
Jane Smith 1/10/2013 VM
John Doe 1/8/2013 Not Interested <--- Connect
Jane Doe 1/8/2013 Busy Signal
Jane Doe 1/9/2013 Busy Signal
Jane Doe 1/10/2013 Busy Signal
I'm trying to get a count of the number of attempts until connect by contact (and not any attempts after the first connect), or the number of attempts so far if no connect has been made, and I'm having trouble. The results that would signify a connect in this case would be Hang Up, Scheduled Call Back and Not Interested.
What I am trying to get would look like:
Contact Attempts
John Smith 4
Jane Smith 2
John Doe 1
Jane Doe 3
Is there a way to do this? Any help would be greatly appreciated.

You need to look into using GROUP BY:
SELECT Contact, COUNT(*) Attempts
FROM Contacts
WHERE Result NOT IN ('Hang Up','Scheduled Call Back','Not Interested')
GROUP BY Contact
--EDIT
Didn't realize OP's request. And couldn't finish this before he accepted another answer...
Good luck.

For MySQL:
SELECT
t.Contact, COUNT(*) AS Attempts
FROM
tableX AS t
JOIN
( SELECT DISTINCT contact
FROM tableX
) AS d
LEFT JOIN
( SELECT contact,
MIN(date) AS date
FROM tableX
WHERE result IN ('Hang Up', 'Scheduled Call Back', 'Not Interested')
GROUP BY contact
) AS g
ON d.contact = g.contact
ON t.contact = d.contact
AND t.date <= COALESCE(g.date, '9999-12-31')
GROUP BY
t.contact ;

Related

Assign correct Responsible person from JSON format column based on Service Date

P.S. previous post was deleted, I hope this time it will reach more people.
I have huge history dataset and I need to assign value (ResponsibleName - from JSON format column) to a new 'Responsible' column based on Service Date for all rows associate with Client.
Each Client can have unique Responsible person (JSON column) for the specific date range:
If Codes Column contains Supervisor, then assign this Employee to only associated row as Responsible.
And finally, if Codes Column contains Employee, than assign associated Responsible person from the JSON column (for specific date range) to Responsible
I don't have issues with the first step, however I can't find a solution to implement the 2nd (last) statement.
Original History Table Joined with Client Table:
SELECT h.Id,
h.ServiceDate
h.ClientId,
cl.ClientName,
h.EmployeeName,
cl.ResponsibleJSON,
h.Codes
FROM History AS h
JOIN ClientTable AS cl
ON (h.ClientId = cl.ClientId)
Output of that table:
Id
ServiceDate
ClientId
ClientName
EmployeeName
ResponsibleJSON
Codes
1
2020-05-06
123
John Smith
Chris Evans
[{"ResponsibleName":"Kevin Costner","ResponsibleStartDate":"2019-02-14","ResponsibleEndDate":"2020-05-31"},{"ResponsibleName":"Tom Cruise", "ResponsibleStartDate":"2020-06-01","ResponsibleEndDate":null}]
Employee, Office
2
2020-05-08
123
John Smith
Tom Holland
[{"ResponsibleName":"Kevin Costner","ResponsibleStartDate":"2019-02-14","ResponsibleEndDate":"2020-05-31"},{"ResponsibleName":"Tom Cruise", "ResponsibleStartDate":"2020-06-01","ResponsibleEndDate":null}]
Supervisor, Remote
3
2020-05-11
123
John Smith
Chris Evans
[{"ResponsibleName":"Kevin Costner","ResponsibleStartDate":"2019-02-14","ResponsibleEndDate":"2020-05-31"},{"ResponsibleName":"Tom Cruise", "ResponsibleStartDate":"2020-06-01","ResponsibleEndDate":null}]
Employee, Office
4
2020-05-15
123
John Smith
Thomas Anderson
[{"ResponsibleName":"Kevin Costner","ResponsibleStartDate":"2019-02-14","ResponsibleEndDate":"2020-05-31"},{"ResponsibleName":"Tom Cruise", "ResponsibleStartDate":"2020-06-01","ResponsibleEndDate":null}]
Employee, Office
5
2020-06-10
123
John Smith
Tom Holland
[{"ResponsibleName":"Kevin Costner","ResponsibleStartDate":"2019-02-14","ResponsibleEndDate":"2020-05-31"},{"ResponsibleName":"Tom Cruise", "ResponsibleStartDate":"2020-06-01","ResponsibleEndDate":null}]
Supervisor, Office
6
2020-06-17
123
John Smith
Thomas Anderson
[{"ResponsibleName":"Kevin Costner","ResponsibleStartDate":"2019-02-14","ResponsibleEndDate":"2020-05-31"},{"ResponsibleName":"Tom Cruise", "ResponsibleStartDate":"2020-06-01","ResponsibleEndDate":null}]
Employee, Remote
7
2020-06-22
123
John Smith
Elon Mask
[{"ResponsibleName":"Kevin Costner","ResponsibleStartDate":"2019-02-14","ResponsibleEndDate":"2020-05-31"},{"ResponsibleName":"Tom Cruise", "ResponsibleStartDate":"2020-06-01","ResponsibleEndDate":null}]
Employee, Remote
8
2020-07-01
123
John Smith
Tom Holland
[{"ResponsibleName":"Kevin Costner","ResponsibleStartDate":"2019-02-14","ResponsibleEndDate":"2020-05-31"},{"ResponsibleName":"Tom Cruise", "ResponsibleStartDate":"2020-06-01","ResponsibleEndDate":null}]
Supervisor, Remote
I've created the table with all JSON data for all Clients:
SELECT c.ClientId,
c.ClientFullName,
c.ResponsibleJSON,
JSON_VALUE(X.VALUE,'$.ResponsibleName') AS ResponsibleName,
JSON_VALUE(X.VALUE,'$.ResponsibleStartDate') AS ResponsibleStartDate,
ISNULL(JSON_VALUE(X.VALUE,'$.ResponsibleEndDate'), '2999-12-31') AS ResponsibleEndDate
FROM ClientTable AS c
CROSS APPLY OPENJSON(c.ResponsibleJSON) AS X
ORDER BY c.ClientFullName, ResponsibleStartDate
And now I need to combine them somehow to produce column below:
Desired Output:
Responsible
Kevin Costner
Tom Holland
Kevin Costner
Kevin Costner
Tom Holland
Tom Cruise
Tom Cruise
Tom Holland
Code I need help with you can find below.
I don't know if I can OUTER APPLY in CASE statement AND I think JOIN should be ON ClientId and check if ServiceDate between ResponsibleStartDate AND ResponsibleEndDate.
SELECT h.Id,
h.ServiceDate
h.ClientId,
cl.ClientName,
h.EmployeeName,
cl.ResponsibleJSON,
h.Codes,
CASE
WHEN h.Codes LIKE '%Supervisor%' THEN h.EmployeeName --- 1st statement
WHEN --- here should be the second statement. I don't know how to implement it.
END AS Responsible
FROM History AS h
JOIN ClientTable AS cl
ON (h.ClientId = cl.ClientId)
It seems you only want to lookup the JSON when the Codes column does not contain Supervisor. The following query should do what you want:
SELECT
c.Id,
c.ServiceDate,
c.ClientId,
c.ClientName,
c.EmployeeName,
c.Codes,
Supervisor =
CASE WHEN c.Codes LIKE '%Supervisor%' THEN c.EmployeeName
ELSE (
SELECT TOP (1)
j.ResponsibleName
FROM OPENJSON(c.ResponsibleJSON)
WITH (
ResponsibleName nvarchar(100),
ResponsibleStartDate date,
ResponsibleEndDate date
) j
WHERE c.ServiceDate >= j.ResponsibleStartDate
AND (j.ResponsibleEndDate IS NULL OR c.ServiceDate <= j.ResponsibleEndDate)
)
END
FROM ClientTable c;
db<>fiddle

MySql searching for shared values across different rows

So I was looking for a possible solution to my problem but could not find it anywhere. I have a log table that logs users' visits (campaign name, IPs, useragent string, hostname etc etc). What I'm trying to get is a list of shared IPs that were seen across the campaigns I define.
so, here is my table for ex:
Log
-------------------------------------------------------------------
id ip campaignName UserName
-------------------------------------------------------------------
1 173.45.87.2 UK-Test John
2 12.45.76.53 Go-4 John
3 173.45.87.2 Robo-s John
4 67.55.33.77 Wrangles John
5 3.25.233.53 Stan-Die John
6 173.45.87.2 StartMa John
7 123.45.67.23 Fresh.Goal John
8 54.23.57.86 Ert56 John
9 173.45.87.2 Yuoit John
Desired output should be:
173.45.87.2
As this IP only appears in all UserName (John) campaigns.
forgot to mention that I know the UserName and all his campaigns, it's just the shared IPs across campaigns that I'm looking for.
Thanks for all helpers
SELECT ip
FROM Log
WHERE UserName = 'John'
GROUP BY ip
HAVING COUNT(*) > 1

MySQL time between different rows as an aggregate

This is my first post, so please forgive me for any formatting errors.
I need to find the time between each row of data for a large number of users, and then take the average of those times as a function of time. I know how to to do the latter part, I just don't know how to find the time differences between rows.
For example, I can generate this output very easily (for all users sequentially, just using 'John' as an example):
User order time
John 13 2013-10-31 22:35:19
John 12 2013-10-18 23:16:50
John 11 2012-12-07 00:38:34
John 10 2012-06-10 02:19:14
John 9 2010-07-02 00:55:54
John 8 2009-12-20 23:43:41
John 7 2009-12-20 01:14:32
John 6 2009-12-18 15:12:40
John 5 2009-12-13 00:38:38
John 4 2009-12-12 16:00:13
John 3 2009-12-12 14:50:18
John 2 2009-12-11 18:41:15
John 1 2009-12-04 03:12:06
But, what I need to find out how to do is create this:
User order time timeDiff
John 13 2013-10-31 22:35:19 13
John 12 2013-10-18 23:16:50 300
John 11 2012-12-07 00:38:34 170
John 10 2012-06-10 02:19:14 ...
John 9 2010-07-02 00:55:54 ...
John 8 2009-12-20 23:43:41 ...
John 7 2009-12-20 01:14:32 ...
John 6 2009-12-18 15:12:40 ...
John 5 2009-12-13 00:38:38 ...
John 4 2009-12-12 16:00:13 ...
John 3 2009-12-12 14:50:18 ...
John 2 2009-12-11 18:41:15 ...
John 1 2009-12-04 03:12:06 NULL
This is easily done in excel, but I need the grouping properties for users + dates in order to do some analysis.
All help appreciated!!
Try this
Select current.time - previous.time As TimeDiff
From UserTable current Join
UserTable previous On current.User = pervious.User And current.Order - 1 = previous.Order
Where current.User = 'John'
That should get you the time differences.
You said you knew how to get the average from there.
Like you said, it's easy in Excel. Referring to relative rows in SQL is pretty hard, especially in MySQL.
You have to use server-side variables to establish "state", so you can remember previous values. e.g.
SET prev := null;
SELECT User, Order, time, IF(#prev IS NOT NULL, time - #prev, null), #prev := time;
It gets even harder since you're doing this for multiple users, and will have to add extra code to detect when the user changes.
For this kind of thing, you're better off doing the calcs in client-side code. Which means just do:
SELECT User, Order, UNIX_TIMESTAMP(time)
...
ORDER BY User, Order
and then you can feed those timestamps directly to PHP's time system for formatting/calculations.

Limit MySQL End User to Viewing His Own Entries Only

My Table is like this
ID FileNumber SellerRep BuyerRep Address
123 142366 John Doe Steve Doe 123 Cute Ave
122 142365 Steve Doe John Doe 412 Best Blvd
121 142364 John Doe John Doe 234 Park Ave
120 132363 Steve Doe Steve Doe 233 Cool St
119 132362 Steve Doe Frank Good 432 Bad Street
users: johnd (lists his name as John Doe)
steved (lists his name as Steve Doe)
How can I limit end user to view/see only his own entries. His entries always include his name either in SellerRep or BuyerRep columns, and sometimes in both though they may possibly be misspelled (e.g. Steven Do, etc). However, either SellerRep or BuyerRep columns may include name of the non user as in the entry with ID # 119 in the table example.
So, basically, if Steve Doe logs in, I want him to see only entries with ID # 119, 120, 122, 123, and if John Doe logs in, I would like to limit his views only to records with ID # 123, 122, 121. One issues though is that One of them may have specify the full name of another user in either SellerRep or BuyerRep column, and I wouldn't want in this case the other user to see this entry.
Is there a way to accomplish this with views or triggers and not in PHP page, even if I have to add another column like #user with auto_complete if that possible.
The least what I could think of to start with is:
CREATE VIEW saleslogview
AS
SELECT *
FROM saleslog
WHERE SellerRep = 'Steve Doe';
CREATE VIEW saleslogview
AS
SELECT *
FROM saleslog
WHERE BuyerRep = 'John Doe';
CREATE VIEW saleslogview
AS
SELECT *
FROM saleslog
WHERE BuyerRep = 'Steve Doe';
CREATE VIEW saleslogview
AS
SELECT *
FROM saleslog
WHERE SellerRep = 'John Doe';
However, when I tried to log in as user steved or johnd with like SQLBuddy and tried to search records it did not work as intended - all records were "visible".
Perhaps there is a way to accomplish this using SESSION_USER(), but I don't know anything about it.

How can I write a SQL query with multiple COUNTs for different GROUP BYs?

One of my coworkers is working on a SQL query. After several joins (workers to accounts to tasks), she's got some information sort of like this:
Worker Account Date Task_completed
Bob Smith 12345 01/01/2010 Received
Bob Smith 12345 01/01/2010 Received
Bob Smith 12345 01/01/2010 Processed
Sue Jones 23456 01/01/2010 Received
...
Ultimately what she wants is something like this - for each date, for each account, how many tasks did each worker complete for that account?
Worker Account Date Received_count Processed_count
Bob Smith 12345 01/01/2010 2 1
... and there are several other statuses to count.
Getting one of these counts is pretty easy:
SELECT
COUNT(Task_completed)
FROM
(the subselect)
WHERE
Task_completed = 'Received'
GROUP BY
worker, account, date
But I'm not sure the best way to get them all. Essentially we want multiple COUNTs using different GROUP BYs. The best thing I can figure out is to copy and paste the subquery several times, change the WHERE to "Processed", etc, and join all those together, selecting just the count from each one.
Is there a more obvious way to do this?
SELECT worker, account, date,
SUM(task_completed = 'Received') AS received_count,
SUM(task_completed = 'Processed') AS processed_count
FROM mytable
GROUP BY
worker, account, date