I'm a beginner (not a DBA).
The simple version of my data ==> My hoped for result:
|ball |color|count| |ball |Total Blue|Total Red|
------------------- ----------------------------
|b1 |red | 2 | ====> |b1 | 5 | 2 |
|b1 |blue | 3 | |b2 | 3 | 1 |
|b1 |blue | 2 |
|b2 |red | 1 |
|b2 |blue | 3 |
I want to tabulate each ball (b1, b2, etc).
Then the total instance of each color for each ball.
There are multiple entries for each color of each ball (in my real world data).
But here I show multiple entries for the blue #1-balls only.
I can easily do this:
SELECT ball,
SUM(count) AS 'Total Blue'
FROM t1
WHERE color = 'blue'
GROUP BY ball
To obtain the first (good) result:
|ball |Total Blue|
-----------------
|b1 | 5 |
|b2 | 3 |
To go further, I think I need a subquery.
But I have not been able to get the subquery to process the same way as the regular query.
Below is the closest result I've gotten so far (simple attempt):
SELECT ball,
SUM(count) AS 'Total Blue',
(SELECT SUM(count) FROM t1 WHERE color = 'red') AS 'Total Red'
FROM t1
WHERE color = 'blue'
GROUP BY ball
I get this:
|ball |Total Blue| Total Red|
---------------------------
|b1 | 5 | 3 |
|b2 | 3 | 3 |
Total Red shows the total of all red balls regardless of ball number.
This more involved subquery (for red) produces the exact same result:
(SELECT SUM(cc) FROM
(SELECT DISTINCT count AS cc FROM t1 WHERE color = 'red') AS dd )
AS 'Total Red'
I've added GROUP BY to this subquery to no added effect.
This is as close as I've been able to get.
Many other tries have given a variety of results.
Try combining SUM and IF:
SELECT
ball,
SUM(IF(color = 'blue', count, 0)) AS 'Total Blue'
SUM(IF(color = 'red', count, 0)) AS 'Total Red'
FROM t1
GROUP BY ball
I just want to offer the following, because CASE is standard SQL and IF is not:
select ball,
sum(case when color = 'blue' then `count` else 0 end) as TotalBlue,
sum(case when color = 'red' then `count` else 0 end) as TotalRed
from t
group by ball
order by 1
Also, having "count" as the name of a column is a bad idea, because it is an SQL reserved word.
Related
I'm returning a list of results from a database but because of a design feature I need a specific order.
The results should return randomly. The only criteria is that one of the values should not appear twice in a row.
Here's the example data:
id
animals
color
1
hamster
brown
2
dog
brown
3
horse
white
4
mouse
gray
5
cat
black
6
bird
orange
7
snake
green
8
monkey
orange
9
chameleon
green
So I have a list of animals and their individual colours in the table. I want to return a list of 5 of these animals randomly ordered but without two colours show up in a row. So the dog can't show up after the mouse and the chameleon can't show up after the snake etc...
I have solved this with PHP in the past. But I'm looking for a faster and smarter solution and hopefully in MySQL only.
Let me know :-)
Well, if you're using a recent version of MySQL (8.0+), you can do something like this.
The first CTE term provides the data. You can replace that with any list of data you wish, directly from some table or the result of a complex query expression.
rn0 is the order of the randomly ordered data.
#Zakaria is correct. Here's the adjusted SQL to handle just the requirement that consecutive rows should not have the same color, after randomly ordering the data.
Basically, this randomly orders the data and then takes just the first edge of each color island, and limits the result to 5 islands.
WITH data (id,animals,color) AS (
SELECT 1 AS id, 'hamster' AS animals , 'brown' AS color UNION
SELECT 2, 'dog' , 'brown' UNION
SELECT 3, 'horse' , 'white' UNION
SELECT 4, 'mouse' , 'gray' UNION
SELECT 5, 'cat' , 'black' UNION
SELECT 6, 'bird' , 'orange' UNION
SELECT 7, 'snake' , 'green' UNION
SELECT 8, 'monkey' , 'orange' UNION
SELECT 9, 'chameleon' , 'green'
)
, list1 AS (
SELECT id, animals, color, ROW_NUMBER() OVER (ORDER BY rand()) AS rn0 FROM data
)
, list AS (
SELECT *, CASE WHEN color = LAG(color) OVER (ORDER BY rn0) THEN 0 ELSE 1 END AS good
FROM list1
)
SELECT *
FROM list
WHERE good = 1
ORDER BY rn0
LIMIT 5
;
An example result:
+----+-----------+--------+-----+------+
| id | animals | color | rn0 | good |
+----+-----------+--------+-----+------+
| 9 | chameleon | green | 1 | 1 |
| 2 | dog | brown | 3 | 1 |
| 6 | bird | orange | 4 | 1 |
| 1 | hamster | brown | 5 | 1 |
| 3 | horse | white | 6 | 1 |
+----+-----------+--------+-----+------+
The original SQL, which does more than requested, requiring distinct colors in the result. It's not what was requested.
WITH data (id,animals,color) AS (
SELECT 1, 'hamster' , 'brown' UNION
SELECT 2, 'dog' , 'brown' UNION
SELECT 3, 'horse' , 'white' UNION
SELECT 4, 'mouse' , 'gray' UNION
SELECT 5, 'cat' , 'black' UNION
SELECT 6, 'bird' , 'orange' UNION
SELECT 7, 'snake' , 'green' UNION
SELECT 8, 'monkey' , 'orange' UNION
SELECT 9, 'chameleon' , 'green'
)
, list AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY rand()) AS rn0 FROM data
)
, step1 AS (
SELECT list.*, ROW_NUMBER() OVER (PARTITION BY color ORDER BY rn0) AS rn
FROM list
)
SELECT *
FROM step1
WHERE rn = 1
ORDER BY rn0
LIMIT 5
;
Sample result:
+----+---------+--------+-----+----+
| id | animals | color | rn0 | rn |
+----+---------+--------+-----+----+
| 7 | snake | green | 1 | 1 |
| 6 | bird | orange | 2 | 1 |
| 3 | horse | white | 3 | 1 |
| 1 | hamster | brown | 5 | 1 |
| 5 | cat | black | 6 | 1 |
+----+---------+--------+-----+----+
Do you mean something like this?
select any_value(name), color from animals group by color order by rand() limit 5;
Fiddle here: https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=ff1854c9698e2c60deaf9131ea87774c
Let's say I have a table that lists cars by user.
id | user_id | color
1 | 1 | red
2 | 1 | red
3 | 2 | blue
4 | 2 | red
5 | 3 | red
Now, I want to know how much red cars each client has, so I've done this SQL :
SELECT user_id, COUNT(color)
FROM cars
WHERE color = 'red'
GROUP BY user_id
Which lists me :
1 | 2
2 | 1
3 | 1
But what I really want is the count of each count. Something like :
Users with 1 red car : 2
Users with 2 red car : 1
...
So is there a way to count my select which already includes a count() grouped by ?
Thank you in advance !
Use an aggregation of aggregations:
SELECT redCount, COUNT(*)
FROM (SELECT user_id, COUNT(color) as redCount
FROM cars
WHERE color = 'red'
GROUP BY user_id
) uc
GROUP BY redCount;
I want to achieve this table:
|Country|Cars|Blue Cars|Red Cars| Green Cars |
|Mexico | 22 | 12 | 8 | 2 |
|U.S.A | 12 | 6 | 3 | 3 |
|Denmark| 10 | 3 | 2 | 5 |
That from a database table that makes a report (row) for every car, like this:
|Country|car_color|
|Mexico | Blue |
|U.S.A | Red |
|Denmark| Blue |
|Denmark| Blue |
|Mexico | Blue |
|Denmark| Green |
|Denmark| Red |
|U.S.A | Red |
|Denmark| Green |
I did the first part: grouping the countries and get the total number of cars by country, that was with this query:
SELECT country,
COUNT(county)
FROM my_table
GROUP BY country
ORDER BY COUNT(country)
My question is, how do I get the color car columns in the first table after grouping the rows by county and getting the total number of cars by every country?
Note: I tried several ways but I'm failing to achieve this. As an example, I used:
SELECT country,
COUNT(country),
COUNT(case when car_color = 'Green' then 1 else 0 end)
FROM my_table
GROUP BY country
ORDER BY COUNT(country)
But that only shows the same value of Cars (total number of cars in a country) for the column "Green Car".
Help please!
COUNT counts non-NULL rows and your CASE always returns a value.
Either switch to SUM or omit the ELSE part:
SELECT country
,COUNT(*) AS cars
,SUM(case when car_color = "blue" then 1 else 0 end) AS "blue cars"
,SUM(case when car_color = "red" then 1 else 0 end) AS "red cars"
,COUNT(case when car_color = "green" then 1 end) AS "green cars"
FROM my_table
GROUP BY country
ORDER BY COUNT(*) DESC
I have a table with products, and by answering a set of questions (Could be 2 or could be six, it's not always the same) I want to get results. Each answer has rules to it like color = green or noise > 69.
Now I don't want to use these rules as a WHERE to refine my searchresults, but I want to increment a variable on CASE so I can ORDER on the amount of true conditions. I still get all values, but the ones that better suit my customers needs are on top.
I tried a lot already, something like:
SELECT a.*, b.*,COUNT(CASE WHEN (b.noise >= 1600) THEN 1 ELSE 0 END) as condition_true
But I cant get it to work with multiple CASES.
SAMPLE DATA:
Products table:
id | title
1 | washing machine X
2 | Washing Machine Y200
3 | Even cooler washing machine
Productinfo table
id | noise | color | locked | product_id
1 | 40 | white | 1 | 1
2 | 68 | green | 0 | 2
3 | 72 | green | 1 | 3
Possible rules I will use in the output table
b.noise > 42
b.color = "green"
b.locked = 1
I would love an output table like this
product_id | title | condition_true
3 | Even cooler washing machine | 3
2 | Washing Machine Y200 | 2
1 | washing machine X | 1
CASE only returns one value, and COUNT requires multiple rows. You could just add them.
SELECT a.*, b.*, (CASE WHEN b.noise >= 1600 THEN 1 ELSE 0 END) +
(CASE WHEN color = 'green' THEN 1 ELSE 0 END) AS relevance
FROM table1
ORDER BY relevance DESC
Or, abbreviated for MySQL:
SELECT a.*, b.*, (b.noise >= 1600) +
(color = 'green') AS relevance
FROM table1
ORDER BY relevance DESC
COUNT is not what you want, that works to aggregate results from multiple rows when using GROUP BY.
I would do this using a series of IF() statements, returning 1 or 0 based on the condition (you could also return a bigger number, for more important columns or something):
SELECT IF(b.noise >= 1600,1,0)+IF(b.ocl1 <= 3,1,0)+...;
This is an example of my table:
drug_id | route (enum) | count
------------------------------
1 | PO | 2
1 | IV | 4
1 | IV | 6
2 | PO | 1
2 | PO | 5
2 | IV | 2
This is how I need the information. Basically its SUM(count) but in a column for each "route":
drug_id | PO | IV
-----------------
1 | 2 | 10
2 | 6 | 2
I assume I need a pivot, which I was trying to learn about, but I cannot for the life of me piece together a succinct query which will work.
I've tried things like:
SELECT drug_id, PO, IV
FROM
(
SELECT drug_id, SUM(count) as PO, '0' as IV FROM `core_reports_antiinfectives` WHERE route="PO"
UNION
SELECT drug_id, SUM(count) as IV, '0' as PO FROM `core_reports_antiinfectives` WHERE route="IV"
) aa
However this gives me 0 for ALL IV columns, and I'm not convinced that its appropriate anyway - it'll need to "group" by drug_id and put the columns together, which I am also stuck on.
Is there something I am missing? Or is there a better way to go about it?
Thanks!
Try this
SELECT drug_id,
SUM(case route when 'po' then `count` else 0 end) totalPO,
SUM(case route when 'iv' then `count` else 0 end) totalIV
FROM core_reports_antiinfectives
GROUP BY drug_id
SQLFiddle Demo
SELECT drug_id,
SUM(IF(route='PO',count,NULL)) AS PO,
SUM(IF(route='IV',count,NULL)) AS IV
FROM core_reports_antiinfectives
GROUP BY drug_id
See it on sqlfiddle.