Currently, I am trying to select a list of posts from people who are friends and/or are being followed by the current user. However, I am running into an issue when I add in the second statement for the following table.
SELECT * FROM login, threads WHERE login.id=threads.poster_id AND deleted=0 AND login.id
IN ((SELECT CASE WHEN second_id=? THEN first_id ELSE second_id END FROM friends WHERE first_id=? OR second_id=?)
AND (SELECT CASE WHEN follower=? THEN following ELSE follower END FROM following WHERE follower=?))
ORDER BY threads.posted DESC LIMIT 20
Just use two explicit IN conditions with the two subqueries:
SELECT *
FROM login
INNER JOIN threads
ON login.id = threads.poster_id
WHERE
deleted = 0 AND
(login.id IN (SELECT CASE WHEN second_id=? THEN first_id ELSE second_id END
FROM friends WHERE first_id=? OR second_id=?) AND
login_id IN (SELECT CASE WHEN follower=? THEN following ELSE follower END
FROM following WHERE follower=?))
ORDER BY
threads.posted
DESC LIMIT 20;
This may fix the syntax errors and even give you the output you expect, but I also feel that we may be able to clean up the query a bit more. Sample data would go a long way towards that end.
Related
I have been trying to do this in many ways suggested.
Note: we do not want aggregate function or Partition since this is just a small part of whole Stored procedure and this is client requirement to not have it, so not in option and not possible duplicate of other existing answers / questions
I have a messages table, which has a column from and to, a foreign key to the user table, basically which user sends to whom at simplest. I also have other columns which are isSnoozed and snoozeAt for if the message is snoozed.
So the ordering is according to case. If messages is snoozed then consider snoozeAt time to Order or if not then consider sendAt. (right now we can ignore this condition while ordering, But I mentioned this since we cannot take simply MAX(id) )
I need to get recent most message from messages group by from user id
messages table like :
id -- to -- from -- isSnoozed -- snoozedAt -- sendAt ...
What I tried :
select * from ( select * from messages order by sendAt DESC) as TEMP GROUP BY TEMP.from
I tried many similar approaches but none worked.
I wasted many paid hours but can't find an approach which meets my exact requirement
NOTE: Please ignore typo in query if any, since I cant type in exact query table and names, So i typed in directly here
I figured this out by doing something like this, which could be explained in a simplified way:
select * from message where message.id in (
select
( select id from message where message.from = user.id order by CASE isSnoozed WHEN 0 THEN sendAt ELSE snoozeAt END DESC limit 1) as id
from user where user.id in ( select friends.`whoIsAdded` from friends where friends.`whoAdded` = myId)
) order by CASE isSnoozed WHEN 0 THEN sendAt ELSE snoozeAt END DESC
If I understand correctly, you just want the largest value in one of two columns. Assuming the values are never NULL, you can use greatest():
select m.*
from messages m
where greatest(m.sendAt, m.snoozedAt) =
(select max(greatest(m2.sendAt, m2.snoozedAt))
from messages m2
where m2.from = m.from
);
If the columns can be NULL, then you can use coalesce() to give them more reasonable values.
I have a problem with my SQL query. I want to display the last message for a user. So, i use the method "GROUP BY" but he don't display the LAST message.
This is my first query:
SELECT `messages`.*, `conversations`.*
FROM `messages` JOIN `conversations` ON `conversations`.`cNUM` = `messages`.`mCONV_NUM`
WHERE `cUSER2` = '2'
GROUP BY `messages`.`mCONV_NUMn`
I try to follow this subject: ORDER BY date and time BEFORE GROUP BY name in mysql (and a lot of other)
And i have this:
SELECT `messages`.*, `conversations`.*
FROM (SELECT mTIME
FROM `messages`
ORDER BY mTIME desc) AS M
JOIN `conversations` ON `conversations`.`cNUM` = `messages`.`mCONV_NUM`
WHERE `cUSER2` = '2'
GROUP BY `messages`.`mCONV_NUMn`
And i have this error: Table 'messages' unknown.
So.. i need your help guys
You gave an alias M to your messages table, as isaace said you shall refer to it as 'M' in the rest of the query as this temporary name lasts for the whole duration of the query and FROM is an initial phase in the query processing.
We are talking about something called logical query processing, this means that in
your query FROM statement is evaluated and processed initially and
then the rest of query.
In LQP terms queries will be processed in the following order.
FROM --> WHERE --> GROUP BY --> HAVING --> SELECT --> ORDER BY
(Of course I left out some phases but you get the idea)
Also you can use LIMIT to get the last message for a user.
Just add LIMIT 1 at the end.
You say you want the last message for a user, but it seems you really want several messages, namely their last message of each conversation they took part in.
For the lack of CROSS APPLY and window functions in MySQL, you need a query that does a lot of lookups to get the last message per conversation:
select *
from conversations c
join messages m on m.mconv_num = c.cnum
where c.cuser2 = 2
and not exists
(
select *
from messages m2
where m2.mconv_num = m.mconv_num
and m2.mtime > m.mtime
);
I want to display the last message for a user.
You get the one last message for a user with LIMIT:
select *
from conversations c
join messages m on m.mconv_num = c.cnum
where c.cuser2 = 2
order by m.mtime
limit 1;
I'm stucked in a MySQL problem that I was not able to find a solution yet. I have the following query that brings to me the month-year and the number new users of each period in my platform:
select
u.period ,
u.count_new as new_users
from
(select DATE_FORMAT(u.registration_date,'%Y-%m') as period, count(distinct u.id) as count_new from users u group by DATE_FORMAT(u.registration_date,'%Y-%m')) u
order by period desc;
The result is the table:
period,new_users
2016-10,103699
2016-09,149001
2016-08,169841
2016-07,150672
2016-06,148920
2016-05,160206
2016-04,147715
2016-03,173394
2016-02,157743
2016-01,173013
So, I need to calculate for each month-year the difference between the period and the last month-year. I need a result table like this:
period,new_users
2016-10,calculate(103699 - 149001)
2016-09,calculate(149001- 169841)
2016-08,calculate(169841- 150672)
2016-07,So on...
2016-06,...
2016-05,...
2016-04,...
2016-03,...
2016-02,...
2016-01,...
Any ideas: =/
Thankss
You should be able to use a similar approach as I posted in another S/O question. You are on a good track to start. You have your inner query get the counts and have it ordered in the final direction you need. By using inline mysql variables, you can have a holding column of the previous record's value, then use that as computation base for the next result, then set the variable to the new balance to be used for each subsequent cycle.
The JOIN to the SqlVars alias does not have any "ON" condition as the SqlVars would only return a single row anyhow and would not result in any Cartesian product.
select
u.period,
if( #prevCount = -1, 0, u.count_new - #prevCount ) as new_users,
#prevCount := new_users as HoldColumnForNextCycle
from
( select
DATE_FORMAT(u.registration_date,'%Y-%m') as period,
count(distinct u.id) as count_new
from
users u
group by
DATE_FORMAT(u.registration_date,'%Y-%m') ) u
JOIN ( select #prevCount := -1 ) as SqlVars
order by
u.period desc;
You may have to play with it a little as there is no "starting" point in counts, so the first entry in either sorted direction may look strange. I am starting the "#prevCount" variable as -1. So the first record processed gets a new user count of 0 into the "new_users" column. THEN, whatever was the distinct new user count was for the record, I then assign back to the #prevCount as the basis for all subsequent records being processed. yes, it is an extra column in the result set that can be ignored, but is needed. Again, it is just a per-line place-holder and you can see in the result query how it gets its value as each line progresses...
I would create a temp table with two columns and then fill it using a cursor that
does something like this (don't remember the exact syntax - so this is just a pseudo-code):
#val = CURSOR.col2 - (select col2 from OriginalTable t2 where (t2.Period = (CURSOR.Period-1) )))
INSERT tmpTable (Period, NewUsers) Values ( CURSOR.Period, #val)
So I have and email data base and where each email send has it's own line. I'm trying to figure out how many times each user is being sent to. So I'm using this query to find out out how many times each user has been mailed.
SELECT count(`id`)
FROM `bde_export`
WHERE `record.type` = 'senttomta'
GROUP BY `user.id`
Now what I'm trying to do is count that count so I get a summary telling me how many users have been mailed 1,2,3,4 times and so on. I know that is a bit confusing please let me know if clarification is needed.
well why dont you try another count???
like this
SELECT count(`tmp`.*) FROM (
SELECT count(`id`)
FROM `bde_export`
WHERE `record`.`type` = 'senttomta'
GROUP BY `user`.`id`
) `tmp`
i dont know what exactly is your problem but with current explanation i think it works. i just copied your query and didnt change that.
but if it doesn't satisfy your meets, i suggest you to try this:
SELECT sum(`tmp`.`count`) FROM (
SELECT count(`id`) AS `count`
FROM `bde_export`
WHERE `record`.`type` = 'senttomta'
GROUP BY `user`.`id`
) `tmp`
You can do this with two selection statements.. try something like this..
SELECT SUM(s.EmailCount) as 'TotalCount', s.id
FROM
(
SELECT COUNT(id) as 'EmailCount', id
FROM
GROUP BY user.id
) AS s
GROUP BY s.EmailCount
Basically you do your initial select statement and select the sum of the initial count
I have the following mysql query
SELECT *, DATE(file_created) as created, s.disk_id, s.url,
(SELECT COUNT(*) FROM Comments WHERE cmt_type=1 AND file_id=cmt_id) as comments FROM (files, servers s)
WHERE usr_id=1 AND (file_name LIKE CONCAT('%','sample','%') OR file_descr LIKE CONCAT('%','sample','%'))
ORDER BY file_created DESC
When I run this query I get 40 records back if there is atleast one record matching the query and all the 40 results will be the same record with the same ID!
I cant see any obvious problems with the query so not sure what is causing this problem.
Here is your query, formatted so it is better understood:
SELECT *, DATE(file_created) as created, s.disk_id, s.url,
(SELECT COUNT(*) FROM Comments WHERE cmt_type=1 AND file_id=cmt_id) as comments
FROM files, servers s
WHERE usr_id = 1 AND
(file_name LIKE CONCAT('%','sample','%') OR file_descr LIKE CONCAT('%','sample','%'))
ORDER BY file_created DESC
You have no join condition between files and server. No surprise that you ware getting duplicates. The comma in the from clause means cross join or "create a cartesian product". Simply do not use commas in the from clause. A simple rule that will save future frustration.
So, if the file has a server id, then you might want:
SELECT *, DATE(file_created) as created, s.disk_id, s.url,
(SELECT COUNT(*) FROM Comments WHERE cmt_type=1 AND file_id=cmt_id) as comments
FROM files JOIN
servers s
ON files.serverid = s.serverid
WHERE usr_id = 1 AND
(file_name LIKE CONCAT('%','sample','%') OR file_descr LIKE CONCAT('%','sample','%'))
ORDER BY file_created DESC
You are joining two tables (files and servers) but I can't see anything to restrict the servers, so it's going to repeat each matching line of files with each matching line of servers (all of them, I suppose).
I think,
First, you should add joining criteria for tables like files.server_id = servers.id at the where statement.
Second, you should change file_id=cmt_id statement to comments.file_id = file_id for correct counts.
SELECT *, DATE(file_created) as created, s.disk_id, s.url, (SELECT COUNT(*) FROM Comments WHERE cmt_type=1 AND Comments.file_id = files.file_id) as comments
FROM (files, servers s)
WHERE files.file_server_id = s.server_id AND usr_id=1 AND (file_name LIKE CONCAT('%','sample','%') OR file_descr LIKE CONCAT('%','sample','%'))
ORDER BY file_created DESC
I hope, it works.