How use #row_number like position row in result in this SQL:
SELECT s.*,
s2.priority AS `priority`,
#row_number := #row_number := #row_number + 1 AS `top`
FROM (SELECT #row_number := 0) init, `server` s
LEFT JOIN servers_services ss ON (s.id = ss.server_id)
LEFT JOIN service s2 ON (s2.id = ss.service_id)
WHERE s.is_banned = 0
ORDER BY ss.service_id IS NULL, priority DESC
#row_number takes values {1, 12, 89 ...} Why?
I don't have experience with variables in MySQL, so my anser can be wrong.
My guess is: You cross join row numbers with your tables. Then in the WHERE clause you dismiss records, so you are left with only some of the original row numbers.
As to how to solve this, I imagine not to join the undesired records in the first place should help:
FROM (SELECT #row_number := 0) init
JOIN server s ON s.is_banned = 0
LEFT JOIN servers_services ss ON (s.id = ss.server_id)
LEFT JOIN service s2 ON (s2.id = ss.service_id)
Related
I need to update the last 110 values of the descricao_geral table with the last 110 values of the relevo table
I'm doing this:
UPDATE descricao_geral
SET id_relevo_fk = (SELECT id_relevo FROM relevo ORDER BY id_relevo DESC LIMIT 110)
ORDER BY id_descricao DESC
LIMIT 110
The error I've received:
Subquery returns more than 1 row
This is really tricky. You need to join the tables together, but you don't have an appropriate key.
You can use variables to assign a sequential value and then use this for the join:
update descricao_geral g join
(select (#rng := #rng + 1) as rn, g2.id_descricao
from (select g2.* from descricao_geral g2 order by g2.id_descricao desc) g2 cross join
(select #rng := 0) params
limit 110
) g2
on g.id_descricao = g2.id_descricao join
(select (#rnr := #rnr + 1) as rn, r.id_relevo
from (select r.* from relevo r order by r.id_relevo desc) r cross join
(select #rnr := 0) params
) r
on g2.rn = r.rn
set g.id_relevo_fk = r.id_relevo;
Trying to select one row at a time from this query (for example where the rank = 1). However, it doesn't work because "unknown column 'rank'. if i change it to "WHERE id = 1" then it works, but for some reason it doesn't know what rank is even tho it is set
SET #rownum=0;
SELECT #rownum := #rownum + 1 AS rank, id, client, date, time, pickupCity, pickupState
FROM (
SELECT r.id, CONCAT(c.fname, ' ', c.lname) as client, r.date,
LOWER(TIME_FORMAT(r.time, '%l:%i%p')) as time, r.pickupCity, r.pickupState
FROM request r
INNER JOIN client c ON r.client = c.id
INNER JOIN pickup p ON r.id = p.request
INNER JOIN driver d ON d.id = p.driver
WHERE date = '2018-04-18' AND d.id = 1
GROUP BY time
) AS tab
HAVING rank = 1;
In MySQL, you can do this using HAVING:
SELECT #rownum := #rownum + 1 AS rank, id, client, date, time, pickupCity, pickupState
FROM (SELECT r.id, CONCAT(c.fname, ' ', c.lname) as client, r.date,
LOWER(TIME_FORMAT(r.time, '%l:%i%p')) as time, r.pickupCity,
r.pickupState
FROM request r JOIN
client c
ON r.client = c.id JOIN
driver d
ON ?
pickup p
ON d.id = p.driver
WHERE date = '2018-04-18' AND d.id = 1
GROUP BY time
) t CROSS JOIN
(SELECT #rank := 0) params
HAVING rank = 1;
Notes:
The ?? is for the missing JOIN conditions.
I went through the effort of fixing your JOIN syntax. You should go through the effort of learning proper, explicit, standard JOIN syntax.
You can set #rank in the query; you don't need a separate statement.
The GROUP BY makes no sense, because you have many unaggregated columns in the SELECT.
If I had to speculate, the root cause of your problems is the missing JOIN condition, and you've put a lot of effort into working around that.
I have my query determined:
SELECT *
FROM `participation`
LEFT JOIN parties ON parties.id = participation.party_id
WHERE `riding_id` = 10001
AND `election_id` = 41
ORDER BY num_votes DESC
LIMIT 1
This accurately produces the result I want.
The result is the most voted for party.
Now I want to perform this same query on every row of a TABLE ridings
which contains all the riding_id rows. Having some trouble getting it.
I don't want to join the other table - but go through every row and perform the same calculation as above - on each row.
Something like:
SELECT *
FROM `participation`
LEFT JOIN parties ON parties.id = participation.party_id
WHERE `riding_id` = "LOOP ALL riding_id IN ridings TABLE"
AND `election_id` = 41
ORDER BY num_votes DESC
LIMIT 1
Any help would be appreciated.
It is tempting to just use a subquery:
SELECT *
FROM participation LEFT JOIN
parties
ON parties.id = participation.party_id
WHERE riding_id IN (SELECT riding_id FROM ridings) AND
election_id = 41
ORDER BY num_votes DESC
But, you no longer get the top vote getter. You get everything.
Here is a method using variables to get just the top vote getting for each riding_id:
SELECT *
FROM (SELECT *,
(#rn := if(#r = riding_id, #rn + 1,
if(#rn := riding_id, 1, 1)
)
) as seqnum
FROM participation LEFT JOIN
parties
ON parties.id = participation.party_id CROSS JOIN
(SELECT #rn := 0, #r := -1) params
WHERE riding_id IN (SELECT riding_id FROM ridings) AND
election_id = 41
ORDER BY riding_id, num_votes DESC
) pp
WHERE seqnum = 1;
I've got the following sqlfiddle http://sqlfiddle.com/#!2/324628/1
I need to create a query that returns the id and the position (ranking) of each student within his class; the position is sorted in descending order according to the value of their academic average stored inside the academic_averages table.
(e.g. the first from class 1, second from the class 1, and so on... the first from class 2, the second from class 2...)
Here's the query:
SELECT students.id,
(SELECT x.position
FROM (
SELECT t.student_id, t.value, #rownum := #rownum + 1 AS position
FROM (
SELECT aa.student_id, aa.value
FROM academic_averages AS aa
INNER JOIN students AS s ON s.id = aa.student_id
INNER JOIN classes_students AS cs ON cs.student_id = s.id
INNER JOIN classes_academic_years AS cas ON cas.id = cs.class_academic_year_id
INNER JOIN classes_academic_years as cas2 on cas2.class_id = cas.class_id
INNER JOIN classes_students as cs2 on cs2.class_academic_year_id = cas2.id
INNER JOIN students as s2 on s2.id = cs2.student_id
WHERE s2.id = 243
AND cas.academic_year_id = 4
AND aa.academic_year_id = 4
GROUP BY aa.student_id
ORDER BY abs(aa.value) DESC
) t
JOIN (SELECT #rownum := 0) r
) AS x WHERE x.student_id = students.id ) AS ranking_by_class
FROM students
However, since it contains a subquery, I cannot change the WHERE from the inner most query to s2.id = students.id because it throws an error (unknown column).
I've tried using an INNER JOIN instead of subqueries, but no luck so far.
Does anyone have a solution?
Thanks
LE: Performance wise the query must be optimized
LE: Here's the structure of the tables:
academic_averages:
id
student_id
value
academic_year_id
classes_academic_years:
id
class_id
name
grade
academic_year_id
classes_students:
id
class_academic_year_id
student_id
classes:
id
school_id
students:
id
The desired output should be student_id, position.
There seems to be some issues with sql fiddle, meanwhile here's the schema: http://snippi.com/s/db8za8k
SELECT x.id
, x.position
, x.academic_average
FROM (SELECT
s.id
, #rownum := #rownum + 1 position
, av.value academic_average
FROM students s
JOIN classes_students cs ON s.id = cs.student_id
JOIN classes_academic_years cay ON cay.id = cs.class_academic_year_id
JOIN academic_averages av ON av.student_id = s.id
WHERE cay.academic_year_id = 4 -- change these two parameters in
AND av.academic_year_id = 4 -- the subquery for different years
ORDER BY av.value DESC) x,
(SELECT #rownum := 0) y
ORDER BY academic_average DESC
I think the above query should work for you.
I've made the assumption that the academic ranking position is determined in a descending order by academic average.
I don't have access to your dataset, so I've added three extra lines, two to select the students' academic average and one to order the result in descending order according to the academic average. This should help you verify that it works as intended. If you run the query, and it works, it should display records with position starting at 1 and incrementing by 1.
In production I would omit these fragments in order to get the result set you specify:
1. , x.academic_average
2. , av.value academic_average
3. ORDER BY academic_average DESC
Edit following elaboration in comments by OP (students' ranking required by class)
This query should give you students' positions by class. If you want to get rid of some fields, you can wrap the SELECT in another SELECT, or ignore the columns once the dataset is extracted to another language.
SELECT
x.student_id
, x.cay_class_id
, x.academic_average
, if(#classid = x.cay_class_id, #rownum := #rownum + 1, #rownum := 1) position
, #classid := x.cay_class_id
FROM (SELECT
s.id student_id
, cay.class_id cay_class_id
, av.value academic_average
FROM students s
JOIN classes_students cs ON s.id = cs.student_id
JOIN classes_academic_years cay ON cay.id = cs.class_academic_year_id
JOIN academic_averages av ON av.student_id = s.id
WHERE cay.academic_year_id = 4 -- change these two parameters in
AND av.academic_year_id = 4 -- the subquery for different years
ORDER BY cay.class_id, av.value DESC) x,
(SELECT #classid := 0, #rownum := 0) y
I wrote a query with a subquery and both of them have an order by.
I have a weird behavior, sometimes I don't get back all the rows, sometimes I have 0 rows, but if I run the inner query I have the correct rows always. Is there some limitation about subquery? MySql is version 5.5
thanks a lot
SELECT
*
FROM
(
SELECT
#fakeId := #fakeId + 1 AS fakeId,
#balance := (#balance + traIn.amount) AS balance,
FROM
(SELECT #fakeId := 0, #balance := 0) AS vars,
table1 traIn
INNER JOIN table2 traTypeIn ON traIn._id = traTypeIn.id
INNER JOIN table3 ptfIn ON traIn.ptf_id = ptfIn.id
LEFT JOIN `user` u ON u.id = traIn.user_create_id
LEFT JOIN `user` up ON up.id = traIn.user_update_id
WHERE
<--- a couple of constraints -->
ORDER BY
traIn.date
) AS data
ORDER BY data.fakeId DESC
LIMIT 50;
Why do you don't, on your sub-query, select traIn.date, and after that, select only fakeId, balance
Somethings like that :
SELECT
data.fakeId, data.balance
FROM
(
SELECT
#fakeId := #fakeId + 1 AS fakeId,
#balance := (#balance + traIn.amount) AS balance,
traIn.date as date1
FROM
(SELECT #fakeId := 0, #balance := 0) AS vars,
table1 traIn
INNER JOIN table2 traTypeIn ON traIn._id = traTypeIn.id
INNER JOIN table3 ptfIn ON traIn.ptf_id = ptfIn.id
LEFT JOIN `user` u ON u.id = traIn.user_create_id
LEFT JOIN `user` up ON up.id = traIn.user_update_id
WHERE
<--- a couple of constraints -->
) AS data
ORDER BY data.date1, data.fakeId DESC
LIMIT 50;