Mysql multiple SELECT and Count query - mysql

Can you advice in whats the best way to combine multiple select and count into the one query
For example here are some queries that are from a test_table and work perfect on their own
SELECT name, count(*) AS 'Overall' FROM test_test WHERE country_prefix = '44' AND area_code = '203' GROUP BY `city_name`;
SELECT name, count(*) AS 'unallocated' FROM test_tab le WHERE country_prefix = '44' AND area_code = '203' AND removed != '1' AND destination-value = '1234' GROUP BY `city_name`;
There's a few more queries i'll be running but I think if I get two working together ill be able to do the rest
I was thinking something like this:
SELECT name, (SELECT count(*) FROM test_table WHERE country_prefix = '44' AND area_code = '203' GROUP BY `city_name') AS "Overall", (SELECT count(*) AS 'unallocated' FROM test_table WHERE country_prefix = '44' AND city_code = '203' AND removed != '1' AND destination-value = '1234' GROUP BY 'city_name')
But unfortunately doesn't work
Would the best way to do this be using sum case when, something like this:
sum(case when destination-value = '1234' then 1 else 0 end) AS unallocated

You can do it with conditional aggregation:
SELECT city_name,
COUNT(CASE WHEN country_prefix = '44' AND area_code = '203' THEN 1 END) AS Overall,
COUNT(CASE WHEN country_prefix = '44' AND area_code = '203' AND removed != '1' AND destination-value = '1234' THEN 1 END) AS unallocated
FROM tablename
GROUP BY city_name;
or since the 2 cases contain common conditions, these conditions can be moved to a WHERE clause:
SELECT city_name,
COUNT(*) AS Overall,
COUNT(CASE WHEN removed != '1' AND destination-value = '1234' THEN 1 END) AS unallocated
FROM tablename
WHERE country_prefix = '44' AND area_code = '203'
GROUP BY city_name;
In Mysql it's possible to simplify the code with the function SUM() instead of COUNT():
SELECT city_name,
COUNT(*) AS Overall,
SUM(removed != '1' AND destination-value = '1234') AS unallocated
FROM tablename
WHERE country_prefix = '44' AND area_code = '203'
GROUP BY city_name;

Related

How to show pivot data without directly using pivot statement?

I am trying to pivoting the data without directly using the pivot function.
I have a simple table t1 which has:
ID Employee Name
100 Amit
100 Rohan
101 Rohit
102 Pradnya
My expected output is:
100 101 103
2 1 1
I want to achieve this without using pivot. I tried using:
SELECT *
FROM (SELECT CASE
WHEN id = '101' THEN '101'
END,
CASE
WHEN id = '102' THEN '102'
END,
CASE
WHEN id = '103' THEN '103'
END,
Count(*) cnt
FROM t1
GROUP BY CASE
WHEN id = '101' THEN '101'
END,
CASE
WHEN id = '102' THEN '102'
END,
CASE
WHEN id = '102' THEN '102'
END);
How can I achieve the output without pivot?
You are sort of there, try the following:
with s as (
select id, Count(*) cnt
from t
group by id
)
select
max(case when id=100 then cnt end) as '100',
max(case when id=101 then cnt end) as '101',
max(case when id=102 then cnt end) as '102'
from s
See Example Fiddle

Combine single values from different select statements using mysql

I have two distinct queries which return single values and I would like to combine them into one single value. See below:
Query 1:
select sum(value)
from table.trans as transactions
where country= 'UK'
and transactions.from = 'Angela'
Query 2:
select sum(value)
from table.trans as transactions
where country= 'UK'
and transactions.to= 'Angela'
I now want to get:
Value from query 1 - Value from query 2
You can use conditional aggregation:
select sum(case when t.to = 'Angela' then value end) as to_value,
sum(case when t.from = 'Angela' then value end) as from_value
from table.trans t
where country = 'UK' and 'Angela' in (t.to, t.from);
For the difference:
select sum(case when t.to = 'Angela' then value
when t.from = 'Angela' then - value
end) as diff
from table.trans t
where country = 'UK' and 'Angela' in (t.to, t.from);
You can use IF as well
select SUM(if(transactions.from = 'Angela',ifnull(value,0),0)+ if(transactions.to = 'Angela',ifnull(-value,0),0)) diff
from table.trans as transactions
where country= 'UK'
and 'Angela' in (transactions.from,transactions.to)

Output of 3 queries

Got this 3 in 1 query:
SELECT * FROM
(
SELECT mesures.date j, AVG(mesures.valeur) maxi
FROM mesures
JOIN plages_horaire ON mesures.id_plage = plages_horaire.id_plage
WHERE MONTH(mesures.date) = '9' AND YEAR(mesures.date) = '2016' AND mesures.code_station = 'P02SE' AND mesures.id_crit = '1' AND mesures.id_type = '1'
GROUP BY mesures.date
) maxi
,
(
SELECT AVG(mesures.valeur) mini
FROM mesures
JOIN plages_horaire ON mesures.id_plage = plages_horaire.id_plage
WHERE MONTH(mesures.date) = '9' AND YEAR(mesures.date) = '2016' AND mesures.code_station = 'P02SE' AND mesures.id_crit = '1' AND mesures.id_type = '2'
GROUP BY mesures.date
) mini
,
(
SELECT AVG(mesures.valeur) moy
FROM mesures
JOIN plages_horaire ON mesures.id_plage = plages_horaire.id_plage
WHERE MONTH(mesures.date) = '9' AND YEAR(mesures.date) = '2016' AND mesures.code_station = 'P02SE' AND mesures.id_crit = '1' AND mesures.id_type = '3'
GROUP BY mesures.date
) moy
GROUP BY j
Problem is that I get what I want excepting values of the 2 last columns are the same at every rows:
query output
I believe it's because of the GROUP BY.
From what I can see from your query, you don't need the plage_horaire table. You can also simplify the logic greatly by using conditional aggregation:
SELECT m.date,
AVG(CASE WHEN m.id_type = 1 THEN m.valeur END) maxi,
AVG(CASE WHEN m.id_type = 2 THEN m.valeur END) mini,
AVG(CASE WHEN m.id_type = 3 THEN m.valeur END) maxmoy,
FROM mesures m
WHERE MONTH(m.date) = 9 AND YEAR(m.date) = 2016 AND
m.code_station = 'P02SE' AND m.id_crit = 1 AND m.id_type IN (1, 2, 3)
GROUP BY m.date ;
Notice that I also removed the quotes from the numeric constants. MONTH() and YEAR() return numbers, so quotes are not appropriate. I am guessing that the ids are numeric as well.

My two queries work separately but when I nest one inside of the other it no longer works

My first query is:
SELECT
SUM(CASE WHEN (Transactions.RegFunction = '1' AND Transactions.RegYear = "2017") THEN RegAmt END) AS GroupCurrsumFee,
SUM(CASE WHEN (Transactions.RegFunction = '1' AND Transactions.RegYear = "2017") THEN Transactions.LMSCAmt END) AS IndCurrsumFee
FROM AllTransactions
My second query is:
SELECT GroupAmt
FROM GroupFees
WHERE
'2016-11-01' BETWEEN BeginDate AND EndDate
AND RegYear = "2016"
AND GROUPID = "14"
AND RegFunction = 1;
When I run that query it returns the below:
| GroupAmt |
| 5.00 |
When I nest the second query inside of the first so that it can return that data in a column alias it does not show up. I have the two queries combined and written as the below:
SELECT
SUM(CASE WHEN (Transactions.RegFunction = '1' AND Transactions.RegYear = "2017") THEN RegAmt END) AS GroupCurrsumFee,
SUM(CASE WHEN (Transactions.RegFunction = '1' AND Transactions.RegYear = "2017") THEN Transactions.LMSCAmt END) AS IndCurrsumFee,
(SELECT GroupAmt FROM GroupFees
WHERE
'2016-11-01' BETWEEN BeginDate AND EndDate
AND RegYear = "2016"
AND GROUPID = "14"
AND RegFunction = 1) AS GroupFee
FROM AllTransactions
Use a join instead. Given the possibility that query might return NULL I suggest a left join with join condition that is always true. (Yes a bit "hacky".) Note, there is no guarantee that subquery returns just one row. If it does your overall result may not be what you are expecting.
SELECT SUM(CASE
WHEN (
Transactions.RegFunction = '1'
AND Transactions.RegYear = "2017"
)
THEN RegAmt
END) AS GroupCurrsumFee
, SUM(CASE
WHEN (
Transactions.RegFunction = '1'
AND Transactions.RegYear = "2017"
)
THEN Transactions.LMSCAmt
END) AS IndCurrsumFee
, GroupFee.GroupAmt
FROM AllTransactions
LEFT JOIN (
SELECT GroupAmt
FROM GroupFees
WHERE '2016-11-01' BETWEEN BeginDate
AND EndDate
AND RegYear = '2016'
AND GROUPID = '14'
AND RegFunction = 1
) AS GroupFee on 1=1

How can I select the rest of the row with DISTINCT?

I have a table where I keep messages and one where I keep users.
I want to get all the users that interactioned (send or received a message) with user_id 1.
This query works:
http://sqlfiddle.com/#!2/6a2f3/1
EDIT:
SELECT DISTINCT
(CASE WHEN `user_to_id` = 1 THEN `user_from_id` ELSE `user_to_id` END) `user_id`,
users.*
FROM `messages`
INNER JOIN users
ON (CASE WHEN `user_to_id` = 1 THEN `user_from_id` ELSE `user_to_id` END) = users.user_id
WHERE `user_to_id` = 1 OR `user_from_id` = 1
ORDER BY `time` DESC
But if I add to SELECT the message column, it returns duplicate records:
http://sqlfiddle.com/#!2/6a2f3/2
EDIT:
SELECT DISTINCT
(CASE WHEN `user_to_id` = 1 THEN `user_from_id` ELSE `user_to_id` END) `user_id`,
`messages`.`message`,
users.*
FROM `messages`
INNER JOIN users
ON (CASE WHEN `user_to_id` = 1 THEN `user_from_id` ELSE `user_to_id` END) = users.user_id
WHERE `user_to_id` = 1 OR `user_from_id` = 1
ORDER BY `time` DESC
How can I fix that?
And also, I see that it orders the results after the "DISTINCT" selection was made. The first query should return the results inverted because the row with message_id 2 has time 3.
Is there a way I can order them before the "DISTINCT"?
EDIT 2: I wasn't clear about the question. I want to select only the last message for a matched user_id.
Do you want something like this?
SELECT *
FROM (
SELECT
users.*,
(SELECT `message` from messages
WHERE
(CASE WHEN `user_to_id` = 1 THEN `user_from_id` ELSE `user_to_id` END) = users.user_id
AND (`user_to_id` = 1 OR `user_from_id` = 1)
ORDER BY `time` DESC limit 1
) AS message
FROM users
) a
WHERE message IS NOT NULL
SQL Fiddle
It's not returning duplicate records, you have two records with User_ID = 2.
I'm confused by what you want them to be ordered by. If you want to order them in the inverted order, just remove 'DESC'