I got a message system with a table like this
ID AID FID MESSAGE
1 1 2 Hi
2 2 1 Hi, how are you?
3 3 1 Hello One, what's up?
4 1 2 I'm fine, how about you?
ID is the unique Message-ID, AID the ID of the transmitter and FID the ID of the receiver of the message. Message is the message itself.
I want to select all unique combinations with the highest ID, but only once, so the output looks like this:
ID AID FID MESSAGE
3 3 1 Hello One, what's up?
4 1 2 I'm fine, how about you?
The problem is that I can't select properly as AID=2 and FID=1 is as unique as FID=1 and AID=2, but it's in fact the same conversation.
Any suggestions would be very appreciated!
EDIT: The ID of the user currently logged in is $_SESSION["said"]
EDIT 2: The message system should look something like this, displaying the last message sent in a conversation (just like on facebook).
http://i.stack.imgur.com/Jmvfr.jpg
here is query:
select * from table
where ID in (
select max(id) as maxid
from table
group by LEAST(aid, fid), GREATEST(aid, fid)
)
if you want to select last message only from/to $_SESSION["said"], you can use:
$query = "select * from table
where ID in (
select max(id) as maxid
from table
where aid = ".$_SESSION["said"]." or fid = ".$_SESSION["said"]."
group by LEAST(aid, fid), GREATEST(aid, fid)
)";
it will give you list of all latest messages sent to/from this user
Might have to modify it depending on your RDBMS (MySQL vs. Microsoft SQL Server, etc.), but the following code should get you headed in the right direction... You'll probably need to modify the string concatenation to use some sort of cast or something, but, like I said, it's RDBMS-dependent.
Pseudocode:
select *
from have
where id in
(
select max(id) as topid
from have
group by case when aid<fid then aid+'|'+fid else fid+'|'+aid end
)
Related
I am building a mobile chat web application and I have stuck in a problem. Coming straight to the issue, I have a screen which displays messages list from all users (like WhatsApp). I want to display the last message sent or received between the users in the list (as in the screenshot below). My current query extracts the message from the 1st row for all users right now. That's not what I want.
Little more brief details of what is happening
As you can see in messages table, the fields msg_from and msg_to represents the sender and the receiver respectively. In my data, the messages are transferred between user 1 & 8 and user 1 & 11. For user 1 & 8 the last record fetched should be record 9 which has msg_message Are you there? and similarly, for user 1 & 11 the last record to be fetched would be record 10 which has msg_message Would you like to join?. But currently, for all users the record getting fetched is the 1st record with message How are you?. What changes should my query have to get the desired result? Please have a look at the fiddle below.
Fiddle Here: DB Fiddle
I learned a lot from researching in order to solve this. When grouping, groupBy will take the first row of non-grouped columns (suck as msg_message), so we may order it when joining with the help of a subquery, just like this:
SELECT swp_by, swp_to, msg_from, msg_to, mem_fname, mem_lname, mem_last_activity, msg_message, GREATEST(MAX(msg_time), swipes.swp_date) as msgdate, COUNT(msg_id) as msgcnt FROM swipes
LEFT JOIN
(
SELECT * FROM messages order by msg_time desc -- this is the magic, we use this subquery to order before grouping
)
messages ON
((
messages.msg_from = swipes.swp_by
AND messages.msg_to = swipes.swp_to)
OR (messages.msg_from = swipes.swp_to
AND messages.msg_to = swipes.swp_by
))
solution is in your fiddle: https://www.db-fiddle.com/f/xnh4jiUb8rDLFHpL2gWHrM/5
I think I got expected output
I am struggling with this for several hours already. I am coding a messaging system and my table has the following columns:
ID(UUID) | from_user_id(uuid) | to_user_id(uuid) | subject | body | created_at
In inbox page I need to get the results grouped by subject+from_user_id. That is required because if the subject is the same then it is a separate dialogue and from_user_id should be concatenated with subject to make sure that if the other user will send a message with the same subject it will not be merged with other dialogue.
Second thing is that for each group I need to get the first message to show as dialogue cover message. It would be pretty easy to solve problem if I has normal ID's used but instead I am using UUID,s so I cannot use min or max for them. So I need to use created_at field to determine which row is the last.
I have tried many different approaches but I cannot get the result I need. Maybe anybody had similar problem before and has a solution?
select msg.id, msg.body, msg.created_at, concat(msg.from_user_id, msg.subject) as concat
from messages as msg
where msg.to_user_id = '8d99eb39-24f8-4dd6-b984-9505cd3eb6b6'
order by msg.created_at desc limit 10 offset 0
Basically you need the subquery to identify the last message in each thread,
and then select against that subquery to get the details from each of those last messsages
select * from messages
where to_user_id = 'jim'
and concat(from_user_id, subject, created_at) in (
select max(concat(from_user_id, subject, created_at))
from messages
where to_user_id = 'jim'
group by concat(from_user_id, subject))
I've encountered this problem for a while and I can't seem to find the right answer on google. I don't know if maybe I'm just unlucky.
Anyway, how can I get row number from a specific record I input from a PHP text field, for example:
ID NAME
11111 john
11112 roger
11113 ellis
11114 jack
11115 wendy
So if I input 11113, the output will be like "this ID is at number 3".
Here is my code:
$id=$_POST['id'];
$query="SELECT COUNT(*) from employee where id like '%$id%'";
$num=mysql_query($query);
echo "this ID is at number $num";
Can anyone point out where did I go wrong?
Here is a query example of how you can do it without adding another column for count:
SELECT e.*,b.count FROM employee as e, (SELECT COUNT(*) as count FROM employee WHERE id <= 3) as b WHERE e.id = 3
Using another select query to count all the rows with id smaller than the id requested
Or if you only want the offset of the row without its data:
SELECT COUNT(*) as count FROM employee WHERE id <= 3
At first, you should select * from the employee table
Then parse the result to array,
Scan the above array (step2) and find your value (11113)
If (3) is found, then you can return array index.
First thing:
You're using old PHP-method for database, use PDO
If you wan't to get the last insert ID, it's possible to catch it with PDO
And I don't understand your SQL, because you want to get an ID, by filtering with the ID? And when your ID is an INTEGER/NUMBER, than your statement is senseless.
I am creating php messaging system based with conversations. And I got a problem.
I have a table with columns: id, to, from, msgtext, timesent, viewed, deleted.
I want to select just one conversation between to and from. Take a notice that if user to can write a message to user from.
How to select seperate conversations?
I am trying with this SQL:
SELECT to, from FROM pms WHERE to='$userid' OR from = $userid group by to ORDER by id desc LIMIT 50
But this does not work another way. Because if user1 wrote message to user2, and user2 replied to user1, and again if user1 replies and user2 replies, i see as 2 conversations, but it should be as one conversation.
It should be like this:
User sends a message to some other user. It should show in conversations list That other user's name.
If user gets a message from another user, he should see his name in the conversation list.
Try this code
SELECT `id`, `to`, `from`, `msgtext`, `timesent`, `viewed`, `deleted` FROM table_name
WHERE `to` = 'username_to' AND `from` = 'username_from'
LIMIT 1
OFFSET 0
If you understand the concept behind you will realize that you need to play only with OFFSET number to get the next record.
P.S. A shortcut to the LIMIT & OFFSET lines above is:
LIMIT 0, 1
Also, when you ask something on Stack Overflow you are supposed to show what you have tried, and ask why is not working, instead of simply asking for code.
I have a MySQL query that results in something like this:
person | some_info
==================
bob | pphsmbf24
bob | rz72nixdy
bob | rbqqarywk
john | kif9adxxn
john | 77tp431p4
john | hx4t0e76j
john | 4yiomqv4i
alex | n25pz8z83
alex | orq9w7c24
alex | beuz1p133
etc...
(This is just a simplified example. In reality there are about 5000 rows in my results).
What I need to do is go through each person in the list (bob, john, alex, etc...) and pull out a row from their set of results. The row I pull out is sort of random but sort of also based on a loose set of conditions. It's not really important to specify the conditions here so I'll just say it's a random row for the example.
Anyways, using PHP, this solution is pretty simple. I make my query and get 5000 rows back and iterate through them pulling out my random row for each person. Easy.
However, I'm wondering if it's possible to get what I would from only a MySQL query so that I don't have to use PHP to iterate through the results and pull out my random rows.
I have a feeling it might involve a BUNCH of subselects, like one for each person, in which case that solution would be more time, resource and bandwidth intensive than my current solution.
Is there a clever query that can accomplish this all in one command?
Here is an SQLFiddle that you can play with.
To get a random value for a distinct name use
SELECT r.name,
(SELECT r1.some_info FROM test AS r1 WHERE r.name=r1.name ORDER BY rand() LIMIT 1) AS 'some_info'
FROM test AS r
GROUP BY r.name ;
Put this query as it stands in your sqlfiddle and it will work
Im using r and r1 as table alias names. This will also use a subquery to select a random some_info for the name
SQL Fiddle is here
My first response would be to use php to generate a random number:
$randId = rand($min, $max);
Then run a SQL query that only gets the record where your index equals $randID.
Here is the solution:
select person, acting from personel where id in (
select lim from
(select count(person) c, min(id) i, cast(rand()*(count(person)-1) +min(id)
as unsigned) lim from personel group by person order by i) t1
)
The table used in the example is below:
create table personel (
id int(11) not null auto_increment,
person char(16),
acting char(19),
primary key(id)
);
insert into personel (person,acting) values
('john','abd'),('john','aabd'),('john','adbd'),('john','abfd'),
('alex','ab2d'),('alex','abd3'),('alex','ab4d'),('alex','a6bd'),
('max','ab2d'),('max','abd3'),('max','ab4d'),('max','a6bd'),
('jimmy','ab2d'),('jimmy','abd3'),('jimmy','ab4d'),('jimmy','a6bd');
You can limit the number of queries, and order by "rand()" to get your desired result.
Perhaps if you tried something like this:
SELECT name, some_info
FROM test
WHERE name = 'tara'
ORDER BY rand()
LIMIT 1