SELECT *
FROM (
`lecture` AS l
)
LEFT JOIN `professor` AS p ON `p`.`professor_id` = `l`.`professor_id`
WHERE `lecture_sem` = '20141'
AND (
lecture_name LIKE '%KEYWORD%'
OR lecture_code LIKE '%KEYWORD%'
OR p.professor_name LIKE '%KEYWORD%'
)
AND (
SELECT COUNT( DISTINCT s1.yoil, s1.start_time, s1.end_time )
FROM schedule AS s1
INNER JOIN schedule AS s2 ON ( s1.lecture_id
IN (
SELECT lecture_id
FROM timeitem
WHERE timetable_id =890
)
AND s2.yoil = s1.yoil
AND (
(
s1.start_time <= s2.start_time
AND s2.end_time <= s1.end_time
) )
AND s2.lecture_id = lecture_id # <-- HERE
)
) >0
LIMIT 0 , 30
I want to use where column like this:
s2.lecture_id = lecture_id
or,
s2.lecture_id = l.lecture_id
So I want to use parent column in subquery, but error occurs:
Column 'lecture_id' in on clause is ambiguous
I googled many answers about this problem ("on clause is ambiguous"), they said I should replace this query to joining two queries. But I don't have a clue how to transform this query.
I believe the following does the equivalent query, but I haven't tested it.
The technique is to move the correlated subquery into the FROM clause as a derived table so that it gets run only once, producing a result for each lecture_id (hence the GROUP BY).
I also factored out the subquery for timetable, which I believe can be rewritten as a JOIN.
And I suspect the join to professor may be properly an INNER JOIN -- how can you have a lecture without a professor?
SELECT l.*, p.*
FROM lecture AS l
INNER JOIN professor AS p ON p.professor_id = l.professor_id
INNER JOIN (
SELECT s2.lecture_id, COUNT( DISTINCT s1.yoil, s1.start_time, s1.end_time ) AS count
FROM schedule AS s1
INNER JOIN schedule AS s2 ON s2.yoil = s1.yoil
AND s1.start_time <= s2.start_time AND s2.end_time <= s1.end_time
INNER JOIN timeitem AS t ON s1.lecture_id = t.lecture_id
WHERE t.timetable_id = 890
GROUP BY s2.lecture_id
) AS c ON l.lecture_id = c.lecture_id
WHERE l.lecture_sem = '20141'
AND c.count > 0
AND (
l.lecture_name LIKE '%KEYWORD%'
OR l.lecture_code LIKE '%KEYWORD%'
OR p.professor_name LIKE '%KEYWORD%'
)
LIMIT 0 , 30
Anyway, even if the query isn't perfect, it demonstrates how one would refactor it to avoid a correlated subquery.
The line you identified in your code isn't an ON clause.
Instead, I think the error is referring to the following section.
AND (
SELECT COUNT( DISTINCT s1.yoil, s1.start_time, s1.end_time )
FROM schedule AS s1
INNER JOIN schedule AS s2 ON ( s1.lecture_id
IN (
# vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
SELECT lecture_id # <---- HERE
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FROM timeitem
WHERE timetable_id =890
)
You can fix this by creating an alias for the timeitem table, and prefixing the column with this prefix:
IN (
SELECT ti.lecture_id
FROM timeitem as ti
WHERE ti.timetable_id =890
)
But as Bill Karwin pointed out in his answer, you have other logical issues that need to be addressed.
Related
Hi i have a problem of how to output the latest data of "reading_timesent" by using max(Date), And Also Include the other column where the latest date, and remove redundant data using distinct or group i don't know whats my problem here's the sample img and data
Patient table
Reading Table
Inner Join table
Expected Output
JSFIDDLE SAMPLE
SELECT * FROM Patients P
INNER JOIN Reading R ON R.patient_ID = P.patient_ID
Try this
SELECT * FROM
(
SELECT *,
(
SELECT reading_ID
FROM Reading
WHERE Reading.patient_ID = p.patient_ID
ORDER BY reading_timesent DESC
LIMIT 1
) AS newestReadingID
FROM Patients p
) AS subquery
JOIN Reading ON subquery.newestReadingID = Reading.reading_ID
You can use a correlated subquery for a condition in the ON clause:
SELECT *
FROM Patients P
INNER JOIN Reading R
ON R.patient_ID = P.patient_ID
AND R.reading_timesent = (
SELECT MAX(R2.reading_timesent)
FROM Reading R2
WHERE R2.patient_ID = P.patient_ID
)
Another way:
SELECT P.*, R.*
FROM (
SELECT patient_ID, MAX(reading_timesent) as reading_timesent
FROM Reading
GROUP BY patient_ID
) X
JOIN Patients P USING (patient_ID)
JOIN Reading R USING (patient_ID, reading_timesent)
Usually I would use the AUTO_INCREMENT column instead of a TIMESTAMP column for similar tasks. But that is not always applicable.
I have a table, named rendeles_termekek.(In english, ordered_products)
I would like to count, that each product how many times was ordered.
With the SQL below, I get 4 as ennyi. I upload a picture, and I wrote the correct number to each rows.
SELECT DISTINCT
rendeles_termekek.termek_id,
termek.termek_id,
termek.termek_nev,
( SELECT COUNT(rendeles_termekek.termek_id) FROM rendeles_termekek ) AS ennyi
FROM rendeles_termekek
LEFT JOIN termek ON rendeles_termekek.termek_id = termek.termek_id
ORDER BY termek.termek_nev ASC
**r1** is the alias of your table rendeles_termekek so you have to access those columns through alias name "r1" like I did in below query. try below
SELECT DISTINCT
r1.termek_id,
termek.termek_id,
termek.termek_nev,
( SELECT COUNT(r.termek_id) FROM rendeles_termekek r where r.termek_id = r1.termek_id ) AS ennyi
FROM rendeles_termekek r1
LEFT JOIN termek ON r1.termek_id = termek.termek_id
ORDER BY termek.termek_nev ASC
I think you have only four rows in your table "rendeles_termekek".
I have updated your query. try this
SELECT DISTINCT
rendeles_termekek.termek_id,
termek.termek_id,
termek.termek_nev,
( SELECT COUNT(rendeles_termekek.termek_id) FROM rendeles_termekek r where r.termek_id = r1.termek_id ) AS ennyi
FROM rendeles_termekek r1
LEFT JOIN termek ON rendeles_termekek.termek_id = termek.termek_id
ORDER BY termek.termek_nev ASC
Note that I have changed the sub-query and added a where condition in it
`( SELECT COUNT(rendeles_termekek.termek_id) FROM rendeles_termekek r where r.termek_id = r1.termek_id ) AS ennyi`
How can I sort the results of a subquery that's using a json aggregate?
If I had a schema like this:
CREATE TABLE plans( id integer NOT NULL, name character varying(255));
CREATE TABLE plan_items ( id integer NOT NULL, plan_id integer NOT NULL, expected_at date, status integer);
I'm aggregating the plan_items result on a json column through a subquery.
Like this:
SELECT
plans.id,
plans.name,
jsonb_agg((SELECT pi_cols FROM
(SELECT plan_items.id, plan_items.expected_at, plan_items.status) pi_cols
)) AS plan_items_data
FROM
plans
INNER JOIN plan_items ON plan_items.plan_id = plans.id
GROUP BY
plans.id,
plans.name
ORDER BY plans.id;
The JSON aggregate is working as expected and give me the results that I need. Ok.
But I can't order the results.
I've tried:
jsonb_agg((SELECT pi_cols FROM
(SELECT plan_items.id, plan_items.expected_at, plan_items.status ORDER BY plan_items.expected_at) pi_cols
)) AS plan_items_data
and also:
jsonb_agg((SELECT pi_cols FROM
(SELECT plan_items.id, plan_items.expected_at, plan_items.status) pi_cols ORDER BY pi_cols.expected_at
)) AS plan_items_data
But none of these solved.
Any ideas?
As Abelisto suggests, just use a simple aggregate expression with ordering:
jsonb_agg(plan_items ORDER BY plan_items.expected_at) AS plan_items_data
Join the tables with the desirable sort order and use lateral join to select columns for jsonb_agg():
select s.plan_id id, name, jsonb_agg(pi_col)
from (
select p.id plan_id, p.name, pi.id, expected_at, status
from plans p
join plan_items pi
on p.id = pi.plan_id
order by p.id, expected_at
) s,
lateral (
select plan_id id, expected_at, status
) pi_col
group by 1, 2
order by 1;
The above query seems to be more natural and flexible (and a bit faster in most cases) than the one with a subquery in a select list. However for better performance you should also apply Abelisto's suggestion:
select s.plan_id id, name, json_agg(pi_col order by pi_col.expected_at)
from (
select p.id plan_id, p.name, pi.id, expected_at, status
from plans p
join plan_items pi
on p.id = pi.plan_id
) s,
lateral (
select plan_id id, expected_at, status
) pi_col
group by 1, 2
order by 1;
How can I optimize this mysql statement?
SELECT DISTINCT p.name
FROM Something_Meta s1
JOIN Something_Meta s2 ON s1.fk_somethingId = s2.fk_somethingId
JOIN Products p ON s2.fk_productId = p.id
JOIN
(
select fk_id from Restricted where fk_foo != 233 and fk_id NOT IN
(
Select fk_id from Restricted where fk_foo = 233
)
)
r ON r.fk_id = p.id
WHERE s1.fk_somethingId = 63 AND s2.fk_somethingId <> s1.fk_somethingId
order by p.name ASC
My tables are like that
Product (id,name )
Restricted (id,fk_id,fk_foo )
Something_Meta (id,fk_id,fk_somethingId )
fk_id is foreign key to product (id)
Probably that sql statement needs optimization..
select fk_id from Restricted where fk_foo != 233 and fk_id NOT IN
(
Select fk_id from Restricted where fk_foo = 233
)
The whole query statement needs more than 1.5 sec to run which are many secs for a website for a single query.
You could try an index on (fk_foo, fk_id) which would cover your entire query:
create index ix_restricted_fk_foo_fk_id(fk_foo, fk_id) on restricted
First off : the DISTINCT is a bit of a red flag. If you need to filter out the doubles then there's probably an error somewhere (either in the query or the design) causing the doubles.
Second; you could write your query like this:
SELECT DISTINCT p.name
FROM Something_Meta s1
JOIN Something_Meta s2 ON s1.fk_somethingId = s2.fk_somethingId
JOIN Products p ON s2.fk_productId = p.id
WHERE s1.fk_somethingId = 63 AND s2.fk_somethingId <> s1.fk_somethingId
AND NOT EXISTS ( SELECT *
FROM Restricted r
WHERE r.fk_foo != 233
AND r.fk_id = p.id )
AND EXISTS ( SELECT *
FROM Restricted r2
WHERE r2.fk_foo = 233
AND r2.fk_id = p.id )
order by p.name ASC
As I don't have a clue about the Something_Meta tables I'll simply focus on the Restricted table and suggest you put an index on fk_foo and fk_id. Said index is NOT part of the query, but rather of the table, so you have to define it upfront, once.
CREATE INDEX idx_Restricted ON Restricted (fk_id, fk_foo)
Once the index is there; any query that might benefit from it will automagically use it in the background; no need for you to adapt the query for it.
Side-note; since you obviously are looking for the product I find it curious you don't 'focus' your query on Products.
SELECT p.name
FROM Products p
JOIN etc...
SELECT e.*,
(
SELECT COUNT(*) FROM
(
SELECT tm.exerciseID FROM exercise_targetedmuscles tm
WHERE tm.exerciseID = e.exerciseID
AND tm.isPrimary = 1
AND tm.targetedMuscleID IN (4,11)
) as musclesCovered
) as numMusclesCovered
FROM exercises e
ORDER BY numMusclesCovered DESC
Basically, I want to order the exercises by the number of targetted muscles they cover (in the example, the targetted muscles are 4 and 11). However, the subquery (for some reason?) doesn't know what e is, so it does not work.
Any ideas as to how I can get this query to order my results properly? Thanks!
EDIT: came up with this after Randy's helpful comment.
SELECT COUNT(tm.targetedMuscleID) as numMusclesCovered, e.*, tm.* FROM exercise_targetedmuscles tm
JOIN exercises e ON tm.exerciseID = e.exerciseID
WHERE tm.isPrimary = 1
AND tm.targetedMuscleID IN (4,11)
GROUP BY tm.exerciseID
ORDER BY numMusclesCovered DESC
thanks so much!
Knowing how the tables are structured might be helpful. I suggest a solution similar to this.
SELECT e.*, tm.*, COUNT(tm.targetedMuscleID) AS coveredMuscles
FROM exercises AS e
JOIN exercise_targetedmuscles AS tm ON tm.exerciseID = e.exerciseID
WHERE tm.isPrimary = 1 AND tm.targetedMuscleID IN (4, 11)
GROUP BY e.exerciseID
ORDER BY coveredMuscles;
If I understand correctly, you don't need subquery at all
SELECT count(tm.targetedMuscleID) as num_muscles, e.exerciseID
FROM exercise_targetedmuscles tm, exercises e
WHERE tm.exerciseID = e.exerciseID
AND tm.isPrimary = 1
AND tm.targetedMuscleID IN (4,11)
GROUP BY e.exerciseID
order by num_muscles
SQL subqueries in MySQL has something like "local namespace". I haven`t got ability to test, but you may be searching for something like this:
SELECT `data`.* FROM (
SELECT COUNT(tm.targetedMuscleID) as `count`,tm.targetedMuscleID FROM exercise_targetedmuscles tm
LEFT JOIN `exercises` as `e` ON (`tm`.`exerciseID`=`e`.`exerciseID`)
WHERE
tm.isPrimary = 1
AND
tm.targetedMuscleID IN (4,11)
GROUP BY tm.targetedMuscleID
) as `data`
ORDER BY `data`.`count`
But, in some cases, you do not have to use subquery at all.