SELECT
student.Student_Name
FROM
`student`
GROUP BY
student.Student_ID,
teacher.Department_No IN (
SELECT
teacher.Department_No
FROM
`teacher`, `building`
WHERE
teacher.Department_No BETWEEN 1000
AND 2999
GROUP BY
teacher.Department_No = (
SELECT
*
FROM
`building`
WHERE
building.Building_No IN ( '1', '2')
)
) LIMIT 0, 25
Your sql has two issues:
You need to use IN instead of = OR limit the subquery to only one record
You need to use a specify column instead of * in the subquery
use IN
teacher.Department_No IN (
SELECT
Department_No
FROM
`building`
WHERE
building.Building_No IN ( '1', '2')
)
use LIMIT
teacher.Department_No = (
SELECT
Department_No
FROM
`building`
WHERE
building.Building_No IN ( '1', '2')
LIMIT 1
)
You need to select one column like deparment_id in subquery part
SELECT
student.Student_Name
FROM
`student`
GROUP BY
student.Student_ID,
teacher.Department_No IN (
SELECT
teacher.Department_No
FROM
`teacher`, `building`
WHERE
teacher.Department_No BETWEEN 1000
AND 2999
GROUP BY
teacher.Department_No = (
SELECT
department_id
FROM
`building`
WHERE
building.Building_No IN ( '1', '2')
)
) LIMIT 0, 25
Related
I want to get recent messages of user. And I need get LAST ID of message to each a fetch. How can I do it? Thank you!
Structure:
Query:
SELECT *
FROM `messages`
WHERE (
`from` = 1 OR
`to` = 1
)
GROUP BY (`from` + `to`)
ORDER BY `id` DESC
LIMIT 10
Result:
What I need?
If you have same a problem? I find solution!
SELECT `id`, `from`, `to`, `text`, `created`
FROM (
SELECT *, (`from` + `to`) AS `anchor`
FROM `messages`
WHERE (
`from` = 1 OR
`to` = 1
)
ORDER BY `id` DESC
LIMIT 1
) AS `*`
GROUP BY `anchor`;
If I understand correctly, you can use a correlated subquery:
select m.*
from messages m
where 1 in (m.from, m.to) and
m.id = (select max(m2.id)
from messages m2
where (m2.from = m.from and m2.to = m.to) or
(m2.from = m.to and m2.to = m.from)
);
Note: from and to are really bad names for columns, because they are SQL keywords.
To make things easier, let's say that I have a table representing pretty simple user's feed.
There are two "key" columns in my feed table:
object_id it's a ID of different assets, e.g. comment, post, etc.
entity_type_id it's a basically reference to another table in my DB.
The "children" tables may have some attributes in common, e.g. is_hidden, is_deleted and is_locked (however, they are not replicated across all tables).
Now, I'd like to implement a filter that should filter out my feed items, based on the values of these three attributes.
What I did so far?
SELECT `f`.*
FROM `feed` `f`
WHERE 1
-- !!! Other filters goes here. ---
AND
(
--
-- !!! Filter by status
--
( -- "Locked" (not all children tables have this column)
(
`f`.`entity_type_id` = 1 AND `f`.`object_id` IN ( SELECT `fb_comment_id` FROM `comments` WHERE `is_locked` = 1 AND `fb_page_id` IN('0123456789') )
)
OR
(
`f`.`entity_type_id` = 4 AND `f`.`object_id` IN ( SELECT `fb_post_id` FROM `posts` WHERE `is_locked` = 1 AND `fb_page_id` IN('0123456789') )
)
)
( -- "Hidden" (not all children tables have this column)
(
`f`.`entity_type_id` = 1 AND `f`.`object_id` IN ( SELECT `fb_comment_id` FROM `comments` WHERE `is_hidden` = 1 AND `fb_page_id` IN('0123456789') )
)
OR
(
`f`.`entity_type_id` = 4 AND `f`.`object_id` IN ( SELECT `fb_post_id` FROM `posts` WHERE `is_hidden` = 1 AND `fb_page_id` IN('0123456789') )
)
)
OR
(
-- "Deleted"
(
`f`.`entity_type_id` = 1 AND `f`.`object_id` IN ( SELECT `fb_comment_id` FROM `comments` WHERE `is_deleted` = 1 AND `fb_page_id` IN ('0123456789') )
)
OR
(
`f`.`entity_type_id` = 3 AND `f`.`object_id` IN ( SELECT `insta_comment_id` FROM `instagram_comments` WHERE `is_deleted` = 1 AND `insta_profile_id` IN ('9876543210') )
)
OR
(
`f`.`entity_type_id` = 4 AND `f`.`object_id` IN ( SELECT `fb_post_id` FROM `posts` WHERE `is_deleted` = 1 AND `fb_page_id` IN ('0123456789') )
)
OR
(
`f`.`entity_type_id` = 5 AND `f`.`object_id` IN ( SELECT `insta_post_id` FROM `instagram_posts` WHERE `is_deleted` = 1 AND `insta_profile_id` IN ('9876543210') )
)
)
)
As you can see I was using sub queries, but I was wondering is there a better way to write such queries?
I don't know if it's better, but I'd create a subquery that unions the necessary flag fields from your child tables and then just do a regular join to get the flag fields. If a flag field is not present for one of the tables, it can just be false.
Something like:
SELECT `f`.*
FROM `feed` `f`
JOIN
(
SELECT
1 AS `entity_type_id`
, fb_comment_id AS `object_id`
, is_locked
, is_hidden
, is_deleted
FROM
comments
UNION ALL
SELECT
4 AS `entity_type_id`
, fb_post_id AS `object_id`
, is_locked
, is_hidden
, is_deleted
FROM
posts
UNION ALL
SELECT
3 AS `entity_type_id`
, insta_comment_id AS `object_id`
, 0 AS is_locked
, 0 AS is_hidden
, is_deleted
FROM
instagram_comments
UNION ALL
SELECT
5 AS `entity_type_id`
, insta_post_id AS `object_id`
, 0 AS is_locked
, 0 AS is_hidden
, is_deleted
FROM
instagram_posts
) AS flag_summary ON (
flag_summary.entity_type_id = f.entity_type_id
AND flag_summary.object_id = f.object_id
)
Some tips:
Try to use INNER JOIN instead of WHERE + correlated queries. Create for example a table with all the tables in the sub-queries, and apply your filters. Do not forget to use PROCEDURE ANALYSE and index.
Avoid SELECT *, type all the variables you need.
Apply an EXPLAIN to know where you can improve your script.
Friends i'm using two queries with same concept in the below query i've used two order by function instead i would like to write only one order by function for the whole query using same attribute date_time DESC is it possible in mysql
(SELECT * FROM `chats` WHERE `chat_from` = '18' AND `chat_to` = '13' ORDER BY `date_time` DESC )
UNION
(SELECT * FROM `chats` WHERE `chat_from` = '13' AND `chat_to` = '18' ORDER BY `date_time` DESC )
Try This
SELECT * FROM `chats`
WHERE `chat_from` IN(18,13)
AND `chat_to`IN(18,13)
ORDER BY `date_time` DESC
select * from
(
SELECT * FROM `chats` WHERE `chat_from`in ('18','13') and `chat_to` in ('18','13')
)
t1 ORDER BY `date_time` DESC
You could do something like this:
SELECT * FROM `chats`
WHERE
(
`chat_from` = '18'
AND `chat_to` = '13'
)
OR
(
`chat_from` = '13'
AND `chat_to` = '18'
)
ORDER BY `date_time` DESC
If you need them to be distinct then you can use:
SELECT DISTINCT * FROM `chats`...
Have next query:
select `privmsgs_id`, `contact`, `privmsgs_date`, `contentType` from (
(
select max(`privmsgs_id`) as `privmsgs_id`, `contact`, max(`privmsgs_date`) as `privmsgs_date`, `contentType` from (
(
select `privmsgs_from_userid` as `contact`, `privmsgs_id`, `privmsgs_date`, 'message' as `contentType`
from `privmsgs_table`
where `privmsgs_to_userid` = 305026
) union (
select `privmsgs_to_userid` as `contact`, `privmsgs_id`, `privmsgs_date`, 'message' as `contentType`
from `privmsgs_table`
where `privmsgs_from_userid` = 305026
)
) as `tmp` group by `contact` order by `privmsgs_date` desc
) union (
select max(`privmsgs_id`) as `privmsgs_id`, `contact`, max(`privmsgs_date`) as `privmsgs_date`, `contentType` from (
(
select `from_userid` as `contact`, `id` as `privmsgs_id`, `date` as `privmsgs_date`, 'postcard' as `contentType`
from `postcards_table`
where `to_userid` = 305026
) union (
select `to_userid` as `contact`, `id` as `privmsgs_id`, `date` as `privmsgs_date`, 'postcard' as `contentType`
from `postcards_table`
where `from_userid` = 305026
)
) as `tmp1` group by `contact` order by `privmsgs_date` desc
)
) as `rTmp` order by `privmsgs_date` desc;
There are two tables tmp and tmp1 merged by union, but has doubled field contact:
privmsgs_id contact privmsgs_date contentType
21490780 7070 1315207813 message
21556868 7070 1315215266 postcard
21226460 7754 1312025735 message
21539085 15588 1314615528 postcard
21489812 15588 1315208838 message
So, I need only last records (message or postcard - does not matters) and id of this last record (there is the problem - i can get max(id) in messages and postcards separate, but can't do it in merged table):
privmsgs_id contact privmsgs_date contentType
21556868 7070 1315215266 postcard
21226460 7754 1312025735 message
21489812 15588 1315208838 message
Reason, why I don't do it by simplifying query is that I need a specific number of results, so, I can do this only by one query.
You have to group the result by contact and select the max privmsgd_id, and then select the info from only those privmsgd_id's.
Check GROUP BY for more info.
I have this small SQL query.
SELECT a.`id` , a.`title` , a.`date` ,
(
SELECT MAX( grade )
FROM tests
WHERE userid = 41
AND presid = a.`id`
) AS grade
FROM `presentations` a
WHERE a.`visible` = 1
AND `grade` >= 5
ORDER BY `grade` DESC
This gives me the error
1054 - Unknown column 'grade' in 'where clause'
But if i remove the 2nd last line, it works fine. I have tried to do AND a.grade and even give the tests table a name and append that name to grade but still no luck.
How can I use this inline query in a WHERE clause?
I have found that this works, but is it the only way?
SELECT a.`id` , a.`title` , a.`date` ,
(
SELECT MAX( grade )
FROM tests
WHERE userid = 41
AND presid = a.`id`
) AS grade
FROM `presentations` a
WHERE a.`visible` = 1
AND (
SELECT MAX( grade )
FROM tests
WHERE userid = 41
AND presid = a.`id`
) >= 5
ORDER BY `grade` DESC
Sql statements are somewhat evaluated in the following order:
FROM
WHERE
SELECT
GROUP
HAVING
ORDER
So things you define in the SELECT-clause are not available in the WHERE-clause. You would need to put that constraint into a HAVING-clause:
SELECT a.`id` , a.`title` , a.`date` ,
(
SELECT MAX( grade )
FROM tests
WHERE userid = 41
AND presid = a.`id`
) AS grade
FROM `presentations` a
WHERE a.`visible` = 1
HAVING `grade` >= 5
ORDER BY `grade` DESC
SELECT a.`id` , a.`title` , a.`date` ,
(
SELECT MAX( grade )
FROM tests
WHERE userid = 41
AND presid = a.`id`
) AS grade
FROM `presentations` a
WHERE a.`visible` = 1
HAVING `grade` >= 5
ORDER BY
`grade` DESC