SQL - Get count of phone calls that resulted in meeting - mysql

I have a table named 'reports', something like this:
id
user_id
type
customer_id
text
created_at
1
1
1
3
....
2021-08-07 17:00:52
2
1
1
3
....
2021-08-12 10:11:11
3
1
1
9
....
2021-08-12 10:08:14
4
1
2
3
....
2021-08-12 10:04:08
5
1
2
9
....
2021-08-13 20:32:21
6
2
1
7
....
2021-08-13 20:34:17
7
2
2
8
....
2021-08-14 18:55:09
I want to get the count of rows that a user has submitted type 1 reports that result in a type 2 report.
Type 1 report means reporting a phone call to the customer and type 2 means meeting the customer. I want to receive the number of calls that resulted in an meeting.
For example, for user 1 should returns 3, because for customer 3, IDs 1 and 2 have led to ID 4, and for customer 9, ID 3 has led to ID 5.
But for user 2, ID 7 is type 2 but there is no previous type 1 report for customer 8, so it returns 0.

Schema (MySQL v5.7)
CREATE TABLE reports
(id int auto_increment primary key,
user_id int,
type int,
customer_id int,
text varchar(4),
created_at varchar(19)
);
INSERT INTO reports
(id, user_id, type, customer_id, text, created_at)
VALUES
(1, 1, 1, 3, '....', '2021-08-07 17:00:52'),
(2, 1, 1, 3, '....', '2021-08-12 10:11:11'),
(3, 1, 1, 9, '....', '2021-08-12 10:08:14'),
(4, 1, 2, 3, '....', '2021-08-12 10:04:08'),
(5, 1, 2, 9, '....', '2021-08-13 20:32:21'),
(6, 2, 1, 7, '....', '2021-08-13 20:34:17'),
(7, 2, 2, 8, '....', '2021-08-14 18:55:09');
Query #1
SELECT x.user_id
, COUNT(DISTINCT y.id) total
FROM reports x
LEFT
JOIN reports y
ON y.id<=x.id
AND y.user_id = x.user_id
AND y.customer_id = x.customer_id
AND y.type = 1
WHERE x.type = 2
GROUP
BY x.user_id;
user_id
total
1
3
2
0
View on DB Fiddle

You haven't shown how your are expecting results, but simply refer to User 1 and 2 and the total votes, you can try using a lateral join
select user_id, Coalesce(Sum(valid),0) rowcount
from reports r
join lateral (
select
case when exists (select * from reports rr
where rr.user_id=r.user_Id and rr.type=2 and rr.customer_id=r.customer_Id and r.type=1)
then 1 end valid
)x
group by User_Id
Example Fiddle

First you Count the number of customers that comply with your criterioa type and typoe 2. But ti get all user you need to join the list of users
I used LEFT join as also RIGHt JOIN in my example
CREATE TABLE reports
(`id` int, `user_id` int, `type` int, `customer_id` int, `text` varchar(4), `created_at` varchar(19))
;
INSERT INTO reports
(`id`, `user_id`, `type`, `customer_id`, `text`, `created_at`)
VALUES
(1, 1, 1, 3, '....', '2021-08-07 17:00:52'),
(2, 1, 1, 3, '....', '2021-08-12 10:11:11'),
(3, 1, 1, 9, '....', '2021-08-12 10:08:14'),
(4, 1, 2, 3, '....', '2021-08-12 10:04:08'),
(5, 1, 2, 9, '....', '2021-08-13 20:32:21'),
(6, 2, 1, 7, '....', '2021-08-13 20:34:17'),
(7, 2, 2, 8, '....', '2021-08-14 18:55:09')
;
SELECT IFNULL(Counts,0),t1.user_id
FROM (SELECT COUNT(distinct r.customer_id) counts,user_id
FROM reports r
WHERE type = 1 AND EXISTS(SELECT 1 FROM reports WHERE type = 2 AND customer_id = r.customer_id)
GROUP BY user_id) r RIGHT JOIN (SELECT DISTINCT user_id FROm reports) t1 ON r.user_id = t1.user_id
IFNULL(Counts,0) | user_id
---------------: | ------:
2 | 1
0 | 2
SELECT IFNULL(Counts,0),t1.user_id
FROM (SELECT DISTINCT user_id FROm reports) t1 LEFT JOIN (SELECT COUNT(distinct r.customer_id) counts,user_id
FROM reports r
WHERE type = 1 AND EXISTS(SELECT 1 FROM reports WHERE type = 2 AND customer_id = r.customer_id)
GROUP BY user_id) r ON r.user_id = t1.user_id
IFNULL(Counts,0) | user_id
---------------: | ------:
2 | 1
0 | 2
db<>fiddle here

Related

How to get how many chapters read by user in mysql

I am having three tables bible_chapters, bible_reading_portions, user_bible_trackings, 1 chapter may have multiple bible portions and we are tracking portions in user_bible_trackings table. Below is my schema:-
bible_chapters
id chapter_name
1 Chpt1
2 Chpt2
3 Chpt3
bible_reading_portions
id bible_chapter_id portion_name
1 1 Chp1P1
2 2 Chp2P1
3 2 Chp2P2
4 2 Chp2P3
5 3 Chp3P1
user_bible_trackings
id bible_reading_portion_id user_id
1 1 1
2 2 1
3 3 1
4 4 1
5 1 1
6 2 1
7 3 1
8 4 1
9 1 1
10 2 1
So you see that above user_bible_trackings table user_id 1 have read Chpt1 3 times and Chpt2 2 times and user again started the chapter2 3rd time but its not complete yet beacuse chapt2 belongs to 3 portions,.... for the 3rd time user not read all the portions. So my expected output be like:-
user_id total_chapteres_read
1 5 // i.e means user read chpt1 3 times and chpt2 2 times so count will be 3+2=5
Can anyone help me how can i acheieve the same.
#Akina PLease check i have added the schema queries below:-
CREATE TABLE `bible_chapters` (
`id` int(11) NOT NULL,
`chapter_name` varchar(150) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `bible_chapters` (`id`, `chapter_name`) VALUES
(1, 'Chp1'),
(2, 'Chp2'),
(3, 'Chp3');
---------------------
CREATE TABLE `bible_reading_portions` (
`id` int(11) NOT NULL,
`bible_chapter_id` int(11) NOT NULL,
`portion_name` varchar(50) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `bible_reading_portions` (`id`, `bible_chapter_id`, `portion_name`)
VALUES
(1, 1, 'Chp1p1'),
(2, 2, 'Chp2p2'),
(3, 2, 'Chp2p2'),
(4, 2, 'Chp2p3');
-----------
CREATE TABLE `user_bible_trackings` (
`id` int(11) NOT NULL,
`bible_reading_portion_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `user_bible_trackings` (`id`, `bible_reading_portion_id`, `user_id`) VALUES
(1, 1, 1),
(2, 2, 1),
(3, 3, 1),
(4, 4, 1),
(5, 1, 1),
(6, 2, 1),
(7, 3, 1),
(8, 4, 1),
(9, 1, 1),
(10, 2, 1);
WITH
cte1 AS (
SELECT ubt.user_id,
bc.id bc_id, bc.chapter_name,
brp.id brp_id, brp.portion_name,
COUNT(*) cnt
FROM bible_chapters bc
JOIN bible_reading_portions brp ON bc.id = brp.bible_chapter_id
JOIN user_bible_trackings ubt ON brp.id = ubt.bible_reading_portion_id
GROUP BY 1,2,3,4,5
),
cte2 AS (
SELECT user_id, bc_id,
COUNT(brp_id) portions_count,
MIN(cnt) complete_readings
FROM cte1
GROUP BY 1,2
)
SELECT user_id, SUM(complete_readings) total_readings
FROM cte2
GROUP BY 1
fiddle with some comments.
The solution does not check does all portions of a chapter were read. For to take this into account you must compare portions_count (added but not used) with the same value for a chapter (obtained in separate CTE).

Case, group by , join on multiple table

I have 3 tables transaction , store and date. A column in store table needs to be assigned values based on conditions and that new column needs to be used in group by.
ASK is to find ` total sales across different banners for a particular time period.
i am using following query..
"""select sum(net_spend) as sales , d.fis_week_id, st.banner
from ( select s*,
CASE WHEN st.format IN ('S','S MINI','S HYPER') THEN 'S'
WHEN st.format = 'CHECKERS' THEN 'CHECKERS'
ELSE st.format END AS banner
from store_dim s) st
from transaction_item_fct tr
inner join date_dim d on d.date_id = tr.date_id
inner join store_dim_c s on st.store_id = tr.store_id
where d.fis_week_id >=201809 and d.fis_week_id<=201813
and tr.store_id = st.store_id
group by st.banner, d.fis_week_id
"""
Where I am getting wrong?
Below is the fabricated tables' data
Transaction table-
store_id week_id net_spend
1 12 345
1 11 788
2 13 556
3 11 300
Store table
store_id format
1 S
2 S MINI
3 S Hyper
4 Checker
Date table
week_id fis_week_id
11 201712
12 201717
Result expected is
week_id banner spend
11 S 888
11 Hyper 666
It's not 100% clear from your question but I think this query will do what you want. You will need to change the WHERE condition on d.fis_week_id as appropriate for your needs, I have made it appropriate for the demo case I set up.
SELECT d.week_id, st.banner, SUM(t.net_spend) AS sales, d.fis_week_id
FROM date_dim d
LEFT JOIN transaction_item t ON t.week_id = d.week_id
JOIN (SELECT store_id,
CASE WHEN format IN ('S', 'S MINI', 'S Hyper') THEN 'S'
WHEN format = 'Checker' THEN 'Checker'
ELSE format
END AS banner
FROM store_dim s) st
ON st.store_id = t.store_id
WHERE d.fis_week_id BETWEEN 201712 AND 201720
GROUP BY d.week_id, st.banner
I've expanded your demo data out a bit and created a test case at SQLFiddle:
CREATE TABLE transaction_item
(`store_id` int, `week_id` int, `net_spend` int);
INSERT INTO transaction_item
(`store_id`, `week_id`, `net_spend`)
VALUES (1, 12, 345), (1, 11, 788), (2, 13, 556), (3, 11, 300),
(4, 11, 440), (4, 12, 123), (5, 11, 100), (6, 13, 444);
CREATE TABLE store_dim
(`store_id` int, `format` varchar(7));
INSERT INTO store_dim
(`store_id`, `format`)
VALUES (1, 'S'), (2, 'S MINI'), (3, 'S Hyper'), (4, 'Checker'), (5, 'Checker'), (6, 'Other');
CREATE TABLE date_dim
(`week_id` int, `fis_week_id` int);
INSERT INTO date_dim
(`week_id`, `fis_week_id`)
VALUES (11, 201712), (12, 201717), (13, 201720);
Output:
week_id banner sales fis_week_id
11 Checker 540 201712
11 S 1088 201712
12 Checker 123 201717
12 S 345 201717
13 Other 444 201720
13 S 556 201720

MySQL: select list of battles, not shared between 2 users

I need to select list of "battle_id", which first "user_id" have, but not shared with second "user_id",
battles (table structure):
id user_id battle_id
0 1 44
1 1 55
2 1 66
3 2 44
4 2 77
5 3 88
6 3 99
7 4 44
8 4 55
9 4 66
sample of input and output:
example 1: input [user_id = 1, user_id = 2] output => 55,66
example 2: input [user_id = 1, user_id = 3] output => 44,55,66
example 3: input [user_id = 1, user_id = 4] output => null
thanks,
Sample data:
CREATE TABLE t
(`id` int, `user_id` int, `battle_id` int)
;
INSERT INTO t
(`id`, `user_id`, `battle_id`)
VALUES
(0, 1, 44),
(1, 1, 55),
(2, 1, 66),
(3, 2, 44),
(4, 2, 77),
(5, 3, 88),
(6, 3, 99),
(7, 4, 44),
(8, 4, 55),
(9, 4, 66)
;
Query:
select
battle_id
from
t
group by battle_id
having sum(user_id = 1) >= 1 and sum(user_id = 2) = 0
Result:
| battle_id |
|-----------|
| 55 |
| 66 |
Explanation:
You don't need to self join like suggested in comments. Do it in one go.
The user_id = 'whatever' inside the sum() function in having clause returns either true or false, meaning 1 or 0.
see it working live in an sqlfiddle.
You can use subqueries here. Somthing like that:-
SELECT battle_id
FROM battles
WHERE user_id IN ('Your first user_id', 'Your second user_id')
AND battle_id NOT IN (SELECT battle_id
FROM battles
WHERE user_id = 'Your second user_id');

SELECT columns FROM t1, join with COUNT of columnX in t2, COUNT of columnY in t3

I am trying to combine data from 3 tables as follows :
SELECT u.USER_ID,u.USERNAME,u.FIRST_NAME,u.LAST_NAME,u.ISACTIVE,
u.ISADMIN, COUNT(m.PURCHASED_ID) AS MOVIES_PURCHASED,
COUNT(r.RENTED_ID) AS MOVIES_RENTED
FROM TBL_USERS AS u
LEFT JOIN TBL_MOVIE_PURCHASED AS m
ON u.USER_ID = m.USER_ID
LEFT JOIN TBL_RENTED_MOVIES AS r
ON u.USER_ID = r.USER_ID
GROUP BY u.USER_ID,u.USERNAME,u.FIRST_NAME,u.LAST_NAME,u.ISACTIVE,u.ISADMIN
ORDER BY MOVIES_PURCHASED, MOVIES_RENTED;
The tables have the following columns :
TBL_USERS :
USER_ID, USERNAME, FIRSTNAME, LASTNAME, ISACTIVE, ISADMIN
TBL_MOVIE_PURCHASED :
USER_ID, MOVIE_ID, PURCHASE_ID, PURCHASED_ON (purchase ID is unique)
TBL_RENTED_MOVIES :
USER_ID, MOVIE_ID, RENTED_ID, RENTED_ON (rented ID is unique )
I am trying to display :
1. all contents of TBL_USERS
2. the count of the rented movies for every user from TBL_RENTED_MOVIES,
3. the count of the purchased movies for every user from TBL_MOVIES_PURCHASED.
4. ORDER BY the results based on both COUNTS.
If say user1 has rented 5 movies and purchased 10 movies, then the query is supposed to return :
(MOVIES_PURCHASED, MOVIES_RENTED) = (5,10).
Instead, the query returns 5*10 = 50 for both columns :
(MOVIES_PURCHASED, MOVIES_RENTED) = (50,50)
I know I have gone wrong in joining the results. I tried using UNION to combine results as well but didnt work. Any ideas?
Hence, The output should Ideally be :
USER_ID, USERNAME, FIRST_NAME, LAST_NAME, ISACTIVE, ISADMIN, MOVIES_PURCHASED, MOVIES-RENTED :
1, user1, userFirst, userLast, Active, NotAdmin, 5, 10
. Any help is appreciated.
Here's one way...
CREATE table USERS(USER_ID integer primary key,
USERNAME varchar(50), FIRST_NAME varchar(50),
LAST_NAME varchar(50), ISACTIVE VARCHAR(10)
DEFAULT '0',
ISADMIN VARCHAR(10) DEFAULT '0');
CREATE table MOVIES_PURCHASED(PURCHASE_ID integer primary key,
USER_ID integer,
FOREIGN KEY(USER_ID) REFERENCES USERS(USER_ID),
PURCHASED_ON VARCHAR(50));
CREATE table MOVIES_RENTED(RENTED_ID integer primary key,
USER_ID integer,
FOREIGN KEY(USER_ID) REFERENCES USERS(USER_ID),
RENTED_ON VARCHAR(50));
INSERT INTO USERS (USER_ID, USERNAME, FIRST_NAME, LAST_NAME, ISACTIVE, ISADMIN)
VALUES
(1, 'user1', 'user1FN', 'user1LN', '1', '0'),
(2, 'user2', 'user2FN', 'user2LN', '1', '0'),
(3, 'user3', 'user3FN', 'user3LN', '1', '0'),
(4, 'user4', 'user4FN', 'user4LN', '1', '0'),
(5, 'user5', 'user5FN', 'user5LN', '1', '0');
insert into MOVIES_RENTED (RENTED_ID, USER_ID, RENTED_ON)
values
(1, 5 ,'2014-07-05'),
(2, 4 ,'2014-07-05'),
(3, 5 ,'2014-07-05'),
(4, 4 ,'2014-07-05'),
(5, 5 ,'2014-07-05'),
(6, 5 ,'2014-07-05'),
(7, 3 ,'2014-07-05'),
(8, 2 ,'2014-07-05'),
(9, 2 ,'2014-07-05'),
(10, 1 ,'2014-07-05');
insert into MOVIES_PURCHASED (PURCHASE_ID, USER_ID, PURCHASED_ON)
values
(1, 1 ,'2014-07-05'),
(2, 3 ,'2014-07-05'),
(3, 3 ,'2014-07-05'),
(4, 3 ,'2014-07-05'),
(5, 4 ,'2014-07-05'),
(6, 4 ,'2014-07-05'),
(7, 5 ,'2014-07-05'),
(8, 5 ,'2014-07-05'),
(9, 1 ,'2014-07-05'),
(10, 2 ,'2014-07-05'),
(11, 2 ,'2014-07-05'),
(12, 2 ,'2014-07-05');
SELECT u.*
, SUM(x.source = 'rented') rented
, SUM(x.source = 'purchased') purchased
, COUNT(x.source) total
FROM users u
LEFT
JOIN
( SELECT 'rented' source, user_id FROM movies_rented
UNION ALL
SELECT 'purchased', user_id FROM movies_purchased
) x
ON x.user_id = u.user_id
GROUP
BY user_id
ORDER
BY total DESC;
USER_ID USERNAME FIRST_NAME LAST_NAME ISACTIVE ISADMIN RENTED PURCHASED TOTAL
5 user5 user5FN user5LN 1 0 4 2 6
2 user2 user2FN user2LN 1 0 2 3 5
4 user4 user4FN user4LN 1 0 2 2 4
3 user3 user3FN user3LN 1 0 1 3 4
1 user1 user1FN user1LN 1 0 1 2 3
http://sqlfiddle.com/#!2/8b3c8/10
A simple DISTINCT keyword for m.PURCHASE_ID and r.RENTED_ID solves the problem :
the query that worked is :
SELECT u.USER_ID,u.USERNAME,u.FIRST_NAME,u.LAST_NAME,u.ISACTIVE, u.ISADMIN, COUNT(DISTINCT m.PURCHASED_ID) AS MOVIES_PURCHASED, COUNT(DISTINCT r.RENTED_ID) AS MOVIES_RENTED,
(COUNT(DISTINCT m.PURCHASED_ID) + COUNT(DISTINCT r.RENTED_ID)) AS MAX_ACTIVITY
FROM TBL_USERS AS u
LEFT JOIN TBL_MOVIE_PURCHASED AS m
ON u.USER_ID = m.USER_ID
LEFT JOIN TBL_RENTED_MOVIES AS r
ON u.USER_ID = r.USER_ID
GROUP BY u.USER_ID,u.USERNAME,u.FIRST_NAME,u.LAST_NAME,u.ISACTIVE,u.ISADMIN
ORDER BY MAX_ACTIVITY DESC;
I added an extra MAX_ACTIVITY column and ordered the results by max_activity.
the link to an example for creating multiple tables, performing left joins on them, counting values for columns, ordering and grouping them and avoiding redundant data from being displayed while performing the joins :
http://sqlfiddle.com/#!2/7d44a2/2/0

Trying to group by a field with latest date in SQL where another field is equal

Hey I have run into a problem - I thought it would be easy with just group by but it was a little more when time is a factor in the game.
I'm trying to get all the records on different mainQuestion_id which can have duplicates with different timestamp (and id ofc). This should be filtered so I get those which are equal to an activationCode_id and not with a subquestion which is the field subQuestion_id
So lets say I have this table
CREATE TABLE surveys_answer
(`id` int, `activationCode_id` int, `mainQuestion_id` int, `subQuestion_id` int, `timestamp` int);
INSERT INTO surveys_answer
(`id`, `activationCode_id`, `mainQuestion_id`, `subQuestion_id`, `timestamp`)
VALUES
(1, 1, 4, 0, 201313),
(2, 1, 4, 0, 201314),
(3, 2, 3, 1, 201315),
(4, 2, 4, 0, 201316),
(5, 1, 9, 1, 201317),
(6, 1, 6, 0, 201318),
(7, 1, 4, 1, 201319);
and I want the results which are latest by time or id which have activationCode_id = 1 and where subQuestion_id = 0
what I want is
2, 1, 4, 0, 201314
6, 1, 6, 0, 201318
I have been trying with group by, that misses (2, 1, 4, 0, 201314) and takes the first one (1, 1, 4, 0, 201313) which is not what I want
I thought this would work:
SELECT * FROM surveys_answer
WHERE activationCode_id = 1
AND subQuestion_id = 0
group by mainQuestion_id
I have been trying to get this to work:
SELECT a.*
FROM surveys_answer a
INNER JOIN
(
SELECT max(id) xx, mainQuestion_id
FROM surveys_answer
GROUP BY mainQuestion_id
) b ON a.mainQuestion_id = b.mainQuestion_id AND
a.id = b.xx AND a.activationCode_id = '1' AND a.subQuestion_id = 0
But this gives me zero results
http://www.sqlfiddle.com/#!2/3e1cd
Can some one help me out with this?
SELECT sa.*
FROM surveys_answer sa
WHERE timestamp = (
SELECT MAX(sa2.timestamp)
FROM surveys_answer sa2
WHERE sa2.activationCode_id = 1 AND sa2.subQuestion_id = 0 AND
sa2.mainQuestion_id = sa.mainQuestion_id
);
SQL Fiddle
Result based on your sample data:
| ID | ACTIVATIONCODE_ID | MAINQUESTION_ID | SUBQUESTION_ID | TIMESTAMP |
|----|-------------------|-----------------|----------------|-----------|
| 2 | 1 | 4 | 0 | 201314 |
| 6 | 1 | 6 | 0 | 201318 |
may be you can try this
SELECT surveys_answer .* , max(timestamp) as mx_time FROM surveys_answer
WHERE activationCode_id = 1
AND subQuestion_id = 0
group by timestamp