Where and group conflict? - mysql

I have a table like this:
mysql> select * from studentscore;
+------------+-----------+-------+
| student_id | cource_id | score |
+------------+-----------+-------+
| 1 | 1 | 80 |
| 1 | 2 | 90 |
| 1 | 3 | 85 |
| 1 | 4 | 78 |
| 2 | 2 | 53 |
| 2 | 3 | 77 |
| 2 | 5 | 80 |
| 3 | 1 | 71 |
| 3 | 2 | 70 |
| 3 | 4 | 80 |
| 3 | 5 | 65 |
| 3 | 6 | 75 |
| 4 | 2 | 90 |
| 4 | 3 | 80 |
| 4 | 4 | 70 |
| 4 | 6 | 95 |
| 5 | 1 | 60 |
| 5 | 2 | 70 |
| 5 | 5 | 80 |
| 5 | 6 | 69 |
| 6 | 1 | 76 |
| 6 | 2 | 88 |
| 6 | 3 | 87 |
| 7 | 4 | 80 |
| 8 | 2 | 71 |
| 8 | 3 | 58 |
| 8 | 5 | 68 |
| 9 | 2 | 88 |
| 10 | 1 | 77 |
| 10 | 2 | 76 |
| 10 | 3 | 80 |
| 10 | 4 | 85 |
| 10 | 5 | 83 |
| 11 | 3 | 80 |
| 12 | 4 | 99 |
| 13 | 5 | 74 |
+------------+-----------+-------+
I want to show student_id and students' average scores that are higher than 80.
The output I want is like this:
+------------+-------------------+
| student_id | Average |
+------------+-------------------+
| 1 | 83.25 |
| 4 | 83.75 |
| 6 | 83.66666666666667 | // and how can I make this result shorter like 83.67?
| 7 | 80 |
| 9 | 88 |
| 10 | 80.2 |
| 11 | 80 |
| 12 | 99 |
+------------+-------------------+
I've tried the following codes
mysql> select student_id, avg(score) as average_score
-> from studentscore
-> group by student_id
-> where avg(score) >= 80;
and it gave me an syntax error.
I know by rules the where clause should go before the group by clause but I can't because the where clause depends on the result from the group by clause, and if I switch their position it will give me another error("Invalid use of group function").
Can some one tell me how to get the table I want?

use "having" instead of "where"

use having instead of where.
Here's the difference:
with where you can write a predicate that will be applied to each row
with having you can write a predicate that will applied to each group
and in your case, the 2nd is the only solution that can work.

select student_id, avg(score) as average_score
from studentscore
group by student_id
having avg(score) >= 80;

where applies a filter to your data before grouping has taken place, whereas having applies a filter post-grouping. round(,2) will format as you also ask:
select student_id, round(avg(score), 2) as average_score
from studentscore
group by student_id
having average_score >= 80;

Related

Unexpected SUM result found using SUM with JOIN query [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I have two tables 'tbl_orders' and 'tbl_instore'. tbl_orders have 'sel_product_qty' which I want to date wise SUM and table(tbl_instore) have 'inst_prod_qty' and 'chln_amount' which I calculate and want to get purchased unit price. But when I use join query on those two tables, the SUM(sel_product_qty) produces double, triple and quadruple amount from the expected result.
Sample data tables are..
Table "tbl_order":
+----------+------------+------------+-----------------+---------------+--------------------+
| order_id | ord_det_id | product_id | sel_product_qty | selling_price | order_date_time |
+----------+------------+------------+-----------------+---------------+--------------------+
| 3 | 1 | 4 | 50 | 67.82 | 2019-03-21 21:52:21|
| 4 | 1 | 1 | 100 | 37.88 | 2019-03-21 21:52:21|
| 5 | 2 | 4 | 120 | 67.82 | 2018-03-23 00:02:36|
| 6 | 3 | 3 | 300 | 123.67 | 2019-03-23 00:04:38|
| 7 | 3 | 2 | 50 | 76.28 | 2019-03-23 00:04:38|
| 8 | 4 | 4 | 50 | 67.82 | 2019-03-24 12:13:06|
| 9 | 4 | 2 | 100 | 76.28 | 2019-03-24 12:13:06|
| 10 | 5 | 1 | 10 | 37.88 | 2019-03-25 12:56:40|
| 11 | 5 | 4 | 7 | 67.82 | 2019-03-25 12:56:40|
| 12 | 6 | 4 | 23 | 67.82 | 2019-03-29 00:29:14|
| 13 | 6 | 2 | 25 | 76.28 | 2019-03-29 00:29:14|
| 16 | 7 | 1 | 120 | 37.88 | 2019-04-14 16:51:10|
| 17 | 7 | 3 | 90 | 123.67 | 2019-04-14 16:51:11|
| 18 | 8 | 1 | 100 | 66.95 | 2019-04-22 23:30:39|
| 19 | 8 | 2 | 22 | 70.04 | 2019-04-22 23:30:39|
+----------+------------+------------+-----------------+---------------+--------------------+
Table "tbl_instore":
+----------+----------+------------+---------------+-------------+--------------------+
| in_st_id | s_inv_id | product_id | inst_prod_qty | chln_amount | instore_date_time |
+----------+----------+------------+---------------+-------------+--------------------+
| 1 | 1 | 1 | 1000 | 65852 | 2/14/2018 17:28 |
| 14 | 9 | 1 | 100 | 6400 | 4/26/2019 8:26 |
| 3 | 2 | 1 | 2000 | 58885 | 3/19/2019 17:32 |
| 5 | 3 | 1 | 100 | 3588 | 3/19/2019 17:35 |
| 11 | 7 | 1 | 1000 | 65000 | 4/22/2019 23:17 |
| 9 | 5 | 1 | 100 | 6345 | 4/20/2019 0:13 |
| 12 | 8 | 2 | 100 | 7800 | 4/22/2019 23:20 |
| 8 | 4 | 2 | 2000 | 144567 | 3/23/2019 0:04 |
| 7 | 4 | 3 | 1000 | 121665 | 3/23/2019 0:04 |
| 13 | 8 | 3 | 150 | 32000 | 4/22/2019 23:20 |
| 15 | 9 | 3 | 100 | 19000 | 4/26/2019 8:26 |
| 10 | 6 | 4 | 1000 | 88022 | 4/20/2019 0:16 |
| 6 | 3 | 4 | 100 | 6582 | 3/19/2019 17:35 |
| 4 | 2 | 4 | 1000 | 65882 | 3/19/2019 17:32 |
| 2 | 1 | 4 | 5000 | 359877 | 2/14/2018 17:28 |
+----------+----------+------------+---------------+-------------+--------------------+
The following query I have currently tried:
SELECT SUM(tbl_orders.sel_product_qty) AS `sel_prod_qty`,
(SUM(chln_amount) / SUM(inst_prod_qty)) AS `pur_uni_price`,
date_format(`order_date_time`, '%M-%Y') as `month`,
tbl_orders.product_id AS `product_id`
FROM tbl_orders
INNER JOIN tbl_instore ON tbl_instore.product_id = tbl_orders.product_id
WHERE YEAR(`order_date_time`)= '2019'
GROUP BY `month`, `product_id`;
Which return the following result:
+--------------+---------------+--------+------------+
| sel_prod_qty | pur_uni_price | month | product_id |
+--------------+---------------+--------+------------+
| 1320 | 47.923256 | Apr-19 | 1 |
+--------------+---------------+--------+------------+
| 44 | 72.555714 | Apr-19 | 2 |
+--------------+---------------+--------+------------+
| 270 | 138.132 | Apr-19 | 3 |
+--------------+---------------+--------+------------+
| 660 | 47.923256 | Mar-19 | 1 |
+--------------+---------------+--------+------------+
| 350 | 72.555714 | Mar-19 | 2 |
+--------------+---------------+--------+------------+
| 900 | 138.132 | Mar-19 | 3 |
+--------------+---------------+--------+------------+
| 520 | 73.290563 | Mar-19 | 4 |
+--------------+---------------+--------+------------+
If I run the query individually without JOIN, I will get SUM(sel_prod_qty) value as following (also my expected result should be):
+--------------+---------------+--------+------------+
| sel_prod_qty | pur_uni_price | month | product_id |
+--------------+---------------+--------+------------+
| 220 | 47.923256 | Apr-19 | 1 |
+--------------+---------------+--------+------------+
| 22 | 72.555714 | Apr-19 | 2 |
+--------------+---------------+--------+------------+
| 90 | 138.132 | Apr-19 | 3 |
+--------------+---------------+--------+------------+
| 110 | 47.923256 | Mar-19 | 1 |
+--------------+---------------+--------+------------+
| 175 | 72.555714 | Mar-19 | 2 |
+--------------+---------------+--------+------------+
| 300 | 138.132 | Mar-19 | 3 |
+--------------+---------------+--------+------------+
| 130 | 73.290563 | Mar-19 | 4 |
+--------------+---------------+--------+------------+
So, my question is, why does my query return SUM(sel_product_qty) double, triple and quadruple amount from the expected result?
Try this:
SELECT `sel_prod_qty`,
`pur_uni_price`,
`month`,
orders.product_id AS `product_id`
FROM
(SELECT product_id,SUM(sel_product_qty) AS `sel_prod_qty`,
DATE_FORMAT(`order_date_time`, '%M-%Y') AS `month`
FROM tbl_orders
WHERE YEAR(`order_date_time`)='2019'
GROUP BY `month`, `product_id`) orders
INNER JOIN
(SELECT product_id,(SUM(chln_amount) / SUM(inst_prod_qty)) AS `pur_uni_price`
FROM tbl_instore GROUP BY product_id) instore
ON orders.product_id=instore.product_id;
I created two sub-query from those tables that you joined because what doesn't work is that you are doing INNER JOIN ... ON tbl_instore.product_id = tbl_orders.product_id. Which if you refer back to your table, those value were repeated multiple times in both tables. Therefore, this sub-queries will perform the mathematical operation and the outer query will only return the results from it.
The pur_uni_price field is not an aggregate field anymore, therefore you need to add it on your GROUP BY. See code below
SELECT SUM(tbl_orders.sel_product_qty) AS `sel_prod_qty`,
(SUM(chln_amount) / SUM(inst_prod_qty)) AS `pur_uni_price`,
date_format(`order_date_time`, '%M-%Y') as `month`,
tbl_orders.product_id AS `product_id`
FROM tbl_orders
INNER JOIN tbl_instore ON tbl_instore.product_id = tbl_orders.product_id
WHERE YEAR(`order_date_time`)= '2019'
GROUP BY `month`, `product_id`, (SUM(chln_amount) / SUM(inst_prod_qty))

How to select multiple values for one table "cell" MySQL

For all players, I need to find the player number and a list of the numbers of teams for which they have ever played.
Here is the table "MATCHES":
+---------+--------+----------+-----+------+
| MATCHNO | TEAMNO | PLAYERNO | WON | LOST |
+---------+--------+----------+-----+------+
| 1 | 1 | 6 | 3 | 1 |
| 2 | 1 | 6 | 2 | 3 |
| 3 | 1 | 6 | 3 | 0 |
| 4 | 1 | 44 | 3 | 2 |
| 5 | 1 | 83 | 0 | 3 |
| 6 | 1 | 2 | 1 | 3 |
| 7 | 1 | 57 | 3 | 0 |
| 8 | 1 | 8 | 0 | 3 |
| 9 | 2 | 27 | 3 | 2 |
| 10 | 2 | 104 | 3 | 2 |
| 11 | 2 | 112 | 2 | 3 |
| 12 | 2 | 112 | 1 | 3 |
| 13 | 2 | 8 | 0 | 3 |
+---------+--------+----------+-----+------+
The best I could come up with was:
SELECT DISTINCT playerno, teamno
FROM matches
ORDER BY playerno;
which results in:
+----------+--------+
| playerno | teamno |
+----------+--------+
| 2 | 1 |
| 6 | 1 |
| 8 | 1 |
| 8 | 2 |
| 27 | 2 |
| 44 | 1 |
| 57 | 1 |
| 83 | 1 |
| 104 | 2 |
| 112 | 2 |
+----------+--------+
Notice how player 8 has played on two teams. How can I get the table to show only one row for player 8 and a list of teamno's (1 & 2)?
You could use the group_concat aggregate function:
SELECT playerno, GROUP_CONCAT(DISTINCT teamno)
FROM matches
GROUP BY playerno
ORDER BY playerno;
You could use group_concat
SELECT playerno, group_concat( teamno)
FROM matches
GROUP BY playerno;

Group rows with sum and join (Build summary)

There is a rowset like this:
| ID | OP_CODE | OWNER | MEASURE | COUNT |
|----|-------------|-------|----------|-------|
| 1 | Operation 1 | 1 | Geometry | 42 |
| 2 | Operation 1 | 1 | Geometry | 48 |
| 3 | Operation 1 | 1 | Vacuum | 29 |
| 4 | Operation 1 | 1 | Electro | 14 |
| 5 | Operation 1 | 2 | Geometry | 87 |
| 6 | Operation 1 | 2 | Geometry | 112 |
| 7 | Operation 1 | 2 | Vacuum | 78 |
| 8 | Operation 1 | 3 | Vacuum | 56 |
| 9 | Operation 1 | 3 | Electro | 78 |
I want to group rows by Owner and merge/join other Measures (values of column MEASURE) with sum of column Count to this result like this:
| OWNER | GEOMETRY_CNT | VACUUM_CNT | ELECTRO_CNT | TOTAL_CNT |
|-------|--------------|------------|-------------|-----------|
| 1 | 90 | 29 | 14 | 133 |
| 2 | 199 | 78 | (null) | 277 |
| 3 | (null) | 56 | 78 | 134 |
In this case Geometry_cnt, Vacuum_cnt, Electro_cnt is a sum of corresponding values in first table:
Owner_1_Geometry_cnt=42+48=90;
Owner_1_Vacuum_cnt=29;
Owner_1_Electro_cnt=14;
Owner_1_TOTAL=29+14+90=133;
How can I get this rowset?
SQL Fiddle
Try this:
SELECT a.OWNER, SUM(IF(a.MEASURE = 'Geometry', a.COUNT, 0)) GEOMETRY_CNT,
SUM(IF(a.MEASURE = 'Vacuum', a.COUNT, 0)) VACUUM_CNT,
SUM(IF(a.MEASURE = 'Electro', a.COUNT, 0)) ELECTRO_CNT,
SUM(a.COUNT) TOTAL_CNT
FROM operations_schedule a
GROUP BY a.OWNER
Check the SQL FIDDLE DEMO
OUTPUT
| OWNER | GEOMETRY_CNT | VACUUM_CNT | ELECTRO_CNT | TOTAL_CNT |
|-------|--------------|------------|-------------|-----------|
| 1 | 90 | 29 | 14 | 133 |
| 2 | 199 | 78 | 0 | 277 |
| 3 | 0 | 56 | 78 | 134 |

MySQL Query for averages

good morning. I have this table:
mysql> select * from Data;
+---------------------------+--------+-------+
| affyId | exptId | level |
+---------------------------+--------+-------+
| 31315_at | 3 | 250 |
| 31324_at | 3 | 91 |
| 31325_at | 1 | 191 |
| 31325_at | 2 | 101 |
| 31325_at | 4 | 51 |
| 31325_at | 5 | 71 |
| 31325_at | 6 | 31 |
| 31356_at | 3 | 91 |
| 31362_at | 3 | 260 |
| 31510_s_at | 3 | 257 |
| 5321_at | 4 | 90 |
| 5322_at | 4 | 90 |
| 5323_at | 4 | 90 |
| 5324_at | 3 | 57 |
| 5324_at | 4 | 90 |
| 5325_at | 4 | 90 |
| AFFX-BioB-3_at | 3 | 97 |
| AFFX-BioB-5_at | 3 | 20 |
| AFFX-BioB-M_at | 3 | 20 |
| AFFX-BioB-M_at | 5 | 214 |
| AFFX-BioB-M_at | 7 | 20 |
| AFFX-BioB-M_at | 8 | 40 |
| AFFX-BioB-M_at | 9 | 20 |
| AFFX-HSAC07/X00351_M_at | 3 | 86 |
| AFFX-HUMBAPDH/M33197_3_st | 3 | 277 |
| AFFX-HUMTFFR/M11507_at | 3 | 90 |
| AFFX-M27830_3_at | 3 | 271 |
| AFFX-MurIL10_at | 3 | 8 |
| AFFX-MurIL10_at | 5 | 8 |
| AFFX-MurIL10_at | 6 | 4 |
| AFFX-MurIL2_at | 3 | 20 |
| AFFX-MurIL4_at | 5 | 78 |
| AFFX-MurIL4_at | 6 | 20 |
| U95-32123_at | 1 | 128 |
| U95-32123_at | 2 | 128 |
| U98-40474_at | 1 | 57 |
| U98-40474_at | 2 | 57 |
+---------------------------+--------+-------+
37 rows in set (0.00 sec)
If I wanna look for the average expression level (level) of each array probe (affyId) across all experiments, I do SELECT affyId, AVG(level) AS average FROM Data GROUP BY affyId;
However, I can't figure out how to look for the average expression level of each array probe (affyId) for each experiment... It must be something similar to the last query, but I don't obtain good results... any help?
PD: someone told me I should give some reputation or click to some green button if somebody solves my question... Is it right? How do I do it? I'm pretty new on this website...
This shows the average for every affyId:
SELECT affyId, AVG(level) AS average FROM Data GROUP BY affyId
This the average for every exptId:
SELECT exptId, AVG(level) AS average FROM Data GROUP BY exptId
and this the average for every exptId in every affyId:
SELECT affyId, exptId, AVG(level) AS average FROM Data GROUP BY exptId, affyId
Just add that to the group by clause
SELECT affyId, exptId, AVG(level) AS average
FROM Data
GROUP BY affyId, exptId;

join with a group by?

i have a table called rc_language_type_table with:
id language
1 english
2 Xhosa
3 afrikaans
etc
then i have a table rc_language_type_assoc_table with:
profile_id | language_type_id |
+------------+------------------+
| 3 | 1 |
| 13 | 1 |
| 15 | 1 |
| 16 | 1 |
where i have profiles and each profile is connected to a language id in a 1 to many
so then i did:
select *,count(*) from rc_language_type_assoc_table group by language_type_id;
+------------+------------------+----------+
| profile_id | language_type_id | count(*) |
+------------+------------------+----------+
| 3 | 1 | 96 |
| 3 | 2 | 19 |
| 3 | 3 | 18 |
| 64 | 4 | 51 |
| 94 | 5 | 10 |
| 37 | 6 | 26 |
| 3 | 7 | 21 |
| 3 | 8 | 4 |
| 3 | 9 | 6 |
| 88 | 10 | 4 |
| 3 | 11 | 3 |
+------------+------------------+----------+
what i want now is: instead having the language_type_id i want to display the actual language...how would i do this please???
i tried:
select *, count(*)
from rc_language_type_assoc_table, rc_language_type_table
group by language_type_id
where rc_language_type_assoc_table.language_type_id = rc_language_type_table.id;
but i get a syntax error...
please help??
thank you
GROUP BY should be "after" the WHERE statement and not before
select *, count(*)
from rc_language_type_assoc_table, rc_language_type_table
where rc_language_type_assoc_table.language_type_id = rc_language_type_table.id
group by language_type_id ;