SQL order by datetime - php

I have 3 tables:
chatmsgs with the columns
itemid, sender, receiver, message, datetime, status
users with the columns
userid, username, phone, email, avatar, online, password
items with the columns
itemid, category, make, type, mainimage, title, price
I am trying to create a list of chats between the current user and some other user on a specific item and order the list by the chat with the most recent message (based on timestamp).
My current query is this:
<?php
$currentuser=$_SESSION['userid'];
$sqls="SELECT DISTINCT itemid,sender,receiver FROM chatmsgs ORDER BY datetime DESC";
$results=mysqli_query($db,$sqls);
while($rows=mysqli_fetch_assoc($results)){
$itemid=$rows['itemid']; $sender=$rows['sender']; $receiver=$rows['receiver']; #$message=$rows['message'];
$sqll="SELECT * FROM items WHERE itemid = '".$itemid."'";
$resultt=mysqli_query($db,$sqll);
while($roww=mysqli_fetch_assoc($resultt)){
$itemid=$roww['itemid']; $title=$roww['title']; $status=$roww['status']; $userid=$roww['userid'];
#$sqlx = "SELECT * FROM users WHERE userid = '".$userid."' AND userid != '".$currentuser."'";
$sqlx = "SELECT * FROM users WHERE userid = '".$userid."'";
$resultx=mysqli_query($db,$sqlx);
while($rowx=mysqli_fetch_assoc($resultx)){
$avatar=$rowx['avatar']; $username=$rowx['username']; $user=$rowx['userid'];
$sq="SELECT * FROM chatmsgs WHERE itemid = '".$itemid."' AND ((sender = '".$sender."' AND receiver = '".$receiver."') OR (sender = '".$receiver."' AND receiver = '".$sender."')) ORDER BY id ASC";
$resul=mysqli_query($db,$sq);
while($ro=mysqli_fetch_assoc($resul)){
$message=$ro['message'];
$ldate=date_format(date_create($ro['datetime']),"M d");
}
echo '
<li>
My list item
</li>
';
}
}
}
?>
I have so far been able to list the chats but I'm unable to sort it.
I know this is not the best way to do this but it's the only way I know how. Would appreciate better ways.

I would start by getting all chat messages associated with just the given user in question. By doing a UNION as both the sender and receiver, if you have an index on each column respectively, the query should be very fast. From that, you can now query the rest of the data all in one quick run something like below.
You can order the data by whatever... From your while loops, it looked like you were doing all things for a given Item ID before moving to the next, so I have the order by clause by the item ID. Now, from within each item, I have ordered by the date/time in descending order with newest chat message first, but you could change that.
Another possible change is you may want the items displayed based on which is the MOST RECENT item that has chat activity first. For example, if a chat from someone was from a year ago, vs one that was just this week, you might want the current first. I would alter the query slightly.
select
um.itemid,
cm.message,
cm.datetime,
cm.status,
uFrom.username senderName,
uFrom.avatar senderAvatar,
uTo.userName receiptName,
uTo.avatar receiptAvatar,
i.category,
i.make,
i.type,
i.mainImage,
i.title,
i.price
from
( select distinct itemid
from chatMsgs
where sender = $currentuser
UNION
select distinct itemid
from chatMsgs
where receiver = $currentuser ) UM
JOIN ChatMsgs ch
on UM.ItemID = ch.ItemID
JOIN Users uFrom
on ch.sender = uFrom.userid
JOIN Users uTo
on ch.receiver = uTo.userid
JOIN Items i
on ch.itemID = i.itemid
order by
um.itemid,
cm.datetime desc
The format is not in php format, but you can see the only place you need a parameter is where the user ID is. All the details come along in the results including the respective avatars, titles, messages, from user and recipient user too. Take what you need in one query.
I would expect two individual indexes on your chatmsgs table. One on the sender, one on the receiver.

Related

Wordpress Shortcode: Get data from 3 tables, compare and filter/show (PHP, MYSQL)

I have been trying everything to achieve this task, but it is rather difficult.
I am trying to do this in Wordpress as shortcode.
The shortcode itself is fine, I don't need any help with that, but just the output here which is giving me a difficult time. The Shortcode has an attribute that can be used to show the ID of the list using $listID
As an example, I have 3 database tables.
complete (variables: id, itemID, listID, userID)
item (variables: id, listID, description, creator)
list (id, name)
What I need to do is show a list from a shortcode variable, in this case database id 1 for the list. Then show the items in that list (using listID in item variable as well as wordpress user function to grab the ID of the logged in user and compare it to the creator variable of the item) -- and have the completed marked in there (using itemID, listID and the logged in user to wordpress to compare with the userID).
I tried this for SQL, but it returned nothing
global $wpdb;
$q_checked = $wpdb->prefix.'checked';
$q_item = $wpdb->prefix.'items';
$q_list = $wpdb->prefix.'list';
$q_results = $wpdb->get_results("
SELECT * FROM (($q_item INNER JOIN $q_list ON $q_item.listID = $listID)
INNER JOIN $q_checked ON $q_list.id = $q_checked.listID;
I also tried this with sql but it only shows from the two tables and not the third, and it will show all instead of excluding the completed.
$q_items = $wpdb->prefix.'items';
$q_checked = $wpdb->prefix.'checked';
$q_result = $wpdb->get_results("SELECT $q_items.title, $q_checked.userID FROM $q_items INNER JOIN $q_checked ON $new_items.id = $q_checked.itemID");
I thought about using a foreach, but none of the above would work well with that would it? Since you can only use one result. Maybe if I could do 2 separate foreach, 1 for the items in the list but exclude them if the id of the item matches the itemID in the completed database? Then do another foreach that would show the completed items for that list.
<?php foreach($q_result as $i ) {
$userID = $i->userID;
$itemNAME = $i->title; ?>
<?php if($userID === ''.$current_user->ID.'') { ?> <?php echo $itemNAME; ?><?php }?>
<?php }; ?>
I honestly think I should rethink the entire thing. Maybe I am overcomplicating it?
This is a fairly standard MySQL query:
SELECT i.description, i.creator,
IF(c.id IS NOT NULL, 'Completed', 'Not Completed') AS status
FROM item i
LEFT JOIN complete c
ON c.itemID = i.id AND
c.listID = i.listID AND
c.userID = ?
WHERE i.listID = ?
The ? placeholders represent parameters that you would bind to the current user ID and list ID supplied by your shortcode.
This performs a left join from items to completed items, and checks for a match on all join conditions. If a match is found, then a row will exist in c, and we mark the item as completed. Otherwise, the c.id will be NULL and we mark it as not completed.

How to apply conditions in mysqli query

I want to apply conditions with my query like i want to interchange one column's value to another column. Here is my query and now i am not getting how to apply
mysqli_query($connect, "
select
user_pro.User_No,
user_pro.Fist_Name,
user_pro.Last_Name,
user_pro.Designation,
user_pro.Profile,
user_pro.ProfileDP,
user_fndrst.Frnd_SNo,
user_fndrst.Rqst_Sender,
user_fndrst.Rqst_Receiver,
user_fndrst.Rqst_Status
from
user_profile INNER JOIN user_fndrst ON user_pro.User_No = user_fndrst.Rqst_Sender
WHERE
user_fndrst.Rqst_Status='1' AND
user_fndrst.Rqst_Receiver='$user_id'
ORDER BY Frnd_SNo DESC
");
Here "user_pro" table contains user's details, "user_fndrst" table contains user's friend request status and $user_id is user's logined id. Here I want that IF user_fndrst.Rqst_Receiver='$user_id' THEN user_fndrst.Rqst_Receiver value change to user_fndrst.Rqst_Sender.
For this I have stuck with user friend request status fetching from table "user_fndrst".
It seems your query has some problems. Use this:
SELECT
user_pro.User_No, user_pro.Fist_Name, user_pro.Last_Name, user_pro.Designation, user_pro.Profile, user_pro.ProfileDP, user_fndrst.Frnd_SNo, user_fndrst.Rqst_Sender, user_fndrst.Rqst_Receiver, user_fndrst.Rqst_Status
FROM
user_profile user_pro
INNER JOIN user_fndrst ON user_pro.User_No = user_fndrst.Rqst_Sender
WHERE
user_fndrst.Rqst_Status='1' AND user_fndrst.Rqst_Receiver='$user_id'
ORDER BY
user_fndrst.Frnd_SNo DESC

SQL for sorting out next/previous picture in gallery

I'm working on the photo section of my website, but more precisely on the next/previous link with sorting options.
There are two different option for sorting that exist, first there is a filter (Latest, Trending, Favorite, User etc.) and secondly a sorting option for some of the previous filters (date, views, ratings etc.)
I am having trouble finding a good solution for easily retrieving the next/previous picture for my slideshow.
This is the little bit of SQL I have for getting the next picture for a filter:latest
if ($filter == "latest") {
$sql = "SELECT *
FROM photos
WHERE status = 0 AND id < ".$id."
ORDER BY id DESC
LIMIT 1
";
$result = $db->sql_query($sql);
$sql2 ="SELECT *
FROM photos
WHERE id = (SELECT MAX(id) FROM photos WHERE status = '0')
ORDER BY id DESC
LIMIT 1
";
}
I am wondering if there is an easier way to implement this in my project ? maybe a php class exists to do something like this ?
I feel like I'm going to spend a long time getting all these SQL queries to work properly if I have to do it all like this.
Edit
This is the layout of my photos table
`id` -> unique ID, autoincremented
`title`
`img_name` -> contains the image file name
`date_created` -> when the picture was uploaded
`uploader` -> id of the user that uploaded
`views` -> number of views the picture has
`up_votes` -> votes used to calculate the Wilson score interval
`down_votes`
`net_votes` -> up vote minus down votes
There are other tables like one that links user with friends they have, it is called users_friends
`user_id` -> contains id of the user that added the friend
`friend_user_id` -> contains id of the friend in question
With these two tables I am able to get all the pictures posted by the friend of a user using this sql query :
SELECT *
FROM photos
WHERE uploader IN
(
SELECT friend_user_id
FROM users_friends
WHERE user_id = ':user_id'
)
ORDER BY id DESC
I then have two queries to get the link to the next picture and 2 other queries for the previous one. I have two because one is for when you get at the end of the database to go back to the other end and the other one is for all the other queries. And they look something like this (I'm only posting the next button here)
$sql = "SELECT *
FROM photos
WHERE status = 0 AND id < ".$id." AND Uploader IN (SELECT friend_user_id FROM users_friends WHERE user_id = ".$logedInUser['User_ID'].")
ORDER BY id DESC
LIMIT 1
";
$sql2 ="SELECT *
FROM photos
WHERE id = (SELECT MAX(id) FROM photos WHERE status = '0' AND Uploader IN (SELECT friend_user_id FROM users_friends WHERE user_id = ".$logedInUser['User_ID']."))
ORDER BY id DESC
LIMIT 1
";
$result = $db->sql_query($sql);
if (mysql_num_rows($result)==1) {
$row = $db->sql_fetchrow($result);
return "/photo/".$row["id"]."/".urlFriendly($row["Title"])."/".$filter.$sort;
}
else
{
$result = $db->sql_query($sql2);
$row = $db->sql_fetchrow($result);
return "/photo/".$row["id"]."/".urlFriendly($row["Title"])."/".$filter.sort;
}
I feel like there is a lot of stuff that could be simplified, but I don't yet know how to do it.
I also have the Lower bound of Wilson score sql code to implement for the next/previous button, and it is quite a bit sql code to have to write 4 time. Maybe that I can insert the Wilson score in the photos table, which could simplify a lot the sql code.
It would be helpful if you could post the structure of your table - i.e. what columns/types you have and what each row represents. I'll assume that you have a table where each row represents a photo, and that each photo has an ID, filename, and various other columns that help you filter/sort (such as date, favorite, etc.).
If your filtering and sorting preferences are defined by the user, you can then use those in a single SQL query, whereby you get the full set of ordered results. For instance:
$sort = date;
$filter = favorite;
$sql = "SELECT ID, filename, [other vars here]
FROM photos
WHERE " . $filter . " = TRUE
ORDER BY ". $sort . " DESC";
$result = $db->sql_query($sql);
Now, you can use a function such as mysql_fetch_array to step through each row in your result set and populate some kind of data structure with the current, previous, and next photos.

Looping through data from multiple tables PHP/Mysql

HI all,
I am trying to figure out how to put this into words even, but I am wanting to know how to format the output from each table separately in a "multiple table" mysql query. The output from the table1 "wall" is formatted within a while loop, but the content from table2 "actions" is already formatted(as 1 line of text with links) before it is inserted into the table(column action_body), so inside the loop I would only be outputting the action_date and action_body columns from the actions table.
I am probably not using the correct sql method(if Im doing anything right at all, that is) for the results I need, so feel free to correct my novice example, or suggest a new way to approach this.
Query:
$query = "SELECT wall.wall_id, wall.wall_owner_id, wall.wall_user_id,
wall.wall_post_date, wall.wall_post_content, actions.action_id,
actions.action_date, actions.action_user_id, actions.action_title,
actions.action_body FROM wall, actions
ORDER BY wall.wall_post_date, actions.action_date DESC";
$result = mysql_query($query);
while( $rows = mysql_fetch_assoc($result) {
// What to put here
}
Any help is appreciated, thanks, Lea
Update after comments
SELECT w.* FROM (
(SELECT
'w' as type,
wall_id as id,
wall_owner_id as owner_id,
wall_user_id as user_id,
wall_post_date as post_date,
NULL as title,
wall_post_content as content
FROM wall
WHERE wall_owner_id = x # user id of owner
)
UNION
(SELECT
'a' as type,
action_id as id,
action_user_id as owner_id,
NULL as user_id,
action_post_date as post_date,
action_title as title,
action_body as content
FROM actions
WHERE action_user_id = x # user id of owner
)
) w
ORDER BY w.post_date DESC
Because you don't JOIN on a specific field, you're gonna get every row-row combination of the two tables, which is a whole lot more data than you probably want.
You'd be better of by doing 2 queries, one for each table. While looping through the result of each table, you can collect the data you want in one array, with the field you want to sort it by as array key.
Then you sort the array, and loop through it to print it out.

Mysql query: How can I get the number of the users who sent messages to my specific user with status =1?

I have a problem with (for me to complicated) MySql query.
Okay, here is what I need to do:
First I need to check messages that some specific user received
$mid=$_SESSION['user'];
$stat1=mysql_query("SELECT id, fromid, toid, subject FROM messages WHERE
toid = '".$mid."' AND subject != 'not readed' GROUP BY fromid ")
or die(mysql_error());
while ($h = mysql_fetch_array($stat1))
{
$whosend=$h['fromid'];
Second thing that I need to do is check the status of the users (deleted or not) who sent the messages ("fromid") to my specific user ("toid"). This I must do from another table:
$stat2=mysql_query("SELECT id, status FROM members WHERE id='".$whosend."' AND
status ='1'")or die(mysql_error());
while ($s = mysql_fetch_array($stat))
{
Then my problems begin to show up.
How can I get the number of the users who sent messages to my specific user with status =1? Not the number of the messages but the total number of the users who sent them.
Is there any easier way to do this query? I tried with join tables like
$stat=mysql_query("SELECT memebers.id, memebers.status, messages.toid,
messages.fromid,messages.subject,messages.id FROM members, messages
WHERE messages.toid='".$mid."' AND members.status ='7' ....
But even in this query I need to have id's of the user who sent messages before this query so there will be another query before this join tables.
So you are looking for the number of members with status = 1 that sent this other member ($mid) a message?
Something like this?
$sql = "select count(distinct messages.fromid) From messages Inner Join members on members.id = messages.fromid Where messages.toid = '" . $mid . "' AND members.`status` = 1";
SELECT id, fromid, toid, subject FROM messages WHERE toid = '".$mid."' AND subject != 'not readed' GROUP BY fromid
can't be right as you have GROUP BY formid and no aggregation in the select clause.

Categories