same (sub)query multiple time in a mysql query - mysql

I have a mysql query like the following.
select new,processing,close
from
(select count(id) new from tickets where id_client in (_a_list_of_client_id) and status = new),
(select count(id) processing from tickets where id_client in (_a_list_of_client_id) and status = processing),
(select count(id) close from tickets where id_client in (_a_list_of_client_id) and status = close)
The following is not the exact query but a pseudo query
here _a_list_of_client_id is another query like following
select id_client from client where id_user = {some_id_given_as_parameter}
I just wondering is this the right approach to use same subquery multiple times in a query. Or is there any other way to do things like this.
Thanks in advance
M H Rasel

You can use sum with case and move the subquery to the where criteria:
select
sum(case when status = 'new' then 1 else 0 end) new,
sum(case when status = 'processing' then 1 else 0 end) processing,
sum(case when status = 'close' then 1 else 0 end) close
from tickets
where id_client in (_a_list_of_client_id)
There are a couple other ways to do this (using if for example or leaving out the case), but I think this is easy to read. I believe mysql will work with sum(status='new') for example.

Related

Mysql - most efficient way to retrieve data based on multiple selects and wheres

I'm having trouble finding the most efficient way of retrieving various different sumed values from a Mysql table.
Let's say I've got 4 columns - userid, amount, paid, referral.
I'd like to retrieve the following based on a user id:
1 - the sum of amount that is paid (marked as 1)
2 - the sum of amount that is unpaid (marked as 0)
3 - the sum of amount that is paid and referral (marked as 1 on both paid and referral columns)
4 - the sum of amount that unpaid and referral (marked as 0 on paid and 1 on referral columns)
I've tried an embedded select statement like this:
SELECT (
SELECT sum(payout)
FROM table1
WHERE ispaid = 0 and userid = '100'
) AS unpaid
(
SELECT sum(payout)
FROM table1
WHERE ispaid = 1 and userid = '100'
) AS paid,
(
SELECT sum(payout)
FROM table1
WHERE ispaid = 0 and isreferral = 1 and userid = '100'
) AS refpending,
(
SELECT sum(payout)
FROM table1
WHERE ispaid = 1 and isreferral = 1 and userid = '100'
) AS refpaid
This works, but its slow (or at least feels like it could be quicker) on my server, around 1.5 seconds.
I'm sure there is a better way of doing this with a group statement but can't get my head around it!
Any help is much appreciated.
Thanks
You can use conditional expressions inside SUM():
SELECT
SUM(CASE WHEN ispaid=0 THEN payout END) AS unpaid,
SUM(CASE WHEN ispaid=1 THEN payout END) AS paid,
SUM(CASE WHEN ispaid=0 AND isreferral=1 THEN payout END) AS refpending,
SUM(CASE WHEN ispaid=0 AND isreferral=1 THEN payout END) AS refpaid
FROM table1
WHERE userid = '100'
If a given row is not matched by any CASE...WHEN clause, then the value of the expression is NULL, and SUM() ignores NULLs. You could also have an ELSE 0 clause in there if you want to be more explicit, since SUM() will not be increased by a 0.
Also make sure you have an index on userid in this table to select only the rows you need.

How to use multiple COUNT in SQL

In my table I have task, every task have state.
1 - planned
2 - executing
3 - finished
I want get count of all planned, executing and finished task.
I can write three queries like this:
SELECT COUNT(*) FROM `task` WHERE state = 1
SELECT COUNT(*) FROM `task` WHERE state = 2
SELECT COUNT(*) FROM `task` WHERE state = 3
So, my question is: It is possible (and how?) get this data in one query?
Thank you for any help.
another approach is to use group by, like this:
select state, count(*)
from task
group by state
you use SUM
select state,
sum(case when state = 1 then 1 else 0 end) state1count,
sum(case when state = 2 then 1 else 0 end) state2count,
sum(case when state = 3 then 1 else 0 end) state3count
from task

Count DISTINCT on a single column over multiple conditions

I have a table, and I want to get the DISTINCT count of usernames over a certain period of time. Currently I'm running this query
SELECT DISTINCT username FROM user_activity WHERE company_id = 9 AND timestamp BETWEEN '2015-09-00' AND '2015-10-01' AND action = "Login Success";
It works great, however, I have multiple Companies that I want to select the count for. How do I expand the previous query to show me the distinct counts for multiple companies?
select count(distinct username),
sum(case when company_id = 1 then 1 else 0 end) A,
sum(case when company_id = 9 then 1 else 0 end) B
from `user_activity` Where timestamp BETWEEN '2015-09-00' AND '2015-10-01' AND action = "Login Success"
I've done something like this, however, I'm not getting the correct numbers. Ideally I would like to list each count as a different value for ease of reading, like the previous query illustrates. I don't need the count(distinct username) column to appear in my result, just the conditionals.
Thanks in advance.
If you don't mind two rows instead of two columns:
SELECT company_id, COUNT(DISTINCT username)
FROM user_activity
WHERE company_id IN (1,9)
AND timestamp >= '2015-09-01'
AND timestamp < '2015-09-01' + INTERVAL 1 MONTH
AND action = "Login Success"
GROUP BY company_id

Several select count(*) in a single query

I have a mysql table(tbl_subscriptiondetails) like the above.Here the last column i.e
'test_status' could have possible values C,S & Y only.
Using a single query i would like to fetch data in the manner
as shown below
But the query that i'm using gives me undesired results.My query is
SELECT pkg_name,
(SELECT COUNT(*) FROM tbl_subscriptiondetails WHERE test_status='C' AND mem_id=3) AS completed,
(SELECT COUNT(*) FROM tbl_subscriptiondetails WHERE test_status='S' AND mem_id=3) AS started,
(SELECT COUNT(*) FROM tbl_subscriptiondetails WHERE test_status='Y' AND mem_id=3) AS remaining
FROM tbl_subscriptiondetails
WHERE mem_id=3
GROUP BY pkg_name
and the result is
Please advise what is wrong. Thanks in advance.
You are running a subquery for each count, instead of counting as part of the main query. Therefore, your filter conditions aren't behaving as you expect them to. You can change it like so, to do the conditional count:
SELECT pkg_name,
SUM( case when test_status='C' then 1 else 0 end) AS completed,
SUM( case when test_status='S' then 1 else 0 end) AS started,
SUM( case when test_status='Y' then 1 else 0 end) AS remaining
FROM tbl
WHERE mem_id = 3
GROUP BY pkg_name
Demo

MySQL - Perform checks on groupings of records

I have a result set like this:
"id","reference_id","type"
"1","aaa","A"
"2","aab","M"
"3","aac","A"
"4","aaa","M"
"5","aaa","E"
"6","aab","M"
"7","aac","M"
"8","aab","D"
"9","aac","M"
I want to run some validations on it using sql.
Each reference_id life cycle must contain only one "A";
Each reference_id life cycle must conatin at least 1 "E" and/or 1 "D";
How can I iterate through a resultset and perform checks per group of records (reference_id).
(Updated) Try:
select r.*
from my_result_set r
join (select reference_id
from my_result_set
group by reference_id
having sum(case type when 'A' then 1 end) = 1 and
sum(case when type in ('D','E') then 1 end) >= 1) s
on r.reference_id = s.reference_id
SQLFiddle here.