Counting rows matching each of the multiple conditions in MySQL - mysql

Please help me figure a single query that will transform the data below...
|id |status_a |status_b |
|+++++++++++++++++++++++|
| 1|active |inactive |
...into this one.
|status_group |count|
|++++++++++++++++++++++++|
|status_a.active | 1|
|status_b.inactive | 1|
edit: If a single pass query is possible then that will be better. Also, does a query with unions does a single pass?

If status can be either only active or inactive, I'd suggest a different approach:
SELECT
sum(if(status_a='active',1,0)) AS status_a_active,
sum(if(status_a='inactive',1,0)) AS status_a_inactive,
sum(if(status_b='active',1,0)) AS status_b_active,
sum(if(status_b='inactive',1,0)) AS status_b_inactive
FROM table
Otherwise you need to use the UNION approach, but I'd do it a little differently. First, you can use UNION ALL, because you don't need to remove duplicates in the result. I'd also use GROUP BY only once like this:
SELECT status_group, count(id)
FROM (
SELECT CONCAT('status_a.', status_a) AS status_group, id FROM table
UNION ALL
SELECT CONCAT('status_b.', status_b) AS status_group, id FROM table
) a
GROUP BY status_group

I have a solution that uses UNIONs. Shown here:
SELECT 'status_a.active' AS status_group, COUNT(*) AS count FROM `test` WHERE status_a = 'active'
UNION
SELECT 'status_a.inactive' AS status_group, COUNT(*) AS count FROM `test` WHERE status_a = 'inactive'
UNION
SELECT 'status_b.active' AS status_group, COUNT(*) AS count FROM `test` WHERE status_b = 'active'
UNION
SELECT 'status_b.inactive' AS status_group, COUNT(*) AS count FROM `test` WHERE status_b = 'inactive'
Basically, it queries each condition for status_a or status_b being active or not. We get four such queries and we apply UNION to all of them.

I suppose, I've to move my comment a while ago which is also a shorter solution here than hw's.
SELECT CONCAT('status_a.', status_a) AS stat, COUNT(id) FROM base GROUP BY stat
UNION
SELECT CONCAT('status_b.', status_b) AS stat, COUNT(id) FROM base GROUP BY stat

Related

how to use mysql "count" and "group by" to include 0 counts?

I'm rookie with sql. I have the following table:
task_name
status
task_01
done
task_02
failed
task_03
done
task_04
done
task_05
failed
task_06
done
task_07
failed
task_08
failed
task_09
failed
task_10
done
task_11
done
task_12
failed
task_13
done
task_14
done
I know that another option for "status" column is "pending", but for now, no row has that status.
So, I want to obtain the count of the status, including the result "pending" to be counted as "0".
I am running:
SELECT status,count(*) FROM test.data where status in ("done","failed","pending") group by status;
And the result is:
status
count(*)
done
8
failed
6
But the desired output is:
status
count(*)
done
8
failed
6
pending
0
How can I make a query to obtain that result?
Note 1: I can't create another table (like a status_label table)
Note 2: sorry for my english, my native language is spanish
Try this:
WITH
-- your input ...
indata(task,status) AS (
SELECT 'task_01','done'
UNION ALL SELECT 'task_02','failed'
UNION ALL SELECT 'task_03','done'
UNION ALL SELECT 'task_04','done'
UNION ALL SELECT 'task_05','failed'
UNION ALL SELECT 'task_06','done'
UNION ALL SELECT 'task_07','failed'
UNION ALL SELECT 'task_08','failed'
UNION ALL SELECT 'task_09','failed'
UNION ALL SELECT 'task_10','done'
UNION ALL SELECT 'task_11','done'
UNION ALL SELECT 'task_12','failed'
UNION ALL SELECT 'task_13','done'
UNION ALL SELECT 'task_14','done'
)
,
-- add an in-line three row table with the three statuses
status(status) AS (
SELECT 'done'
UNION ALL SELECT 'failed'
UNION ALL SELECT 'pending'
)
-- left join your in-line table with the base table
-- and count the base table's statuses
SELECT
status.status
, COALESCE(count(indata.status),0) AS statuscount
FROM status
LEFT JOIN indata USING(status)
GROUP BY status.status;
status | statuscount
---------+-------------
pending | 0
failed | 6
done | 8
The simplest way is a UNION query.
SELECT status,count(*) FROM test.data group by status;
UNION
SELECT 'pending', 0
UNION allows you to combine the output of two identical queries, and even manufacture fake output for a query.
Note: This isn't a robust solution that would be used as a general solution as hard-coding results should be frowned upon, it is the simplest answer to your specific question.

Query for selecting duplicates + finding lowest value

I have 3 tables in 3 different databaes; Currently the goal here is to find the duplicates unique ID in the three databases and then find the lowest price value of the duplicates unique ID.
Currently I'm using a INNER JOIN to query between only 2 database... Can anyone advise on how to add the third one?
set #a = (SELECT db1.tb1.var1 from db1.tb1
INNER JOIN db2.tb1 ON db2.tb1.var1 = db1.tb1.var1
UNION );
Also, once I have the #a variable set to the duplicate, I wanted to grab a secondary value here.
SELECT price
FROM db1.tb1
WHERE asin=#a
UNION ALL
SELECT price
FROM db2.tb1
WHERE asin=#a
UNION ALL
SELECT price
FROM db3.tb1
WHERE asin=#a
However, the result I'd get would return multiple rows (obviously), How do I query only for the MIN() number from this ?
Any help is appreciated.
Thanks,
Put your query into a subquery, and then use MIN() in the main query.
SELECT MIN(price)
FROM (
SELECT price
FROM db1.tb1
WHERE asin=#a
UNION ALL
SELECT price
FROM db2.tb1
WHERE asin=#a
UNION ALL
SELECT price
FROM db3.tb1
WHERE asin=#a) AS x
You can use order by and limit:
SELECT price
FROM db1.tb1
WHERE asin = #a
UNION ALL
SELECT price
FROM db2.tb1
WHERE asin = #a
UNION ALL
SELECT price
FROM db3.tb1
WHERE asin = #a
ORDER BY price
LIMIT 1;

How to create multiple rows from a initial row

I use mysql db engine, I wonder is it possible that the data in the table one row transferred to another table, this table would consist of two columns, id and value
each of the transferred value would go into one row and row would look like ID, value, and for as long as it has a value that is transferred to new row maintains the id as long as it has a value that belonged to the id of a row from which it transferred
Initial table looks like
id |country_name |city_1 |city_2 |city_3 |city_4
------------------------------------------------------------------------
1 |Some_country |some_city1 |some_city2 |some_city3 |some_city4
Wanted table looks like
id | city_name
1 | some_city1
1 | some_city2
1 | some_city3
1 | some_city4
Use this for one particular ID
select id, city_name from(
select id, city_1 as city_name from yourTable
union all
select id, city_2 from yourTable
union all
select id, city_3 from yourTable
union all
select id, city_4 from yourTable
) as t where id= yourID
http://sqlfiddle.com/#!9/7ee1f/1
Use this for whole table
select id, city_name from(
select id, city_1 as city_name from yourTable
union all
select id, city_2 from yourTable
union all
select id, city_3 from yourTable
union all
select id, city_4 from yourTable
) as t
order by id
What you are looking for is often referred to as vertical pivoting: you want to pivot something like an array of four city names - hard-wired into the table definition - into four vertical rows.
The solution is a cross join with a temporary table with as many consecutive integers, starting from 1, as you have columns to pivot, in conjunction with a CASE-WHEN expression that makes use of that series of integers.
See here:
WITH foo(id,country_name,city_1,city_2,city_3,city_4) AS (
SELECT 1,'Some_country','some_city1','some_city2','some_city3','some_city4'
)
, four_indexes(idx) AS (
SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
)
SELECT
id AS country_id
, idx AS city_id
, CASE idx
WHEN 1 THEN city_1
WHEN 2 THEN city_2
WHEN 3 THEN city_3
WHEN 4 THEN city_4
ELSE ''
END AS city_name
FROM foo CROSS JOIN four_indexes
;
country_id|city_id|city_name
1| 1|some_city1
1| 3|some_city3
1| 2|some_city2
1| 4|some_city4
Only the other day, I answered a question that was looking for reversing the operation we are performing here: horizontal pivoting.
See here if you're curious ...
How to go about a column with different values in a same row in sql?
Happy Playing -
Marco the Sane

Mysql how to sum and display as single row

I have a vote mysql table and users (user column) can vote y or n. (option column)
My table structure is like below:
| id | option | user | 
| 1 | y | jack | 
| 2 | n | jack | 
| 3 | n | michi| 
| 4 | n | michi| 
What I would like to do is, select distinct user and count option and display it in a single row like below:
| y | n |
| 1 | 2 |
I tried GROUP_CONCAT() and SUM but without luck. Can you please help me to get this sql working?
Thanks.
Group functions like GROUP_CONCAT(), SUM() and COUNT() need a GROUP BY statement to know which rows to combine.
In your query, you want to use COUNT().
Try this:
SELECT `option`, COUNT(DISTINCT `user`) AS users
FROM `table`
GROUP BY `option`
DEMO: http://sqlfiddle.com/#!9/705a9d/3
This will show you one row per option. If you want both options across one row, that's a bit trickier. You'll need to use subqueries for each option.
SELECT (
SELECT COUNT(DISTINCT `user`)
FROM `table`
WHERE `option` = 'y'
) AS y, (
SELECT COUNT(DISTINCT `user`)
FROM `table`
WHERE `option` = 'n'
) AS n
DEMO: http://sqlfiddle.com/#!9/705a9d/4
NOTE: You can use COUNT() without GROUP BY. That will make the query combine all found rows together.

MySQL: Counting column from different tables on a certain timeframe

I have the following query:
SELECT SUM(COUNTED) AS TCOUNTED
FROM (SELECT COUNTED FROM `clicks`.`t1`
UNION ALL
SELECT COUNTED FROM `clicks`.`t2`
UNION ALL
SELECT COUNTED FROM `clicks`.`t3`
) AS TMP
Where and how do I add a time constraint? I want it to count only between certain dates... Sorry for the MySQL noobness.
Thanks!
SELECT SUM(COUNTED) AS TCOUNTED
FROM (SELECT COUNTED FROM `clicks`.`t1` WHERE somedatecol BETWEEN somedate AND somedate
UNION ALL
SELECT COUNTED FROM `clicks`.`t2` WHERE somedatecol BETWEEN somedate AND somedate
UNION ALL
SELECT COUNTED FROM `clicks`.`t3` WHERE somedatecol BETWEEN somedate AND somedate
) AS TMP`
http://dev.mysql.com/doc/refman/5.0/en/select.html
I would think your best bet is to include the where clause inside each sub-select before the UNION statements.
SELECT SUM(COUNTED) AS TCOUNTED FROM
(SELECT COUNTED FROM clicks.t1 WHERE <fieldname> BETWEEN '<date1>' AND '<date2>'
UNION ALL
SELECT COUNTED FROM clicks.t2 WHERE <fieldname> BETWEEN '<date1>' AND '<date2>'
UNION ALL
SELECT COUNTED FROM clicks.t3 WHERE <fieldname> BETWEEN '<date1>' AND '<date2>')
AS TMP;
Of course it as all relative to what you are trying to accomplish with the query.