MySQL query not working using nested Select - mysql

SELECT * FROM
(
SELECT messages.from AS `from`, messages.creation AS `creation`, account_images.profile AS `profile`, bio.user_full_name AS `user_full_name`
FROM messages
INNER JOIN account_images ON account_images.uuid=messages.from
INNER JOIN bio ON bio.uuid=messages.from
WHERE messages.to='{$user}'
ORDER BY `creation` DESC
)
GROUP BY `from`
Why this query not working? Is there something wrong with nested select statements? Please help me how to solve this...

FROM is a mysql reserved keyword using from as column name should be in backtics otherwise you will get error messages.from
SELECT * FROM
(
SELECT messages.`from` AS `from`, messages.creation AS `creation`, account_images.profile AS `profile`, bio.user_full_name AS `user_full_name`
FROM messages
INNER JOIN account_images ON account_images.uuid=messages.`from`
INNER JOIN bio ON bio.uuid=messages.`from`
WHERE messages.to='{$user}'
ORDER BY `creation` DESC
)
GROUP BY `from`
Reserved Words

In addition to the unquoted from problem, the joins are in the wrong order. You cannot refer to a table alias in an on clause before it is defined and you need a table alias on the subquery:
SELECT *
FROM (SELECT messages.from AS `from`, messages.creation AS `creation`,
account_images.profile AS `profile`, bio.user_full_name AS `user_full_name`
FROM account_images INNER JOIN
bio
ON bio.uuid = messages.`from` INNER JOIN
messages
ON account_images.uuid = messages.`from`
WHERE messages.to='{$user}'
ORDER BY `creation` DESC
) t
GROUP BY `from`;
Finally, you are attempting to get the last message for a group using a technique explicitly described as unreliable in the MySQL documentation on group by extensions (see here).

Related

Why can I not issue the same query against a recursive view as I can on the table backing it?

I have a tags table, and on it I have defined a view from a recursive CTE, containing all the columns of the tags table:
CREATE VIEW tags_paths AS
WITH RECURSIVE tag_path (id, created_at, updated_at, community_id, tag_set_id, wiki_markdown,
wiki, excerpt, parent_id, name, path) AS
(
SELECT id, created_at, updated_at, community_id, tag_set_id, wiki_markdown,
wiki, excerpt, parent_id, name, name as path
FROM tags
WHERE parent_id IS NULL
UNION ALL
SELECT t.id, t.created_at, t.updated_at, t.community_id, t.tag_set_id,
t.wiki_markdown, t.wiki, t.excerpt, t.parent_id, t.name,
concat(tp.name, ' > ', t.name) as path
FROM tag_path AS tp JOIN tags AS t ON tp.id = t.parent_id
)
SELECT * FROM tag_path
ORDER BY path;
I can issue this query against the tags table just fine:
SELECT tags.*, COUNT(posts.id) AS post_count
FROM `tags`
LEFT OUTER JOIN `posts_tags` ON `posts_tags`.`tag_id` = `tags`.`id`
LEFT OUTER JOIN `posts` ON `posts`.`community_id` = 2 AND `posts`.`id` = `posts_tags`.`post_id`
WHERE `tags`.`community_id` = 2 AND `tags`.`tag_set_id` = 3
GROUP BY tags.id ORDER BY COUNT(posts.id) DESC LIMIT 96 OFFSET 0;
However, the equivalent query issued against the tags_paths view:
SELECT tags_paths.*, COUNT(posts.id) AS post_count
FROM `tags_paths`
LEFT OUTER JOIN `posts_tags` ON `posts_tags`.`tag_id` = `tags_paths`.`id`
LEFT OUTER JOIN `posts` ON `posts`.`community_id` = 2 AND `posts`.`id` = `posts_tags`.`post_id`
WHERE `tags_paths`.`community_id` = 2 AND `tags_paths`.`tag_set_id` = 3
GROUP BY tags_paths.id ORDER BY COUNT(posts.id) DESC LIMIT 96 OFFSET 0;
comes back as an error, specifically:
[42000][1055] Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column
'tags_paths.created_at' which is not functionally dependent on columns in GROUP BY clause; this is
incompatible with sql_mode=only_full_group_by
Why? What can I do about it?
As #Akina states id is a key on the table tags, but not on the view. Therefore, a direct dependency cannot be established in the view for the rest of the columns against the id column, as specified by the SQL Standard.
You have two options. You can either:
Add all columns to the GROUP BY clause. Sometimes this is not possible for large types such as TEXT or binaries.
Or, you can aggregate the columns in the SELECT clause.
Below is the modified SQL statement using the latter:
SELECT
tags_paths.id,
max(tags_paths.created_at) as created_at,
max(tags_paths.updated_at) as updated_at,
max(tags_paths.community_id) as community_id,
max(tags_paths.tag_set_id) as tag_set_id,
max(tags_paths.wiki_markdown) as markdown,
max(tags_paths.wiki) as wiki,
max(tags_paths.excerpt) as excerpt,
max(tags_paths.parent_id) as parent_id,
max(tags_paths.name) as name,
max(tags_paths.path) as path,
COUNT(posts.id) AS post_count
FROM `tags_paths`
LEFT OUTER JOIN `posts_tags` ON `posts_tags`.`tag_id` = `tags_paths`.`id`
LEFT OUTER JOIN `posts` ON `posts`.`community_id` = 2
AND `posts`.`id` = `posts_tags`.`post_id`
WHERE `tags_paths`.`community_id` = 2 AND `tags_paths`.`tag_set_id` = 3
GROUP BY tags_paths.id
ORDER BY COUNT(posts.id) DESC
LIMIT 96
OFFSET 0;
Yep, it becomes longer.

Getting The Latest Record Of Table By Date And Group By ID

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.

how to enhance efficiency of my query

I have such a query:
SELECT
*,
(
SELECT COUNT(DISTINCT client_id)
FROM 1097_course_students_tbl
WHERE course_cycl_id=id
AND stts_id <> 8
AND client_id IN(SELECT id FROM 1097_clients_tbl WHERE is_removed=0)
) AS cnt
FROM 1097_course_cycle_tbl
WHERE (course_id IN (SELECT id FROM 1097_courses_tbl WHERE is_removed=2))
ORDER BY start_date DESC
I need to make it more efficient because it takes too long
any suggestions ?
thanks
Try the following
SELECT cc.*,IFNULL(q.cnt,0) cnt
FROM 1097_course_cycle_tbl cс
JOIN 1097_courses_tbl с ON c.id=cc.course_id AND c.is_removed=2
LEFT JOIN
(
SELECT cs.course_cycl_id,COUNT(DISTINCT cs.client_id) cnt
FROM 1097_course_students_tbl cs
JOIN 1097_clients_tbl c ON cs.client_id=c.id AND c.is_removed=0
WHERE cs.stts_id<>8
GROUP BY cs.course_cycl_id
) q
ON q.course_cycl_id=cс.id
ORDER BY cc.start_date DESC
I think id in 1097_courses_tbl and 1097_clients_tbl is primary key.
Therefore I replaced IN into JOIN.
And I converted the subquery from SELECT block wich executed for each rows into the subquery with GROUP BY which using in LEFT JOIN. Here it'll execute only one time and return all the necessary information.

LEFT JOIN SUM with WHERE clause

The following query always outputs SUM for all rows instead of per userid. Not sure where else to look. Please help.
SELECT * FROM assignments
LEFT JOIN (
SELECT SUM(timeworked) AS totaltimeworked
FROM time_entries
) assignments ON (userid = assignments.userid AND ticketid = ?)
WHERE ticketid = ?
ORDER BY assigned,scheduled
If you want to keep the SELECT *, you would have to add a group by clause in the subquery. Something like this
SELECT * FROM assignments
LEFT JOIN (
SELECT SUM(timeworked) AS totaltimeworked
FROM time_entries
GROUP BY userid
) time_entriesSummed ON time_entriesSummed.userid = assignments.userid
WHERE ticketid = ?
ORDER BY assigned,scheduled
But a better way would be to change the SELECT * to instead select the fields you want a add a group by clause directly. Something like this
SELECT
assignments.id,
assignments.assigned,
assignments.scheduled,
SUM(time_entries.timeworked) AS totalTimeworked
FROM assignments
LEFT JOIN time_entries
ON time_entries.userid = assignments.userid
GROUP BY assignments.id, assignments.assigned, assignments.scheduled
Edit 1
Included table names in query 2 as mentioned in chameera's comment below

MySQL views cannot have subquery in from, and don't maintain order. How can I create a view from this query?

I'm essentially trying to obtain a resultset with each employee's current title. I'd like to create a view from this for later use, but I find I'm being stumped, and likely missing a simple solution. Here's the query in question, and thanks in advance!
select * from
(SELECT
appointment.employee_id,
title.`name` as title_name
FROM
appointment
INNER JOIN appointment_title ON appointment.id = appointment_title.appointment_id
INNER JOIN title ON appointment_title.title_id = title.id
order by appointment_title.effective_date DESC) tmp group by employee_id
Updated:
SELECT
appointment.employee_id ,
( SELECT title.`name`
FROM appointment_title
INNER JOIN title
ON appointment_title.title_id = title.id
WHERE appointment.id = appointment_title.appointment_id
ORDER BY appointment_title.effective_date DESC
LIMIT 1
) AS title_name
FROM appointment
GROUP BY appointment.employee_id
Another option is to break up the query into two views. The first view will contain the derived table subquery, and the second will simply select from that one:
CREATE VIEW vwEmployee_Inner AS
SELECT
appointment.employee_id,
title.`name` as title_name
FROM
appointment
INNER JOIN appointment_title ON appointment.id = appointment_title.appointment_id
INNER JOIN title ON appointment_title.title_id = title.id
order by appointment_title.effective_date DESC
And then your original view becomes:
CREATE VIEW vwEmployee AS
SELECT * FROM vwEmployee_Inner GROUP BY employee_id