how to perform delete in mysql table using avg() of another table? - mysql

table_a
user_id score
1 0.33
2 0.34
3 0.35
11 0.90
88 0.80
7 0.10
8 0.11
10 0.09
12 0.80
17 0.80
18 0.80
19 0.80
20 0.80
table_b
user_id canon_id
1 1000
2 1000
3 1000
11 4344
88 4344
7 2023
8 2023
10 2023
12 3333
17 3333
18 3333
19 3333
20 3333
In the above case, how can I delete records from table_b where associated table_a.user_ids from table_b.canon_id have avg(score) < 0.50. In this case, canon_id 2023 and associated user_ids 7,8,10 avg(score) is 0.10 hence it should get deleted.

Join table_b to a query that returns all the canon_ids with associated with average < 0.5:
delete b
from table_b b inner join (
select b.canon_id
from table_b b inner join table_a a
on a.user_id = b.user_id
group by b.canon_id
having avg(a.score) < 0.5
) t on t.canon_id = b.canon_id;
See the demo.
Results:
| user_id | canon_id |
| ------- | -------- |
| 11 | 4344 |
| 88 | 4344 |
| 12 | 3333 |
| 17 | 3333 |
| 18 | 3333 |
| 19 | 3333 |
| 20 | 3333 |

Related

Get single unique row from duplicate data with multiple tables in mysql

I want to get the unique data from multiple tables with the highest id
Refer below data
Users Table
id firstname_english
------ --------------------
2 Lama
4 Akram
6 Ammar
8 Basil
10 Sami
12 Hasan
14 Adnan
16 Mamoon
18 Sulaiman
20 Wasfi
22 Mervat
Users form status with their id
id users_id status_id
------ ----------- -----------
3 2 10
368 4 10
5 4 10
402 6 9
7 6 10
9 8 10
11 10 10
223 10 10
13 12 10
3253 14 2
15 14 10
17 16 10
1488 16 9
231 16 10
19 18 10
22 20 10
750 20 9
232 22 10
24 22 10
2935 22 9
297 22 10
The Result I need
id firstname_english status_id form_id
------ -------------------- --------------------
2 Lama 10 3
4 Akram 10 368
6 Ammar 9 402
8 Basil 10 8
10 Sami 10 223
12 Hasan 10 12
........and so on
I need to display the highest data from the table 2 with the matching id of table 1
For MySql 8.0+ use row_number() window function:
select
u.id, u.firstname_english,
f.status_id, f.id form_id
from users u inner join (
select *,
row_number() over (partition by users_id order by id desc) rn
from users_form
) f on f.users_id = u.id
where f.rn = 1
See the demo.
For previous versions of MySql:
select
u.id, u.firstname_english,
f.status_id, f.id form_id
from users u inner join (
select uf.* from users_form uf
where not exists (
select 1 from users_form
where users_id = uf.users_id and id > uf.id
)
) f on f.users_id = u.id
See the demo.
Results:
| id | firstname_english | status_id | form_id |
| --- | ----------------- | --------- | ------- |
| 2 | Lama | 10 | 3 |
| 4 | Akram | 10 | 368 |
| 6 | Ammar | 9 | 402 |
| 8 | Basil | 10 | 9 |
| 10 | Sami | 10 | 223 |
| 12 | Hasan | 10 | 13 |
| 14 | Adnan | 2 | 3253 |
| 16 | Mamoon | 9 | 1488 |
| 18 | Sulaiman | 10 | 19 |
| 20 | Wasfi | 9 | 750 |
| 22 | Mervat | 9 | 2935 |

Join tables in order

Let's my say, I have two tables PTO_CONTROL and RUTA_PTO,
I try join this tables only by the FK_PTO that they
share in the order that provide the PTO_CONTROL table.
The problem until now is that always get the first
register that find in the search, obtaining repeated values.
How I can create the sql instruction to fix this issue? Thanks.
TABLE PTO_CONTROL
ID FK_PTO NUM HORA
55 122 566 5:02
56 104 568 5:16
57 114 572 5:38
58 104 573 6:12
59 110 577 6:28
60 122 582 6:45
TABLE RUTA_PTO
ID FK_RUTA FK_PTO TIEMPO
15 56 122 0
16 56 104 12
17 56 114 22
18 56 104 32
19 56 121 40
20 56 110 45
21 56 122 55
JOIN TABLE / VALUES EXPECTED
FK_PTO NUM HORA TIEMPO
122 566 5:02 0
104 568 5:16 12
114 572 5:38 22
104 573 6:12 32
110 577 6:28 45
122 582 6:45 55
The DML and sql instruction can be,
CREATE TABLE pto (
ID INT PRIMARY KEY,
NOMBRE VARCHAR(32)
);
CREATE TABLE ruta (
ID INT PRIMARY KEY,
NOMBRE VARCHAR(32)
);
CREATE TABLE ruta_pto (
ID INT PRIMARY KEY,
FK_RUTA INT NOT NULL,
FK_PTO INT NOT NULL,
TIEMPO INT,
CONSTRAINT FK_RUTA_PTO_PTO
FOREIGN KEY (FK_PTO)
REFERENCES pto (ID)
CONSTRAINT FK_RUTA_PTO_RUTA
FOREIGN KEY (FK_RUTA)
REFERENCES ruta (ID)
);
CREATE TABLE pto_control (
ID INT PRIMARY KEY,
FK_PTO INT NOT NULL,
NUM INT,
HORA TIME,
CONSTRAINT FK_PTO_CONTROL_PTO
FOREIGN KEY (FK_PTO)
REFERENCES pto (ID)
);
SELECT
pc.FK_PTO,
pc.NUM,
pc.HORA,
rp.TIEMPO
FROM pto_control AS pc
INNER JOIN ruta_pto AS rp ON
pc.FK_PTO = rp.FK_PTO AND rp.FK_RUTA = 56
INNER JOIN pto AS p ON
pc.FK_PTO = p.ID;
and the wrong result that obtain is
FK_PTO NUM HORA TIEMPO
122 566 5:02 0
104 568 5:16 12
114 572 5:38 22
104 568 5:16 12
110 577 6:28 45
122 566 5:02 0
You need to implement group ranking for both tables. That can be done with these queries:
select c1.*, count(*) as rank
from PTO_CONTROL c1
join PTO_CONTROL c2
on c2.FK_PTO = c1.FK_PTO
and c2.ID <= c1.ID
group by c1.ID;
Result:
| ID | FK_PTO | NUM | HORA | rank |
|----|--------|-----|------|------|
| 55 | 122 | 566 | 5:02 | 1 |
| 56 | 104 | 568 | 5:16 | 1 |
| 57 | 114 | 572 | 5:38 | 1 |
| 58 | 104 | 573 | 6:12 | 2 |
| 59 | 110 | 577 | 6:28 | 1 |
| 60 | 122 | 582 | 6:45 | 2 |
And
select r1.*, count(*) as rank
from RUTA r1
join RUTA r2
on r2.FK_PTO = r1.FK_PTO
and r2.ID <= r1.ID
group by r1.ID;
Result:
| ID | FK_RUTA | FK_PTO | TIEMPO | rank |
|----|---------|--------|--------|------|
| 15 | 56 | 122 | 0 | 1 |
| 16 | 56 | 104 | 12 | 1 |
| 17 | 56 | 114 | 22 | 1 |
| 18 | 56 | 104 | 32 | 2 |
| 19 | 56 | 121 | 40 | 1 |
| 20 | 56 | 110 | 45 | 1 |
| 21 | 56 | 122 | 55 | 2 |
Now you can join the two results using the generated rank
select *
from (
select c1.*, count(*) as rank
from PTO_CONTROL c1
join PTO_CONTROL c2
on c2.FK_PTO = c1.FK_PTO
and c2.ID <= c1.ID
group by c1.ID
) c
join (
select r1.*, count(*) as rank
from RUTA r1
join RUTA r2
on r2.FK_PTO = r1.FK_PTO
and r2.ID <= r1.ID
group by r1.ID
) r using (FK_PTO, rank)
Result:
| FK_PTO | NUM | HORA | TIEMPO |
|--------|-----|------|--------|
| 122 | 566 | 5:02 | 0 |
| 104 | 568 | 5:16 | 12 |
| 114 | 572 | 5:38 | 22 |
| 104 | 573 | 6:12 | 32 |
| 110 | 577 | 6:28 | 45 |
| 122 | 582 | 6:45 | 55 |
http://sqlfiddle.com/#!9/f3f427/5

Pivot table query in mysql

Is there a way to do a query in mysql with this scenario.
i have a table
group_name | cost_period | books_cost | others_cost
group_A | 1/01/2015 | 100 | 200
group_A | 1/02/2015 | 56 | 86
group_A | 1/01/2015 | 22 | 222
group_A | 1/03/2015 | 30 | 40
group_B | 1/02/2015 | 50 | 10
group_B | 1/02/2015 | 45 | 10
group_B | 1/01/2015 | 22 | 15
group_C | 1/02/2015 | 45 | 20
and i want it to have this format after the query
JAN-2015 FEB-2015 MAR_2015 total
group_A
sum of book cost 122 56 30 208
sum of others cost 422 86 40 548
group_B
sum of book cost 22 95 0 117
sum of others cost 15 20 0 45
group_C
sum of book cost 0 45 0 45
sum of others cost 0 20 0 20
is there a way this is possible by a query to avoid using a pivot tool once data is gathered? since jasper's crosstabs are not that flexible
thanks

How to use subquery combine group by DAY

Here is my table trans:
id // user_id // money // date
1 1001 20 2015-11-1
2 1001 50 2015-11-1
3 1001 50 2015-11-2
4 1001 50 2015-11-3
5 1002 10 2015-11-3
6 1002 20 2015-11-1
7 1002 70 2015-11-1
8 1003 80 2015-11-2
9 1003 10 2015-11-3
10 1003 20 2015-11-3
I wannt output like:
id // user_id // date
1 1001 2015-11-1
2 1001 2015-11-2
3 1001 2015-11-3
4 1002 2015-11-1
5 1002 2015-11-3
6 1003 2015-11-2
7 1003 2015-11-3
Which means sum money group by every day,every type and display by each id.
I tried GROUP BY DAY(date) like:
SELECT SUM(a.money), a.user_id FROM trans a GROUP BY DAY(date);
But it sum all the money by each day instead of by user_id.
Thank you.
You can group by more than one column:
mysql> SELECT user_id, SUM(money), `date` FROM trans a GROUP BY user_id, date;
+---------+------------+------------+
| user_id | SUM(money) | date |
+---------+------------+------------+
| 1001 | 70 | 2015-11-01 |
| 1001 | 50 | 2015-11-02 |
| 1001 | 50 | 2015-11-03 |
| 1002 | 90 | 2015-11-01 |
| 1002 | 10 | 2015-11-03 |
| 1003 | 80 | 2015-11-02 |
| 1003 | 30 | 2015-11-03 |
+---------+------------+------------+
7 rows in set (0.00 sec)
If you want a result row per user id, you should group by it:
SELECT `user_id`, `day`, SUM(money)
FROM `trans`
GROUP BY `user_id`, `day`

SQL sub queries - one alias column

course_completions
+-----------------------------------------------+
| id coursemodid userid state timemodified |
+-----------------------------------------------+
| 370 23 2 1 1433582890 |
| 329 24 89 1 1427771915 |
| 333 30 39 1 1428309816 |
| 332 32 39 1 1428303307 |
| 327 33 40 1 1427689703 |
| 328 34 89 1 1427710711 |
| 303 35 41 1 1410258482 |
| 358 36 99 1 1432020067 |
| 365 25 2 1 1433142455 |
| 304 26 69 1 1410717866 |
| 353 37 95 1 1430387005 |
| 416 38 2 1 1438972465 |
| 300 27 70 1 1409824001 |
| 302 29 74 1 1412055704 |
| 297 30 2 1 1409582123 |
| 301 133 41 1 1410255923 |
| 336 133 91 1 1428398435 |
| 364 133 40 1 1433142348 |
| 312 133 85 1 1425863621 |
+-----------------------------------------------+
course_modules
+------------------+
| id course |
+------------------+
| 23 6 |
| 24 6 |
| 25 6 |
| 26 6 |
| 27 6 |
| 28 6 |
| 29 8 |
| 30 8 |
| 31 8 |
| 32 8 |
| 33 8 |
| 34 5 |
| 35 5 |
| 36 5 |
| 37 5 |
| 38 5 |
| 39 9 |
| 40 9 |
| 41 9 |
+------------------+
course_mod_settings
+--------------------------------------+
|id course modinstance |
+--------------------------------------+
| 27 8 30 |
| 28 8 31 |
| 29 8 32 |
| 30 8 33 |
| 31 6 23 |
| 32 6 24 |
| 33 6 25 |
| 34 6 26 |
| 35 6 27 |
| 36 6 28 |
| 37 9 39 |
| 38 9 40 |
| 39 9 41 |
+--------------------------------------+
I was trying about to frame two sub queries in one SQL statement like I want the count of 'criteria mod settings' table values in one column and count of 'course_completions' table values in one column for a particular user along with course.
There shouldn't be relation between count(cms.id) and count(cc.id) except course id, because count(cms.id) is the count of user modules and count(cc.id) is the settings count set by default.
OUTPUT:
COURSE USERID count(cms.id) count(cc.id)
6 89 3 6
6 39 7 6
6 40 5 6
8 69 3 4
8 2 0 4
8 95 4 4
COURSE : getting courseid
USERID : getting userid
count(cms.id) : getting the count of user completed modules.
count(cc.id) : getting the count of settings (ex: For course 6, settings count has 6 and for course 4, settings count has 3.
SELECT cm.course
,cc.userid
,count(cc.coursemodid) AS usermodules
,(
SELECT count(ccc.id)
FROM course_mod_settings cms
INNER JOIN course_modules cm ON cms.course = cm.course
) AS modsettings
FROM course_completions cc
INNER JOIN course_modules cm ON cc.coursemodid = cm.id
WHERE cc.STATE = 1
GROUP BY cm.cours
,cc.userid
I have read your comment above.
Have you tried something like this?
I didn't test the query, it's just a thought.
I might be wrong.
SELECT cms.course AS COURSE, cc.userid AS USERID, COUNT(cms.id), COUNT(cc.id) FROM
course_completions AS cc
INNER JOIN course_modules AS cm ON cc.coursemodid = cm.id
INNER JOIN course_mod_settings AS cms cm.course = cms.course
WHERE cc.state = 1
GROUP BY cm.course, cc.userid