MySQL: Select multiple max values from one column - mysql

Suppose I got this table:
mytable
+------+-------+
| type | count |
+------+-------+
| red | 4 |
| blue | 3 |
| red | 2 |
| blue | 7 |
+------+-------+
Now I want this back:
+--------+---------+
| maxRed | maxBlue |
+--------+---------+
| 4 | 7 |
+--------+---------+
How can I do this?
This is what I tried
SELECT MAX(count) as maxRed, 0 as maxBlue FROM mytable WHERE type='red'
UNION
SELECT 0 as maxRed, MAX(count) as maxBlue FROM mytable WHERE type='blue'
but it does not quite work and only results
+--------+---------+
| maxRed | maxBlue |
+--------+---------+
| 4 | 0 |
| 0 | 7 |
+--------+---------+

For your query to work you only needed to wrap it with another query:
SELECT MAX(maxRed) as maxRed, MAX(maxBlue) as maxBlue
FROM(
SELECT MAX(count) as maxRed, 0 as maxBlue FROM mytable WHERE type='red'
UNION
SELECT 0 as maxRed, MAX(count) as maxBlue FROM mytable WHERE type='blue') t
A more elegant way is conditional aggregation:
SELECT MAX(CASE WHEN t.type = 'red' THEN t.count END) as maxRed,
MAX(CASE WHEN t.type = 'blue' THEN t.count END) as maxBlue
FROM mytable t
WHERE t.type IN('blue','red')

This is how to do it:
SELECT
MAX(CASE WHEN type = 'red' THEN `count` ELSE NULL END) AS maxRed,
MAX(CASE WHEN type = 'blue' THEN `count` ELSE NULL END) AS maxBlue
FROM
mytable
WHERE type IN ('red', 'blue');

SELECT type,MAX(count) FROM mytable group by type
This will return type and maxcount in vertical and not horizontal and is scalable for n number of records.
If horizontal data doesn't matter otherwise you can use above suggested answers to use case but it will require case when then for each distinct value of data.

EDIT
Because of the comments below I tested it on real data, my version is a bit faster for a large table ,when mytable is indexed. For those who argue about it please test yourself and report back.
select
(select max(count) from mytable WHERE type='red') aa,
(select max(count) from mytable WHERE type='blue') bb

Related

How to convert rows to columns?

I've the following query:
SELECT first_period, period, sum(num) trans_num
FROM (SELECT (DATEDIFF(created_at, '2022-12-10') DIV 6) period,
user_id,
count(1) num,
MIN(MIN(DATEDIFF(created_at, '2022-12-10') DIV 6)) OVER (PARTITION BY user_id) as first_period
FROM pos_transactions
WHERE DATE(created_at) >= '2022-12-10'
GROUP BY user_id, DATEDIFF(created_at, '2022-12-10') DIV 6
) u
GROUP BY first_period, period
ORDER BY first_period, period
It returns the following result:
But now I need to make it visualize like a Cohort diagram. So I need to restructure the same result as follows:
+--------------+------+------+------+------+
| first_period | 0 | 1 | 2 | 3 |
+--------------+------+------+------+------+
| 0 | 6230 | 2469 | 2846 | 1713 |
| 1 | | 2589 | 742 | 375 |
| 2 | | | 3034 | 397 |
| 3 | | | | 1207 |
+--------------+------+------+------+------+
Any idea how can I do that?
WITH YOUR_TABLE_DATA(FIRST_PERIOD,PERIOD,TRANS_NUM)AS
(
SELECT 0,0,6230 UNION ALL
SELECT 0,1,2469 UNION ALL
SELECT 0,2,2846 UNION ALL
SELECT 0,3,1713 UNION ALL
SELECT 1,1,2589 UNION ALL
SELECT 1,2,742 UNION ALL
SELECT 1,3,375 UNION ALL
SELECT 2,2,3034 UNION ALL
SELECT 2,3,397 UNION ALL
SELECT 3,3,1207
)
SELECT C.FIRST_PERIOD,
MAX(
CASE
WHEN C.PERIOD=0
THEN C.TRANS_NUM
ELSE 0
END)AS ZERO,
MAX(
CASE
WHEN C.PERIOD=1
THEN C.TRANS_NUM
ELSE 0
END)AS ONE,
MAX(
CASE
WHEN C.PERIOD=2
THEN C.TRANS_NUM
ELSE 0
END)AS TWO,
MAX(
CASE
WHEN C.PERIOD=3
THEN C.TRANS_NUM
ELSE 0
END)AS THREE
FROM YOUR_TABLE_DATA AS C
GROUP BY C.FIRST_PERIOD

Select group multiple records by specific condition

I have table:
+----+-------+-------------+
| id | code | value_check |
| 1 | p-01 | OK |
| 2 | p-01 | NOT OK |
| 3 | p-01 | OK |
| 4 | p-02 | OK |
| 5 | p-02 | OK |
| 6 | p-02 | OK |
+----+-------+-------------+
How can I select record which having 'OK' group by code,but if there is one or more 'NOT OK' on value_check then don't need to select
expected result:
code
p-02
i have tried my query can get the result but its very slow
this is my query :
SELECT code FROM table
WHERE code
NOT IN (SELECT code FROM table
WHERE value_check = 'NOT OK' GROUP BY code)
GROUP BY code
any other solution?
Check whether the total count is equal to the count of rows having value as OK using HAVING clause.
Query
select `code` from `your_table_name`
group by `code`
having count(*) = sum(`value_check` = 'OK');
Find a demo here
Try below with conditional aggregation
select code from table
group by code
having sum(case when value_check='NOT OK' then 1 else 0 end)=0
You can try it also with correlated subquery:
demo
SELECT distinct code FROM cte1 a
WHERE NOT exists (SELECT 1 FROM cte1 b where a.code=b.code and val = 'NOT OK')
SELECT DISTINCT x.code
FROM my_table x
LEFT
JOIN my_table y
ON y.code = x.code
AND y.value_check = 'not ok'
WHERE x.value_check = 'ok'
AND y.id IS NULL

MySQL Select all values from 1st column that have specific value in 2nd column

I have a mysql table with 2 columns.
+---------+-----------+
| Barcode | StationID |
+---------+-----------+
| 89411 | 1 |
| 89411 | 2 |
| 89411 | 3 |
| 89412 | 1 |
| 89413 | 1 |
+---------+-----------+
I would like to select all valus from Barcode column which have StationID = 1 and do NOT have a StationID different than 1.
As shown in the picture Barcode 89411 appears three times with different StationID and should be excluded from the result.
Can you help me make a query?
Another approach is to use an EXISTS query:
SELECT t1.*
FROM yourTable t1
WHERE
t1.StationID = 1 AND
NOT EXISTS (SELECT 1 FROM yourTable t2
WHERE t1.Barcode = t2.Barcode AND t2.StationID <> 1);
Demo
Use aggregation function GROUP_CONCAT, and use HAVING clause to filter out those barcodes, which has only one StationID, that is '1':
SELECT barcode, GROUP_CONCAT(DISTINCT StationID) AS stations
FROM table_name
GROUP BY barcode
HAVING stations = '1';
Try this: https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=641d334c5f9e57bbdde07e4f24365f88
select barcode from tablename
group by barcode
having sum(case when sanctionid=1 then 0 else 1 end)=0
output:
barcode
89412
89413

combining multiple different sql into one

cusID | Name | status | Date
---------------------------------
1 | AA | 0 | 2013-01-25
2 | BB | 1 | 2013-01-23
3 | CC | 1 | 2013-01-20
SELECT COUNT(cusID) FROM customer WHERE STATUS=0;
SELECT COUNT(cusID) FROM customer WHERE STATUS=1;
Is there a way of combing such two sql and return the results as one. Because want to avoid calling to DB everytime. I tried UNION of two statments, but only showing one result.
This is the shortest possible solution in MySQL.
SELECT SUM(status = 1) totalActive,
SUM(status = 0) totalInactive
FROM tableName
SQLFiddle Demo
and this is the CASE version
SELECT SUM(CASE WHEN status = 1 THEN 1 ELSE 0 END) totalActive,
SUM(CASE WHEN status = 0 THEN 1 ELSE 0 END) totalInactive
FROM tableName
SQLFiddle Demo

Need a twin group by value

I have a query something like this,
SELECT SOME_ID, COUNT(ANOTHER_ID) AS WITHOUT_FILTER
from SOME_TABLE GROUP BY SOME_ID
this returns me
+------------+------------------+
| SOME_ID | WITHOUT_FILTER |
+------------+------------------+
| 1 | 40 |
| 2 | 30 |
+------------+------------------+
I have the same query with a condition which gives me filtered values.
SELECT SOME_ID, COUNT(ANOTHER_ID) AS WITH_FILTER
from SOME_TABLE WHERE SOME_COL > 10 GROUP BY SOME_ID
which returns obviously lesser values in the grouped_by section
+------------+----------------+
| SOME_ID | WITH_FILTER |
+------------+----------------+
| 1 | 20 |
| 2 | 15 |
+------------+----------------+
Now, I need a query to give me both the count values ie with condition and without condition in one single query. The result should be like this
+----------+----------------+---------------+
| SOME_ID | WITHOUT_FILTER | WITH_FILTER |
+----------+----------------+---------------+
| 1 | 40 | 20 |
| 2 | 30 | 15 |
+------------+--------------+---------------+
Please help me.
You can do this:
SELECT
SOME_ID,
COUNT(ANOTHER_ID) AS WITHOUT_FILTER
SUM(case when SOME_CONDITION then 1 else 0 end) AS WITH_FILTER
from SOME_TABLE GROUP BY SOME_ID
For learning purposes, here are my 2 cents. You can use COUNT on both fields:
SELECT SOME_ID,
COUNT(ANOTHER_ID) AS WITHOUT_FILTER
COUNT(case
when WHEN SOME_COL > 10 then ANOTHER_ID
else NULL
end) AS WITH_FILTER
from SOME_TABLE GROUP BY SOME_ID
The trick is that COUNT counts non-null values. This feature is ANSI SQL supported, BTW.
You can get a "COUNT, but only for the rows meeting a condition" effect by using IF() and SUM.
SELECT SOME_ID,
COUNT(ANOTHER_ID) AS WITHOUT_FILTER,
SUM(IF(SOME_COL > 10, 1, 0)) AS WITH_FILTER
FROM SOME_TABLE GROUP BY SOME_ID
(Note: This solution, and all the others except Adrian's, has a subtle problem if ANOTHER_ID is ever NULL. If that's the case, then Adrian's is the only one that is truly correct).
try CASE and SUM combined:
SELECT SOME_ID, COUNT(ANOTHER_ID) as WITHOUT_FILTER,
SUM(CASE WHEN SOME_COL > 10 THEN 1 else 0 END) as WITH_FILTER
from SOME_TABLE GROUP BY SOME_ID;
SELECT T1.SOME_ID,
COUNT(T1.ANOTHER_ID) AS WITH_FILTER,
COUNT(T2.ANOTHER_ID) AS WITHOUT_FILTER
FROM SOME_TABLE as T1,
SOME_TABLE as T2
WHERE
T1.SOME_ID=T2.SOME_ID
AND T2.SOME_COL > 10
GROUP BY T1.SOME_ID, T2.SOME_ID
Or you can do it with 2 views merging if your conditions become too touchy