How do I combine these two Select queries with an OR case - mysql

I want to select all rows where WHERE (uid = {$uid} OR uid = **HERE** ) where **HERE** is the cids retreived from query 2 below.
Query 1:
SELECT * FROM `t_activities`
WHERE (`uid` = {$uid} OR `uid` = **HERE** )
AND `del` = 0
GROUP BY `fid`
ORDER BY `time` DESC
LIMIT 10
And Query 2:
SELECT `cid` FROM `t_con` WHERE `uid` = {$uid} AND `flag` = 1

SELECT * FROM `t_activities`
WHERE (`uid` = {$uid} OR `uid` in (SELECT `cid`
FROM `t_con`
WHERE `uid` = {$uid} AND `flag` = 1))
AND `del` = 0
GROUP BY `fid`
ORDER BY `time` DESC
LIMIT 10

You can do this as a join as well:
SELECT *
FROM `t_activities` ta left outer join
(SELECT `cid`
FROM `t_con`
WHERE `uid` = {$uid} AND `flag` = 1)
) tc
on ta = tc.cid
WHERE (`uid` = {$uid} OR tc.`uid` is not null) AND `del` = 0
GROUP BY `fid`
ORDER BY `time` DESC
LIMIT 10
By the way, as a SQL statement the "GROUP BY fid" looks very strange. This is allowed in mysql, but I think it is a bad practice. It is much better to be explicit about what you are doing:
SELECT fid, min(<field1>) as Field1, . . .
This helps prevent mistakes when you go back to the query or try to modify it.

Related

How get the least ID from table after GROUP BY

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.

SQL query to select all rows with max column value

CREATE TABLE `user_activity` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL,
`type` enum('request','response') DEFAULT NULL,
`data` longtext NOT NULL,
`created_at` datetime DEFAULT NULL,
`source` varchar(255) DEFAULT NULL,
`task_name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
);
I have this data:-
Now I need to select all rows for user_id=527 where created_at value is the maximum. So I need the last 3 rows in this image.
I wrote this query:-
SELECT *
FROM user_activity
WHERE user_id = 527
AND source = 'E1'
AND task_name IN ( 'GetReportTask', 'StopMonitoringUserTask' )
AND created_at = (SELECT Max(created_at)
FROM user_activity
WHERE user_id = 527
AND source = 'E1'
AND task_name IN ( 'GetReportTask',
'StopMonitoringUserTask' ));
This is very inefficient because I am running the exact same query again as an inner query except that it disregards created_at. What's the right way to do this?
I would use a correlated subquery:
SELECT ua.*
FROM user_activity ua
WHERE ua.user_id = 527 AND source = 'E1' AND
ua.task_name IN ('GetReportTask', 'StopMonitoringUserTask' ) AND
ua.created_at = (SELECT MAX(ua2.created_at)
FROM user_activity ua2
WHERE ua2.user_id = ua.user_id AND
ua2.source = ua.source AND
ua2.task_name IN ( 'GetReportTask', 'StopMonitoringUserTask' )
);
Although this might seem inefficient, you can create an index on user_activity(user_id, source, task_name, created_at). With this index, the query should have decent performance.
Order by created_at desc and limit your query to return 1 row.
SELECT *
FROM user_activity
WHERE user_id = 527
AND source = 'E1'
AND task_name IN ( 'GetReportTask', 'StopMonitoringUserTask' )
ORDER BY created_at DESC
LIMIT 1;
I used EverSQL and applied my own changes to come up with this single-select query that uses self-join:-
SELECT *
FROM user_activity AS ua1
LEFT JOIN user_activity AS ua2
ON ua2.user_id = ua1.user_id
AND ua2.source = ua1.source
AND ua2.task_name IN ( 'GetReportTask', 'StopMonitoringUserTask' )
AND ua1.created_at < ua2.created_at
WHERE ua1.user_id = 527
AND ua1.source = 'E1'
AND ua1.task_name IN ( 'GetReportTask', 'StopMonitoringUserTask' )
AND ua2.created_at IS NULL;
However, I noticed that the response times of both queries were similar. I tried to use Explain to identify any performance differences; and from what I understood from its output, there are no noticeable differences because proper indexing is in place. So for readability and maintainability, I'll just use the nested query.

Using common order by for both query with union function

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`...

MySQL How to select mulipie rows then send to another query

I hava a Table ,I can use
SELECT `event_id` FROM `event` WHERE 1
to get mulipie rows event_id , and I put event_id in this query
SET #event_id = XXXX;
SELECT * FROM(
(SELECT `event_id`,`author_id`,`latitude`,`longitude`,`type`,`rate`,`description`,`photo_id`, UNIX_TIMESTAMP(`timestamp`) AS `timestamp`
FROM `event`) AS `event`,
(SELECT COUNT(*) AS `thumb_up_count` FROM `thumb_event` WHERE `event_id` = #event_id AND `thumb_state` = 1) AS `thumb_up_count`,
(SELECT COUNT(*) AS `thumb_down_count` FROM `thumb_event` WHERE `event_id` = #event_id AND `thumb_state` = 2) AS `thumb_down_count`,
(SELECT IFNULL((SELECT `thumb_state` FROM `thumb_event` WHERE `event_id` = #event_id AND `user_id` = ?) , 0) AS `thumbed`) AS `thumbed`,
(SELECT COUNT(*) AS `comment_count` FROM `event_comment` WHERE `event_id` = #event_id) AS `comment_count`
) WHERE `event_id` = #event_id;
I can use SET #event_id = 0000; to set event_id , but how I can put all event_id from select in that query
If i understoods, maybe what you need it's an IN clause:
WHERE `event_id` IN (SELECT `event_id` FROM `event` WHERE 1);

WHERE subquery = 0

I'm trying to write a query which checks if a question have any answers which are marked as a correct answer.
Now I tried using a subquery and I tried setting the subquery as a user-defined variable.
Test #1
SELECT
#id := `id` AS `id`, `title`
FROM
`eu_questions`
WHERE
CAST((SELECT COUNT(`id`) FROM `eu_answers` WHERE `question_id` = #id AND `correct` = 1) AS UNSIGNED) = 0
ORDER BY `id` ASC
LIMIT 0, 10;
Test #2
SELECT
#id := `id` AS `id`,
#count_correct := (SELECT COUNT(`id`) FROM `eu_answers` WHERE `question_id` = #id AND `correct` = 1) AS `count_correct`
FROM
`eu_questions`
WHERE
CAST(#count_correct AS UNSIGNED) = 0
ORDER BY `id` ASC
LIMIT 0, 10;
The queries doesn't result in errors, they simply return 0 results and I don't get why? I tried comparing the user-defined variable while selected and that seems to work and return the correct value, so that simply bugs me even more!
This is how I checked it:
SELECT
#id := `id` AS `id`,
#count_correct := (SELECT COUNT(`id`) FROM `eu_answers` WHERE `question_id` = #id AND `correct` = 1) AS `count_correct`,
CAST(#count_correct AS UNSIGNED) = 0
FROM
`eu_questions`
ORDER BY `id` ASC
LIMIT 0, 10;
Answer - Thanks to Branko Dimitrijevic
I used his example and ended up with this query, which fits my needs.
SELECT *
FROM `eu_questions`
WHERE
1 != ANY (
SELECT COUNT(`id`)
FROM `eu_answers`
WHERE `question_id` = `eu_questions`.`id`
AND `correct` = 1
)
ORDER BY `id` ASC
LIMIT 0, 10;
Here you go:
SELECT *
FROM eu_questions
WHERE 1 = ANY (
SELECT correct
FROM eu_answers
WHERE question_id = eu_questions.id
);
[SQL Fiddle]
Add extra WHERE and LIMIT conditions as desired...
You can LEFT JOIN on the answers table and use a where clause to keep only questions without correct answer.
SELECT
`eu_questions`.`id`, `title`
FROM
`eu_questions`
LEFT JOIN
`eu_answers` ON `question_id` = `eu_questions`.`id` AND `correct` = 1
WHERE
`eu_questions`.`id` IS NULL
ORDER BY `eu_questions`.`id` ASC
LIMIT 0, 10;