Query with multiple subqueries required in Mysql - mysql

I am looking for some query help
here is the following table data
Name Runs Status
Ram 50 out
Ram 103 not out
Krish 51 out
Sam 15 out
Ram 15 out
Krish 78 not out
I am expecting a single query to give the folllowing results
Name Total >100 >50&<100 TotalTimes Notout
Ram 168 1 1 3 1
Sam 15 0 0 1 0
Krish 129 0 2 2 1
I am able to write the query to get the total, Totaltimes with the help of Group By functionalities, I am stuck with the rest
Here is the query I have come up
select Name, sum(Runs) as total, count(*) as totalTimes
from tempTable
where classID IN (Select classID from upcoming_Clases where classes_id=175)
group by Name order by total desc
I am using the Mysql Database

You can do this using case:
select Name,
sum(Runs) as total,
count(case when Runs>100 then 1 end) `>100`,
count(case when Runs>50 and Runs<100 then 1 end) `>50&<100`,
count(*) as totalTimes,
count(case when Status='not out' then 1 end) `Not Out`
from tempTable
where classID IN (Select classID from upcoming_Clases where classes_id=175)
group by Name order by total desc

You can use SUM() together with IF() to test your criteria:
SELECT
Name,
SUM(Runs) AS Total,
SUM(IF(Runs>100, 1, 0)) AS `>100`,
SUM(IF(Runs>50 AND Runs<100), 1, 0) AS `>50&<100`,
COUNT(*) AS TotalTimes,
SUM(IF(Status='not out', 1, 0)) AS Notout
FROM tempTable
WHERE classID IN (SELECT classID FROM upcoming_Clases WHERE classes_id = 175)
GROUP BY Name
ORDER BY Total DESC

Related

SQL query to find the repetitions of data

I've a sample data
id date user_id customer_id status
1 2022-06-23 1 12 no response
2 2022-06-23 1 12 no response
3 2022-06-24 1 12 no response
4 2022-06-23 2 15 no response
4 2022-06-23 2 15 successful
5 2022-06-23 3 16 call later
I need to fetch those kind of records where a user_id called the same customer_id on the same day got only no response status more than once but not any other statuses.
The result for the above example would be
id
1
2
You can use aggregation and the conditions in the HAVING clause:
SELECT user_id, customer_id, date
FROM tablename
GROUP BY user_id, customer_id, date
HAVING COUNT(*) > 1 AND SUM(status <> 'no response') = 0
If you want the respective rows of the table use the above query with the operator IN:
SELECT *
FROM tablename
WHERE (user_id, customer_id, date) IN (
SELECT user_id, customer_id, date
FROM tablename
GROUP BY user_id, customer_id, date
HAVING COUNT(*) > 1 AND SUM(status <> 'no response') = 0
);
See the demo.

Mysql select unique columns from where clause

I'm trying to see if it's possible to have several unique columns in a select statement from varying where clause selections. Here is my query.
select org_id, count(org_role) as total
from organization
where org_id = 10 and org_role = 9
group by org_id;
the above works perfectly. It produces:
org_id total
10 19
Id'd like to add another column count named total2 where org_id = 10 and org_role = 7 (the count is 23). So i'd have this result:
org_id total total2
10 19 23
I'm just not sure how to edit the original above query to produce that. Any thoughts would be appreciated.
You can use conditional aggregation. For example:
select
org_id,
sum(case when org_role = 9 then 1 else 0 end) as total,
sum(case when org_role = 7 then 1 else 0 end) as total2
from organization
where org_id = 10 and org_role in (7, 9)
group by org_id;
select org_id, count(org_role) as total, count(total_2)
from organization
where org_id = 10 and org_role = 9
group by org_id;
If it does not work please send your database structure.

MySQL show proportion

I am trying to show a proportion of customers that signed up because he/she was being referred by other customers and customers with no referral. So far I only able to show it as numerical but I wanted to show it in percentage. Null is when the customer signs up without being referred.
The original data as follows:
CustomerID ReferralID
1000004 1000003
1000015 1000010
1000007 1000004
1000011 Null
1000026 1000004
The query that I have and return data as follows:
select customerID, COUNT(*) as proportion
from company123.customertable
group by (customerID)
order by customerID asc;
CustomerID proportion
1000004 1
1000015 1
1000007 1
1000011 1
1000026 1
Expected result
CustomerID referred non-referred
1000004 1 0
1000015 1 0
1000007 1 0
1000011 0 1
1000026 1 0
Any suggestion to show it as a percentage? Thank you in advance
Use aggregate function AVG():
select avg(ReferralID is not null) referred,
avg(ReferralID is null) non_referred
from customertable
See the demo.
Results:
> referred | non_referred
> -------: | -----------:
> 0.8000 | 0.2000
you can use an aggregate function on a case statement like this
SELECT
COUNT(*) customers,
SUM(CASE WHEN referral_id IS NOT NULL THEN 1 ELSE 0 END) / COUNT(*) AS referred,
SUM(CASE WHEN referral_id IS NULL THEN 1 ELSE 0 END) / COUNT(*) AS non_referred
FROM company123.customertable
should give you something like this (numbers are made up)
customers referred non_referred
12301 0.7128 0.2872
Here's one way which will give a percentage to 2 decimal places:
EDIT: Added % sign to output using CONCAT
SELECT customerid,
CONCAT(CAST(COUNT(ReferralID) * 100.0 / Count(*) as decimal(9,2)),'%') AS proportion
FROM company123.customertable
GROUP BY customerid
ORDER BY customerid ASC;

How to add a null value in the group_concat if the record does not exist?

I have this SQL query with substring_index and group_concat but the results I get does not give the right location of the values because the values does not exist.
I need to add a null or zero value in order to have the right location of the values in the sql result.
In the table there are three lid (1, 2, 3). The lid should be the basis count of the P's (P1, P2, P3) for the substring_index.
This is the table:
lid class_id class total
----- ------- ----- -----
1 73 Leader 10000
1 77 Consultant 8000
1 83 Coordinator 6000
2 73 Leader 20000
2 76 Staff 8000
2 77 Consultant 10000
3 73 Leader 30000
3 78 Team Leader 8000
This is the SQL query I used to group_concat for the totals and substring_index to separate the grouped values with their each column (P1, P2, P3)
SELECT *, GROUP_CONCAT(lid) as lids, GROUP_CONCAT(pyear) as pyears,
COUNT(DISTINCT lib_id) AS total_count,
CASE WHEN COUNT(*)>=1 THEN SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(if(total is null,0,total) ORDER BY lid ASC SEPARATOR ' '),' ',1),' ',-1) END AS P1,
CASE WHEN COUNT(*)>=2 THEN SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(if(total is null,0,total) ORDER BY lid ASC SEPARATOR ' '),' ',2),' ',-1) END AS P2,
CASE WHEN COUNT(*)>=3 THEN SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(if(total is null,0,total) ORDER BY lid ASC SEPARATOR ' '),' ',3),' ',-1) END AS P3
FROM (
SELECT * FROM view_items WHERE lid='1'
UNION
SELECT * FROM view_items WHERE lid='2'
UNION
SELECT * FROM view_items WHERE lid='3'
) AS AZ GROUP BY class_id
This is the result of the above query:
class id class lids P1 P2 P3
--------- ----- ----- ---- ---- ----
73 Leader 1,2,3 10000 20000 30000
76 Staff 2 8000
77 Consultant 1,2 8000 10000
78 Team Leader 3 8000
83 Coordinator 1 6000
The lids should always have three count even though the record does not exists, a zero or null value should be added. How to do the adding of null value?
This is the expected result I need.
class id class lids P1 P2 P3
--------- ----- ----- ---- ---- ----
73 Leader 1,2,3 10000 20000 30000
76 Staff 0,2,0 0 8000 0
77 Consultant 1,2,0 8000 10000 0
78 Team Leader 0,0,3 0 0 8000
83 Coordinator 1,0,0 6000 0 0
To get 0 values where no lid is present in the table, you need to generate a list of all lid values for all class_id values, which you can do with a CROSS JOIN of two SELECT DISTINCT queries (one for lid, one for class_id). This can then be LEFT JOINed to the table, to get the required total value for each P group using conditional aggregation:
SELECT c.class_id,
MAX(v.class),
GROUP_CONCAT(COALESCE(v.lid, 0) ORDER BY l.lid) AS lids,
MAX(CASE WHEN v.lid=1 THEN total ELSE 0 END) AS P1,
MAX(CASE WHEN v.lid=2 THEN total ELSE 0 END) AS P2,
MAX(CASE WHEN v.lid=3 THEN total ELSE 0 END) AS P3
FROM (SELECT DISTINCT lid FROM view_items) l
CROSS JOIN (SELECT DISTINCT class_id FROM view_items) c
LEFT JOIN view_items v ON v.lid = l.lid AND v.class_id = c.class_id
GROUP BY c.class_id
Output:
class_id class lids P1 P2 P3
73 Leader 1,2,3 10000 20000 30000
76 Staff 0,2,0 0 8000 0
77 Consultant 1,2,0 8000 10000 0
78 Team Leader 0,0,3 0 0 8000
83 Coordinator 1,0,0 6000 0 0
Demo on dbfiddle
Use else 0 in case expression
SELECT *, GROUP_CONCAT(lid) as lids, GROUP_CONCAT(pyear) as pyears,
COUNT(DISTINCT lib_id) AS total_count,
CASE WHEN COUNT(*)>=1 THEN SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(if(total is null,0,total) ORDER BY lid ASC SEPARATOR ' '),' ',1),' ',-1) else 0 END AS P1,
CASE WHEN COUNT(*)>=2 THEN SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(if(total is null,0,total) ORDER BY lid ASC SEPARATOR ' '),' ',2),' ',-1) else 0 END AS P2,
CASE WHEN COUNT(*)>=3 THEN SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(if(total is null,0,total) ORDER BY lid ASC SEPARATOR ' '),' ',3),' ',-1) else 0 END AS P3
FROM (
SELECT * FROM view_items WHERE lid='1'
UNION
SELECT * FROM view_items WHERE lid='2'
UNION
SELECT * FROM view_items WHERE lid='3'
) AS AZ GROUP BY class_id
I think the problem is, that you say count >= 1, but count >= 3 is also count >=1 so your code never reaches this line. You have to say,
CASE WHEN COUNT() >=1 AND COUNT () < 2...
CASE WHEN COUNT() >=2 AND COUNT () < 3...
I don't think GROUP_CONCAT() is the right approach for what you want. Try this:
SELECT vi.class_id, vi.class,
COUNT(DISTINCT vi.lib_id) AS total_count,
CONCAT_WS(',',
MAX(CASE WHEN vi.lid = 1 THEN 1 ELSE 0 END),
MAX(CASE WHEN vi.lid = 2 THEN 1 ELSE 0 END),
MAX(CASE WHEN vi.lid = 3 THEN 1 ELSE 0 END)
) as lids,
SUM(CASE WHEN vi.lid = 1 THEN vi.total ELSE 0 END) as total_1,
SUM(CASE WHEN vi.lid = 2 THEN vi.total ELSE 0 END) as total_2,
SUM(CASE WHEN vi.lid = 3 THEN vi.total ELSE 0 END) as total_3
FROM view_items vi
WHERE vi.lid IN (1, 2, 3)
GROUP BY vi.class_id;
Notes:
Your subquery and UNION are not needed. In MySQL, these can actually hurt performance.
I assume that lid is a number, so I've removed the single quotes.
You can use conditional aggregation for each of the totals that you want. Parsing GROUP_CONCAT() is not the right way to do this.
Your question is about the lids. The CONCAT_WS() does what you want -- concatenating either the value (if it appears) or zero if it does not.

Count Totals by Day of Week and Week Total for each Subject

In my table I have recorded various bits of information but the key fields for this problem are the subject_id and lesson_time where I want to group by subject to give a total count of rows for each day of week for each subject and total rows for each subject(weekly total), so from this sample data:
id subject_id lesson_time
1 4 2015-04-28
2 4 2015-04-28
3 3 2015-04-28
4 1 2015-04-28
5 4 2015-04-27
I want to count the totals for each subject for monday to friday and week total, so output for the above data example would be:
subject_id monday_total tuesday_total wednesday_total ... week_total
1 0 1 0 1
3 0 1 0 1
4 1 2 0 3
I can get total by subject easy enough as it is just count(*) after group by, what I am struggling with is the count for each individual day, my current (non working) query is
SELECT
subject_id,
COUNT( DAYOFWEEK(lesson_time)=2) AS monday_total,
COUNT( DAYOFWEEK(lesson_time)=3) AS tuesday_total,
COUNT( DAYOFWEEK(lesson_time)=4) AS wednesday_total,
COUNT( DAYOFWEEK(lesson_time)=5) AS thursday_total,
COUNT( DAYOFWEEK(lesson_time)=6) AS friday_total,
COUNT(*) AS week_total
FROM
tbl_lessons
GROUP BY
subject_id
Any help would be much appreciated.
try this
SELECT
subject_id,
SUM(DAYOFWEEK(lesson_time)=2) AS monday_total,
SUM(DAYOFWEEK(lesson_time)=3) AS tuesday_total,
SUM(DAYOFWEEK(lesson_time)=4) AS wednesday_total,
SUM(DAYOFWEEK(lesson_time)=5) AS thursday_total,
SUM(DAYOFWEEK(lesson_time)=6) AS friday_total,
COUNT(*) AS week_total
FROM
tbl_lessons
GROUP BY
subject_id
In mysql COUNT(n) counts every row (+ 1 for every row where n is not NULL). SUM(n) sums all n values (+ n for every row).
As boolean expression returns 1 or 0 SUM(DAYOFWEEK(lesson_time)=2) will return number of rows where DAYOFWEEK(lesson_time)=2 (it's like summing booleans 1+0+0+1+1+1+0+0+1+...)
SELECT date(lesson_time) AS lesson_time, count( * ) AS count FROM tbl_lessons GROUP BY date(lesson_time)