Using PHP to select and pair two users - php

I'm trying to make an application that pairs two available users by selecting them randomly from a database and then making them unavailable (so they can't be selected again).
I was wondering how I could select them and then pair them?
I've got the following database structure.
USERS
| id | autoincrement, primary key
| user_id | user's ID
| connected | available, connecting, chatting
ROOMS
| id |
| room_name |
| room_id |
| user_id | first user connected
| user_id2 | second user connected
I'm not making rooms, I'm simply trying to pair users and send them to a room.

Do you mean join the records?
You could do something like:
select * from rooms as r
left outer join users as u on r.user_id=u.id
left outer join users as u2 on r.user_id2=u2.id
where r.id=123
123 = a room id.
EDIT:
Here is a way to update a Rooms record with two random Users
UPDATE rooms
SET
user_id=(SELECT id FROM users ORDER BY RAND() LIMIT 0,1),
user_id2=(SELECT id FROM users ORDER BY RAND() LIMIT 0,1),
where id=123
I have tested this and it seems to work. This will keep you from having duplicate users:
UPDATE rooms
SET
user_id=(SELECT u1.id FROM users as u1 ORDER BY RAND() LIMIT 0,1),
user_id2=(SELECT u2.id FROM users as u2 where user_id <> u2.id ORDER BY RAND() LIMIT 0,1)
where id=123

The SELECT could be something like this:
SELECT user_id
FROM `USERS`
WHERE connected = 'available'
ORDER BY RAND()
LIMIT 2;
You would need to parse the resultset and assign the to user_ids to variables such as
$user_id1
$user_id2
The first UPDATE would be something like this:
UPDATE `USERS`
SET connected = 'connecting'
WHERE user_id IN ($user_id1,$user_id2);
The INSERT would look something like this:
INSERT INTO `ROOMS` (room_name,room_id,user_id,user_id2)
VALUES ($room_name,$room_id,user_id,user_id2);
Finally the last UPDATE
UPDATE `USERS`
SET connected = 'connected'
WHERE user_id IN ($user_id1,$user_id2);
Although you are probably going to want to lock rows I have not grasped that part of database management yet. For you purposes you might want to look into it.

According to me you'll need three tables instead of two to implement your logic.
Consider my db schema
USERS
| id | autoincrement, primary key
| user_id | user's ID
| connected | available, connecting, chatting
ROOMS
| id |
| room_name |
USERCHAT
| id |
| user_id | user's ID
| room_id | room id
To get pair you can execute following query.
SELECT user_id
FROM USERS
WHERE id NOT IN (SELECT user_id FROM USERCHAT)
ORDER BY RAND()
LIMIT 2;
After selecting users you can simply insert them in ROOMS and USERCHAT tables. Using this schema you can also allow multiple users instead of two for chat.

Related

Like structure table with Laravel and showing the most popular content at top

I am using Laravel to creating a website, my users can post questions and other users can write their comments under the post, each comment have Up vote and Down vote, and users can voting for comments.
I need most liked (Up vote) shows topper than others..
This is my database structure and I join them together:
comment table:
comment_id | question_id | user_id | timestamp
up and down votes table (like):
like_id | comment_id | like_type | user_id | timestamp
note:like_type is an enum on mysql and its values are upvote and downvote.
1-What is the mysql query and Laravel codes for that?
2-Is my database Structure right?
1.Calculate SUM belongs to Each Comment
2.Make it order by Desc
select * from (
select ct.comment_id,ct.question_id,
ct.user_id,SUM(case when vt.like_type='upvote' then 1 else -1 end )
cnt from commenttable ct
from votestable
vt left join
on
vt.comment_id=ct.comment_id
)D order by D.cnt desc

Select records from one table and sort the result using a column from another table

I'm working on payroll system for the CRM located at my work and I'm trying to save having to store redundant data which over a period of years will stack up.
I tried to relate it to "how to get value from mysql table ordered by another table?" but had no luck.
I have a Users table
===========================================
# id | username | first_name | last_name #
===========================================
# 1 | joe | Joe | Blow #
===========================================
I also have a Timesheets table which stores the data of each individual session which for the sake of keeping short I have condensed a little in this question and obviously misses the full date/time in start and finish.
============================================
# id | username | start | finish #
============================================
# 1 | joe | 00:00 | 23:59 #
============================================
What I want to achieve is to order the results from the Timesheets table by the last_name column in the Users table with just the username that is derived the Timesheets table.
What I am trying to attempt here:
SELECT * FROM `Timesheets` WHERE `start` >= '{$monday}' AND `finish` <= '{$sunday}' ORDER BY (`Users`.`last_name` WHERE `username` = `Timesheets`.`username`) ASC
MySQL is clearly not my niche, what query would provide the desired result?
You'd have to use a JOIN and then ORDER BY, like this:
SELECT ts.*
FROM timesheets ts
JOIN users
ON ts.username = users.username
ORDER BY users.last_name
You may add the WHERE clause as required before the ORDER BY.
Use JOIN:
SELECT *
FROM Timesheets T
JOIN Users U ON T.username = U.username
WHERE T.start >= '{$monday}' AND `finish` <= '{$sunday}'
ORDER BY U.last_name ASC
use join for this:
SELECT t.*
FROM timesheets t
JOIN users
ON t.username = users.username WHERE t.start >= '{$monday}' AND t.finish <= '{$sunday}'
ORDER BY users.last_name

mysql sub query to get latest comment from two tables

I have been working on a query to get summarised list of communications like an inbox that shows conversations
below are my tables
users
company | contact_person | pic_small
alerts
comment_id | user_id | poster_id | timestamp
activity
comment_id | user_id | comment | timestamp
comments
comment_id | user_id | comment | timestamp
This is what I have so far which works ok although I need help with one aspect.
SELECT alerts.comment_id,
alerts.user_id,
alerts.poster_id,
alerts.active,
MAX(alerts.timestamp) AS maxTime,
users.contact_person,
users.company,
users.pic_small
FROM alerts
LEFT JOIN users ON users.user_id = alerts.poster_id
WHERE alerts.user_id = %s
GROUP BY alerts.comment_id
ORDER BY maxTime DESC
Comments are held in the activity and comments tables and I need to somehow join the last (newest) comment from either the activity or comments table (depending which is newer)
How do I add this to my above query, below is what I am trying to achieve

How to store multiple rows values in single table with single id

I want to save multiple rows with single id store in table. What should I do? Please guide me.
For example:
| table1 |
|-----------------|
|id |name |
|001(pk) |Ajit |
| table2 |
|-----------------|
|id(FK) |address |
|001 |Pune |
|001 |Mumbai. |
means TWO TABLES are their in table1 id is primary key & table2 id is foreign key
i.e.: 001 id should multiple address it would be save into table2 but id must be same,
i.e.: address textbox will generate at runtime
Put its(id) default value as "001"(you deserve it) using mysql query and then while inserting a new entry leave that column to add as new.
If you're wanting to link the data in the two tables (i.e. a users table and an addresses table) just use a foreign key.
Your users table:
id | name
================
1 | Martin Bean
Your addresses table:
id | user_id | address
==================================
1 1 Newcastle upon Tyne
This way, the primary key of your addresses table is not dependent on the ID of the users table. And your query to fetch both pieces of data is easy with a join:
SELECT
u.id,
u.name,
a.address
FROM
users u
LEFT JOIN
addresses a ON u.id = a.user_id

Mysql Query from Query results

I am making something like an announcement board that requires readers to acknowledge that they read it, and was wondering if there is a more efficient way of doing this.
I have 3 Tables on MySQL side:
+-----------------+ +-----------------+ +-----------------+
| Announcements | | Acknowledgement | | User |
+-----------------+ +-----------------+ +-----------------+
| announce_id | | ack_id | | user_id |
| announce_msg | | announce_id | | user_name |
| ... | | user_id | | ... |
+-----------------+ +-----------------+ +-----------------+
When a user "reads" the announcement (by clicking a button), Acknowledgment table will be inserted with the Announcement ID and User ID. When a second user "reads" the same announcement, Acknowledgement table will be inserted again with same Announcement ID and the second User ID and so on...
+--------------------------------+
| Acknowledgement |
+--------+-------------+---------+
| ack_id | announce_id | user_id |
+--------+-------------+---------+
| 1 | 1 | 1 |
| 2 | 1 | 4 |
| 3 | 1 | 3 |
| 4 | 3 | 1 |
| 5 | 3 | 6 |
| 6 | 3 | 2 |
+--------+-------------+---------+
Now to the problem. On the front end, when I list all the announcements on a page, I would have to first query for all the announcements. Then, for each announcement, I would have to do another query for all the users that have read this announcement.
$sql = "select * from Announcements";
$result = $pdo->query($sql);
while ($row = $result->fetch())
{
$announce_id = $row['announce_id'];
$announce_msg = $row['annouce_msg'];
$readers = "";
$sql2 = "select u.user_name from Acknowledgement as a INNER JOIN User as u where announcement_id =".$annouce_id;
$result2 = $pdo->query($sql);
while ($row2 = $result2->fetch())
{
$readers .= $row2['user_name'].", ";
}
echo "id:".$annouce_id.", message:".$announce_msg.", Readers:".$readers;
}
So if there 10 announcements on the page, there will be 10 sub-queries for each announcement. What I have now does the job right now... but what if there is 1000 announcements? Then there will be 1000 sub-queries? Sounds like the database will be really hammered. So I'm hoping there is a better way of doing this.
Also, if 1000 people in the user table reads all 1000 announcements, the acknowledgement table will have 1000x1000 entries. seems like the acknowledgement table will become really really long. Will that be a problem as time goes by?
This is a really rough example of what I'm trying to do but it did take me a long time to write all this. If more details is needed let me know.
There is a better way. You can use a single query with group_concat:
select a.*, group_concat(u.user_name separator ', ') as AllUsers
from Announcements a join
Acknowledgement ak
on a.Announce_Id = ak.Announce_Id join
User u
on u.user_ID = ak.User_ID
group by a.announce_id
This uses the MySQL feature of hidden columns to group by only one column (announce_id) but still pull in a bunch of other columns with no aggregations (everything else pulled in by the "*").
If your purpose here is to filter out the announcements that your current user has read, you can do this an entirely different way. Instead of querying for every announcement, and then finding out all the users that have read those announcements and examining those results to find ones that your use has read and trimming them from the displayed list, you can just query in one go for everything a particular user (or list of users) have not yet read.
Change your query to this:
SELECT * FROM Announcements WHERE Announce_id NOT IN (SELECT ANNOUNCE_ID FROM Acknowledgement WHERE User_ID = <INSERT USER ID HERE>)
That should return all Announcement rows that this particular user has not yet acknowledged. If you change that final WHERE clause to be WHERE User_ID IN () then you can specify a list of user IDs.
EDIT: Given the comment you posted above, you could use this query to get all announcements that have been read by no one:
SELECT * FROM Announcements WHERE Announce_id NOT IN (SELECT ANNOUNCE_ID FROM Acknowledgement WHERE User_ID IN (SELECT User_ID FROM User))
The logic for putting together a query to find announcements that haven't been read by someone (if not everyone) is escaping me right this second.
EDIT THE SECOND: Every announcement, and everyone who has and has not read it, requires use of a different kind of join that you've used above, a FULL OUTER JOIN. Unfortunately MySQL doesn't have that feature IIRC, but it can be simulated with a union query
SELECT A.*, ACK.*, U.* FROM Announcements AS A
INNER JOIN Acknowledgement AS ACK ON A.Announce_ID = ACK.Announce_ID
LEFT OUTER JOIN User AS U ON ACK.User_ID = U.User_ID
WHERE U.User_ID IS NOT NULL
UNION ALL
SELECT A.*, ACK.*, U.* FROM Announcements AS A
LEFT OUTER JOIN Acknowledgement AS ACK ON A.Announce_ID = ACK.Announce_ID
RIGHT OUTER JOIN User AS U ON ACK.User_ID = U.User_ID
I think that should do it. No facilities to test at the moment, of course.

Categories