Mysql best students in every class in a school - mysql

In MySql I need to select top student in every class in a school in termid=10 to get discount for next term enrollment .
Please notice that total is not in table(I put in below for clearing problem)
I have this workbook table for all students workbook:
id studentid classid exam1 exam2 total termid
1 2 11 20 40 60 10
2 1 22 40 20 60 10
3 4 11 40 20 60 10
4 5 33 10 60 70 10
5 7 22 10 40 50 10
6 8 11 10 30 40 10
7 9 33 20 45 65 10
8 11 11 null null null 10
9 12 54 null null null 02
10 13 58 null null null 02
1st challenge is : exam1 and exam2 are VARCHAR and total is not in table (as i explained).
2nd challenge is : as you can see in id=8 std #11 has not numbers
3rd challenge is : may be two students have top level so they must be in result.
I need result as :
id studentid classid exam1 exam2 total termid
1 2 11 20 40 60 10
3 4 11 40 20 60 10
4 5 33 10 60 70 10
2 1 22 40 20 60 10
i have this query but not work good as i mention.
SELECT DISTINCT id,studentid,classid,exam1,exam2,total,termid ,(CAST(exam1 AS DECIMAL(9,2))+CAST(exam2 AS DECIMAL(9,2))) FROM workbook WHERE ClassId = '10';

You can get the total for the students by just adding the values (MySQL will convert the values to numbers). The following gets the max total for each class:
select w.classid, max(coalesce(w.exam1, 0) + coalesce(w.exam2, 0)) as maxtotal
from workbook w
group by w.classid;
You can then join this back to the original data to get information about the best students:
select w.*, coalesce(w.exam1, 0) + coalesce(w.exam2, 0) as total
from workbook w join
(select w.classid, max(coalesce(w.exam1, 0) + coalesce(w.exam2, 0)) as maxtotal
from workbook w
group by w.classid
) ww
on w.classid = ww.classid and (coalesce(w.exam1, 0) + coalesce(w.exam2, 0)) = ww.maxtotal;

Another approach is to join the table with itself. You find out the max for each class and then join all students of this class which match the class max:
max for each class (included in the final statement already):
SELECT classid, MAX(CAST(exam1 AS UNSIGNED) + CAST(exam2 AS UNSIGNED)) as 'maxtotal'
FROM students
WHERE NOT ISNULL(exam1)
AND NOT ISNULL(exam2)
GROUP BY classid
The complete statement:
SELECT s2.*, s1.maxtotal
FROM (SELECT classid, MAX(CAST(exam1 AS UNSIGNED) + CAST(exam2 AS UNSIGNED)) as 'maxtotal'
FROM students
WHERE NOT ISNULL(exam1)
AND NOT ISNULL(exam2)
GROUP BY classid) s1
JOIN students s2 ON s1.classid = s2.classid
WHERE s1.maxtotal = (CAST(s2.exam1 AS UNSIGNED) + CAST(s2.exam2 AS UNSIGNED));
SQL Fiddle: http://sqlfiddle.com/#!2/9f117/1

Use a simple Group by Statement:
SELECT
studentid,
classid,
max(coalesce(exam1,0)) as max_exam_1,
max(coalesce(exam2,0)) as max_exam_2,
sum(coalesce(exam1,0) + coalesce(exam2,0)) as sum_exam_total,
termid
FROM
workbook
WHERE
termid=10
GROUP BY
1,2
ORDER BY
5

Try something like this:
SELECT id,studentid,classid,exam1,exam2,(CAST(exam1 AS DECIMAL(9,2))+CAST(exam2 AS DECIMAL(9,2))) AS total,termid FROM `workbook` WHERE ((CAST(exam1 AS DECIMAL(9,2))+CAST(exam2 AS DECIMAL(9,2)))) > 50

Thanks all my friends
I think combine between 2 answer in above is best :
SELECT s2.*, s1.maxtotal
FROM (SELECT ClassId, MAX(
coalesce(exam1,0)+
coalesce(exam2,0)
) as 'maxtotal'
FROM workbook
WHERE
(
termid = '11'
)
GROUP BY ClassId) s1
JOIN workbook s2 ON s1.ClassId = s2.ClassId
WHERE s1.maxtotal = (
coalesce(exam1,0)+
coalesce(exam2,0)
) AND (s1.maxtotal >'75');
last line is good for s1.maxtotal=0 (some times student scores have not be entered and all equals 0 so all will shown as best students) or some times we need minimum score (to enroll in next term).
So thanks all

Related

MYSQL GROUP BY and SUM with clause

Hello there are two tables
Interval
id
is_full
1
1
2
0
3
0
entry_penalty
interval_id
entry_id
amount
2
14
55
3
14
7
3
14
1
1
15
4
1
15
8
2
15
11
So i am trying to display Sum of all entry_penalties per interval, twist is even if there is no relation between entry_penalty and interval table i should display full course interval sum per entry_id (related to is_full field).
For example total results should be in this case
interval_id
entry_id
amount
1
14
63
2
14
55
3
14
8
1
15
23
2
15
11
I have tried with sub query but it ignores to do calculation when there is no relation between entry_penalties and interval tables regarding is_full column.
My code so far.
SELECT
ep.interval_id,
IF (
i.is_full,
(
SELECT SUM(ep2.amount) * 1000 FROM entry_penalty as ep2
WHERE ep2.entry_id = ep.entry_id
),
SUM(ep.amount) * 1000
) as penalty_time,
ep.entry_id
FROM entry_penalty ep
INNER JOIN \`interval\` i ON i.id = ep.interval_id
WHERE ep.entry_id IN (:entryIds)
GROUP BY interval_id, entry_id`
I would propose to deal with the two cases (full, not full) separately, and then use union all to combine the two results:
SELECT i.id, ep.entry_id, SUM(ep.amount)
FROM `interval` i,
entry_penalty ep
WHERE i.is_full
GROUP BY i.id, ep.entry_id
UNION ALL
SELECT i.id, ep.entry_id, SUM(ep.amount)
FROM entry_penalty ep
INNER JOIN `interval` i
ON ep.interval_id = i.id
AND NOT i.is_full
GROUP BY i.id, ep.entry_id
ORDER BY 2, 1
See it run on dbfiddle.uk, where it outputs:
id
entry_id
SUM(ep.amount)
1
14
63
2
14
55
3
14
8
1
15
23
2
15
11

Is there a way to have a conditional statement for comparing of tables using MySQL only?

I am having a dilemma from comparing my tables.
My problem is, I want to get each sum, which depends on the pricing. Here is the table.
Main table
main_id main_price main_date_created
25 8.5 2019-08-16
26 11.5 2019-08-01
Total table
id main_id total_price date_generated
1 25 10 2019-08-16
2 25 10 2019-08-17
3 25 10 2019-08-18
4 25 10 2019-08-19
5 25 10 2019-08-20
6 25 10 2019-08-21
7 26 20 2019-08-01
8 26 5 2019-08-02
9 26 5 2019-08-03
10 26 10 2019-08-04
Price History table
id main_id changed_main_price price_date_changed
1 25 15 2019-08-18
2 26 20 2019-08-03
I don't know if there is a way to do this just by using MySQL, what I am trying to achieve is, the Total table will be sum by MONTH and YEAR and will be multiplied by their designated price that depends on the date whether if the price has changed or not . the SUM will from each month will be generated by multiplying with the main price in the Main table but if the price had changed from its original price which it is on the Price history table
The output should be like this if the conditional is possible:
id main_id total_price price_generated (which is the prices) date
1 25 170 (10+10*8.5) 8.5
2 25 610 (10+10+10+10*15) 15
3 26 287.5 (20+5*11.5) 11.5
4 26 300 (5+10*20) 20
Here is my existing query,
SELECT m.main_id
, m.main_price
, SUM(t.total_price) total_generated
, t.date_generated
FROM main m
INNER JOIN total t
ON m.main_id = t.main_id
GROUP
BY MONTH(t.date_generated);
I know that my query is not enough, and I still don't know if my idea is really possible :(.
I racked my brain. hahaha Is this you're after?
SELECT pricelist.id, pricelist.price, SUM(t.total_price), SUM(t.total_price) * pricelist.price,
year( pricelist.latestdate), month(pricelist.latestdate),
year( t.total_date_generated), month(t.total_date_generated)
from totaltable as t
LEFT JOIN (
(
select main_id as id, main_price as price, main_date_created as latestdate
from maintable
)
UNION ALL
(
select total_main_id, changed_main_price , price_date_changed
from pricehistorytable
)
) as pricelist on pricelist.id = t.total_main_id
GROUP BY pricelist.id , t.total_price, pricelist.price,
year( pricelist.latestdate), month(pricelist.latestdate),
year( t.total_date_generated), month(t.total_date_generated) ;

Retrieve a column with the list of object_id's that occurs together more than once and a second column with the count of how many times it occurs

Note that object_id's 18,10 and 21 are associated to the cart_id 3 once. I wanna know whether the combination occurs again in another cart_id and how many times does that occurs over all the rows existent. I expect two columns as a resultset "combination" and "combination_occurrence_count"
It is quite complicated task to check all possible combinations as it is too many of them.
However, if you simplify your requirements a bit, you can get something useful.
Lets start with finding all combinations of two items. At the beginning you can try the following query:
SELECT
c1.cart_id AS cart1_id
, c1.object_id AS object1_id
, c2.object_id AS object2_id
, cx1.cart_id AS cartX_id
, cx1.object_id AS objectX1_id
, cx2.object_id AS objectX2_id
FROM
cart_item AS c1
INNER JOIN cart_item AS c2 ON (
c2.cart_id = c1.cart_id
AND c2.object_id > c1.object_id
)
INNER JOIN cart_item AS cx1 ON (
cx1.cart_id > c1.cart_id
AND cx1.object_id = c1.object_id
)
INNER JOIN cart_item AS cx2 ON (
cx2.cart_id = cx1.cart_id
AND cx2.object_id = c2.object_id
)
ORDER BY
c1.cart_id
, c1.object_id
, c2.object_id
, cx1.cart_id
, cx1.object_id
, cx2.object_id
There are two ideas behind the query:
Get all possible combinations of two object ids that are exist in
carts. Carts with only one item will be excluded. The only existing
combinations would be analyzed (instead of all possible combinations). [c1 & c2]
Find other carts that have the same object ids combinations [cx1 & cx2]
The results would be something like this:
cart1_id object1_id object2_id cartX_id objectX1_id objectX2_id
3 10 18 30 10 18
3 10 18 31 10 18
3 10 21 30 10 21
3 18 21 30 18 21
30 10 18 31 10 18
Then you can group these results to get "the most popular" pairs:
SELECT
cx1.object_id AS object1_id
, cx2.object_id AS object2_id
, 1 + COUNT(DISTINCT cx1.cart_id) AS cnt
FROM
cart_item AS c1
INNER JOIN cart_item AS c2 ON (
c2.cart_id = c1.cart_id
AND c2.object_id > c1.object_id
)
INNER JOIN cart_item AS cx1 ON (
cx1.cart_id > c1.cart_id
AND cx1.object_id = c1.object_id
)
INNER JOIN cart_item AS cx2 ON (
cx2.cart_id = cx1.cart_id
AND cx2.object_id = c2.object_id
)
GROUP BY
cx1.object_id
, cx2.object_id
ORDER BY
cnt DESC
LIMIT
20
Results:
object1_id object2_id cnt
10 18 3
10 21 2
18 21 2
So pair 10 + 18 is the most popular and are exist in 3 carts.
Pairs 10 + 21 and 18 + 21 are in 2 different carts.
You can continue and do something like this for 3-objects combinations.
P.S. I used the following data set (added a few rows to your data to get a bit more interesting results):
id cart_id object_id
10 2 24
9 3 10
3 3 18
19 3 21
12 4 24
1 7 30
5 9 24
2 11 10
20 14 12
14 14 18
8 14 27
13 15 11
7 16 9
18 16 13
15 20 11
6 21 6
4 23 5
17 23 6
16 25 16
11 29 11
23 30 1
21 30 10
22 30 18
24 30 21
25 31 10
26 31 18
P.P.S. I have not spent too much time on this so it is possible that I missed something in queries. However, I hope you understand the general idea.
The following returns the list of carts with all three objects:
select cart_id
from t
where object_id in (18, 10, 21)
group by cart_id
having count(distinct cart_id) = 3;
select group_concat(`app_item`.`object_id`) as `combination`
from `app_item`
group by `app_item`.`cart_id`
The query return a "combination" resultset as I was looking for:
Since I cannot group again using the "combination" and then make a count of occurrences for each combination and then get the "combination_occurrence_count" it contains, I am now doing this through a method in the application as following
and now I can display an array as key/pair like "combination" => "occurrence count" as following

MySQL Query keep numbers which do not fall between a range

Could anyone point me in the correct direction on how to do this SQL query? I have two tables coord_table and rm_table. I would like to perform a query where any coord_table.loc which falls between any rm_table.start_loc or rm_table.end_loc is removed from the result of the query.
coord_table
coord_id loc
____________________
1 9
2 19
3 30
4 55
rm_table
rast_id start_loc end_loc
___________________________
1 10 20
2 50 60
query_result
coord_id loc
_____________
1 9
3 30
EDIT: This should work. It uses the BETWEEN syntax:
SELECT a.* FROM coords_table a
LEFT JOIN
(
SELECT
*
FROM
(
SELECT
coords_id, loc, start_loc, end_loc,
(loc BETWEEN start_loc AND end_loc) as is_between
FROM
coords_table, rm_table
) a
WHERE a.is_between = 1
) b
ON a.coords_id = b.coords_id
WHERE b.coords_id IS NULL
Fiddle: http://sqlfiddle.com/#!9/3acdb/2

Mysql Query Min And Max with Limit N Grouping

I'd like to ask some question about query.
This is my case:
Structure Table
codenumber varchar (PK)
prize varchar
batchno double
category varchar
Sample Data On Database:
Code Prize BatchNumber Category
1000000231 TRY AGAIN 1 A
1000000238 TRY AGAIN 2 A
1000000376 TRY AGAIN 3 A
1000000473 TRY AGAIN 4 A
1000000934 50 5 A
1000001281 50 6 B
1000001894 50 7 B
1000002014 TRY AGAIN 8 B
1000002831 TRY AGAIN 9 B
1000003123 TRY AGAIN 10 B
1000003158 TRY AGAIN 11 C
1000003224 TRY AGAIN 12 C
1000003524 TRY AGAIN 13 C
1000003598 50 14 C
1000003616 TRY AGAIN 15 C
1000003657 TRY AGAIN 16 A
1000003959 50 17 A
1000004289 TRY AGAIN 18 A
1000004529 TRY AGAIN 19 A
1000004853 TRY AGAIN 20 A
1000005683 TRY AGAIN 21 B
1000005728 100 22 B
1000005816 TRY AGAIN 23 B
1000006325 TRY AGAIN 24 B
I wanted to get the Minimum and Maximum batch number for each 5 rows.
Then how to get the query result like below:
Category MinBatch MaxBatch
A 1 5
B 6 10
C 11 15
A 16 20
B 21 24
Please Help Thanks
Presuming that batch represents the ordering for determining groups of 5, you can do this with variables:
select category, min(batch), max(batch)
from (select s.*, (#rn := #rn + 1) as rn
from structure s cross join
(select #rn := 0) params
order by batch
) s
group by floor((rn - 1) / 5)
order by min(batch);
Actually, if you know the batches are consecutive with no gaps and start at 1:
select category, min(batch), max(batch)
from structure s
group by floor((batch - 1) / 5)
order by min(batch);
Below query will give you the result
select category, min(batchnumber)as 'MinBatch', max(batchnumber)as 'MaxBatch'
from tablename order group by (category)