So I have a subscriptions table, here's the schema
+-------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| user_id | int(11) | YES | | NULL | |
| sub_to | int(11) | YES | | NULL | |
| date_subbed | varchar(255) | YES | | NULL | |
+-------------+------------------+------+-----+---------+----------------+
Pretty basic, here's an example row
+----+---------+--------+------------------------+
| id | user_id | sub_to | date_subbed |
+----+---------+--------+------------------------+
| 23 | 13 | 2 | 08/19/2014 07:44:49 pm |
+----+---------+--------+------------------------+
All pretty basic stuff. So user 13 is essentially subbed to user 2. So lets say that another user joins the site and another row is created with user 14 subs to user 5.
And now user 2 and user 5 post a message on the site and it gets inserted into the database. I want the users who are subscribed to someone to get an email with the newest post.
//Get user subs
$stmt = $con->prepare("SELECT * FROM subscription");
$stmt->execute();
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $key) {
print_r($key);
}
I've already tried a foreach loop but I couldn't see how it would work. So to sum things up I want to email the user when their is a new post. I'll be sending out an email every 24 hours so I don't kill the server. I want to make sure it's fully automated too. I know how to do the 24 hour time thing, but when I say automated I mean that it'll query and email by its self. Any pointers or ideas?
I figured it out. Just use ob_start(), and loop through each user. Select the posts they're subscribed to. Then inside the loop email it to each user. I used this query
SELECT
articles.*
FROM
articles
INNER JOIN subscriptions ON articles.from_id = subscriptions.sub_to
INNER JOIN users ON subscriptions.user_id = users.id
WHERE
users.email = :email
http://sqlfiddle.com/#!2/a1ceb/9
I kindof tried to do what your saying with SQL fiddle, but in trying it out it seemed impossible with the current schema. In the link above I have many comments about how you should completely redesign your schema. The query is a pretty big headache and not scalable unless you set up a new schema.
$sql="select email id from subscription";
$rs=mysql_query($sql); //resultset
if(mysql_num_rows($rs)>0) //checking whether anyone subscribed the user or not
{
while($d=mysql_fetch_array($rs))
{
$sql1="select * from subscription where sub_to in ('".$d["user_id"]."')";
$rs1=mysql_query($sql1);
while($ds=mysql_fetch_array($rs1)
{
$to=$ds["email_id"];//assuming the field for email id
$subject="";
$msg="";
#mail($to,$subject,$msg);
}
}
}
$sql="select email id from subscription";
$rs=mysql_query($sql); //resultset
if(mysql_num_rows($rs)>0) //checking whether anyone subscribed the user or not
{
while($d=mysql_fetch_array($rs))
{
$sql1="select email id from subscription where sub_to in('".$d["user_id"]."')";
$rs1=mysql_query($sql1);
while($ds=mysql_fetch_array($rs1))
{
$to=$ds["email_id"];//assuming the field for email id
$subject="";
$msg="";
#mail($to,$subject,$msg);
}//inner while end
}//outer while end
}
Related
I have these two tables which I'm trying to make an output of.
The first one **USERS** stores all information about a user, including an unique ID (androidID).
The second one gets input based on number of laps a user has taken, and will make one row pr lap.
What I'm trying to do is to output the last entry of a given androidID in **ROUNDS**, whith the corresponding name etc. from **USERS**
_____________________ _________________________
| **USERS** | | **ROUNDS** |
--------------------- -------------------------
| NAME | | ID(unique) |
| LASTNAME | | TIME |
| androidID(unique) | <----> | androidID(NOT unique) |
| ... | | ROUNDS |
This is how I'm quering the server
$result_users = $con->query(
"SELECT * FROM users"
);
$result_rounds = $con->query(
"SELECT * FROM Rounds ORDER BY laps desc"
);
I tried to numerous combination of the following. With no luck. My PHP skills is not the best, I'm afraid.
foreach ($result_users as $row_users) {
foreach ($result_rounds as $row_rounds) {
if($row_users['androidID'] == $row_rounds['androidID'] {
// Do some wizzardy
}
}
}
I have really hit a wall trying to connect the tables.
This would be the sql statement you want in your query.
SELECT * FROM `**USERS**` LEFT JOIN `**ROUNDS**`ON `**USERS**`.`androidID` = `**rounds**`.`androidID` ORDER BY `laps` desc 0,1;
I'm currently building a website where user can post(like a tweet on twitter), but I want to limit the number of post a user can submit on the website every hour.
This is what I have coded so far and it outputs the total number of post a user have.
$counter = mysql_query("SELECT COUNT(*) AS post_userID FROM post");
$num = mysql_fetch_array($counter);
$count = $num["post_userID"];
echo("$count");
if($count > 2) {
echo("You have exceeded the posting limits, please try again in 24 hours");
}
MY POST TABLE
+------------+------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------+------+-----+---------+----------------+
| postID |int(11) | NO | PRI | NULL | auto_increment |
| post_userID|int(11) | NO | | NULL | |
| message |VARCHAR(140)| NO | | NULL | |
| time |datetime | NO | | NULL | |
+------------+------------+------+-----+---------+----------------+
As you can see, I have a time(datetime) stored on my database and it holds the time when the post was submitted.
EXAMPLE:
+------------+------------+------------+----------+
| postID |post_userID | message | time |
+------------+------------+------------+----------+
| 1 | 25 | Hello Mike |1413620228|
| 2 | 26 | Hi John! |1413620332|
+------------+------------+------------+----------+
Oh btw, my server type is MySQL.
One way to do this would be:
select count(*) from post
where post_userID = 25
and time >= date_add(now(), INTERVAL -1 HOUR);
This will give you the number of posts for the user in the past hour.
Link to SQL Fiddle
I would assume that you have a users table. Create a column in the users table called last_post_submit_time and then whenever a user submits the post save that time in it. Finally whenever a user submits a post check if the current time - it's last_post_submit_time >= one hour. I hope you get it...
You can simply divide the timestamp by 3600 and round it to integer, something like this:
SELECT
ROUND(time/3600) AS hours_since_epoch
FROM
posts
WHERE
port_userID = <user> AND hours_since_epoch = ROUND(UNIX_TIMESTAMP(NOW())/3600)
This will return you the list posts user posted this hour (roughly).
Another way is to see how much the user has posted for the last hour:
SELECT
COUNT(*)
FROM
posts
WHERE
port_userID = <user> AND time > UNIX_TIMESTAMP(NOW()) - 3600
I'm having an issue on a personal project. I'm creating a project board where a user can log in, create different projects and add tasks to them. Basically a categorised to do list.
When the user logs in they are redirected to a screen that lists their already created boards. If no boards have been created then a link to "create board" will be displayed
When the user logs in their user name is saved in a session and called with $username
I have two tables, user and boards:
USER:
+---------+----------+-----------------+------------+
| user_id | username | email | password |
+---------+----------+-----------------+------------+
| 1 | user1 | user#user1.com | pass1 |
| 2 | user2 | user#user2.com | pass2 |
| 3 | user3 | user#user3.com | pass3 |
+---------+----------+-----------------+------------+
BOARDS:
+----------+-----------------+---------+
| board_id | board_name | user_id |
+----------+-----------------+---------+
| 1 | user1-board1 | 1 |
| 2 | user1-board2 | 1 |
| 3 | user2-board1 | 2 |
| 4 | user2-board2 | 2 |
+----------+-----------------+---------+
Note user 3 hasn't created any boards.
I run the below query to pull all associated boards for the current logged in user and display the board name.
$query = "SELECT board_id, board_name, boards.user_id, username ";
$query .= "FROM boards, user ";
$query .= "WHERE boards.user_id = user.user_id ";
$query .= "AND user.username = '{$username}' ";
$set = mysqli_query($connection, $query);
This all works fine and when I run the below code I can display the board names.
while ($boards = mysqli_fetch_assoc($set)) {
echo $boards['board_name'];
echo "<hr/>";
}
The problem I am having is displaying a "create board link" when a user is logged in but hasn't created any boards. I.e user 3.
My code:
if (!mysqli_fetch_row($set)) {
echo "create board";
} else {
while ($boards = mysqli_fetch_assoc($set)) {
echo $boards['board_name'];
echo "<hr/>";
}
}
I have tried variations of the above code but this is the closet i've got. If user 3 (who has no boards) logs in, he is greeted with "create board" so I presume it works as there are no rows of data associated with that user. However, if user 1 logs in (has 2 boards) only the second board name is being displayed. If I remove the !mysqli_fetch_row code then both board names are outputted. Obviously the fetch_row is effecting the results but I can't work out why.
If anyone can offer any guidance in how to check if a user has any boards I would be very grateful. Also if anyone can explain (for my own personal development) why running fetch_row alters my result set that is passed to the while loop it would be a bonus.
Thanks in advance
This line:
if (!mysqli_fetch_row($set)) {
both fetches and consumes a row from the result set. Since you're not assigning that returned row to a variable, it's utterly lost. If there are rows found, you then go off to the else clause, now missing one row of results.
You need to check how many rows were found, THEN start consuming:
if (mysqli_num_rows($set) == 0) {
... there are no rows ...
} else {
... there are rows: loop and display them
}
I'm working on a website, and I'm implementing a friend system. People can become friends and that will unlock some stuff which is not important. It is coded in PHP with MySQL as database.
Lets say this is my account table
id | name | picture
0 | Jorik | Cat.jpg
1 | Joost | Fish.jpg
2 | Henk | Ferret.png
This is the friend table(Is this a good way to do this?)
id | user id | friend id | invite date | accepted
0 | 0 | 1 | 123 | 0
1 | 2 | 0 | 456 | 1
2 | 1 | 2 | 123 | 1
The way I check if they are friends is as following (Could be an error in it, but you get the idea).
$fid = friend id, $uid = user id.
WHERE ( (`userid` = '{$uid}' && `friendid` = '{fid}' ) || (`friendid` = '{$uid}' && `userid` = '{$fid}' ))
First of all, is this an efficient way of doing this or is there a better way?
If I wanted to get the list of friends a user has I can run this query
WHERE (`userid` = '{$uid}' || `friendid` = '{$uid}')
now if I would run this query for the user 0, it would return
id | user id | friend id | invite date | accepted
0 | 0 | 1 | 123 | 0
1 | 2 | 0 | 456 | 1
I have worked with MySQL joins before but I can't figure out how to return something like the following result
id | friend id | invite date | accepted | Name | Picture
0 | 1 | 123 | 0 | Joost | Fish.jpg
1 | 2 | 456 | 1 | Jorik | Ferret.png
It would have to check if it should join the friend id or the user id with id from the account table. (The invited person is the friend id, the one who invited him will get the user id.)
I hope I gave enough information.
Can anyone help me with this?
Thanks in advance,
Jorik
My $0.02:
1) Normalize your data: get rid of the either 'userid' or 'id'. You only need one unique column for accounts.
2) Make a table for 'friends' like so:
( approximately )
create table Friends( UserId int unsigned, FriendUserId int unsigned, index( UserId, FriendUserId ));
Then add a row for each 'friend' where 'FriendUserId' is the account id (see #1) for each person.
3) Make a table for 'invites' like so:
(appx)
create table Invites ( UserId int unsigned, FriendId int unsigned, InviteDate datetime default timestamp, Accepted tinyint(1) default 0, primary key( UserId, FriendId ));
Add a row for each invite and update if/when its accepted.
Now to get a persons friends:
select * from Accounts a join Friends f on a.UserId = f.UserId where a.UserId = ;
to get Invites:
select * from Accounts a join Invites i on a.UserId = i.UserId
And so on...
.. but more than anything.. avoid duplicating data ..
If I understand your question correctly, something like this may work:
SELECT a.user_id as orig_user_id, f.*, ab.*
FROM account a
JOIN friends f
ON f.user_id=a.id
JOIN account ab
ON f.friend_id=ab.user_id
WHERE a.id={$uid}
I haven't tested this sql, but you get the picture. Basically, select the row for the user whose friends you are trying to locate, then join their friends rows, and then join the user account rows for their friends. You may need to alias some column names to make things clear in your code. You will have duplicates because you are double joining the account table.
I have a members table in MySQL
CREATE TABLE `members` (
`id` int(10) unsigned NOT NULL auto_increment,
`name` varchar(65) collate utf8_unicode_ci NOT NULL,
`order` tinyint(3) unsigned NOT NULL default '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
And I would like to let users order the members how they like.
I'm storing the order in order column.
I'm wondering how to insert new user to be added to the bottom of the list.
This is what I have today:
$db->query('insert into members VALUES (0, "new member", 0)');
$lastId = $db->lastInsertId();
$maxOrder = $db->fetchAll('select MAX(`order`) max_order FROM members');
$db->query('update members
SET
`order` = ?
WHERE
id = ?',
array(
$maxOrder[0]['max_order'] + 1,
$lastId
));
But that's not really precise while when there are several users adding new members at the same time, it might happen the MAX(order) will return the same values.
How do you handle such cases?
You can do the SELECT as part of the INSERT, such as:
INSERT INTO members SELECT 0, "new member", max(`order`)+1 FROM members;
Keep in mind that you are going to want to have an index on the order column to make the SELECT part optimized.
In addition, you might want to reconsider the tinyint for order, unless you only expect to only have 255 orders ever.
Also order is a reserved word and you will always need to write it as `order`, so you might consider renaming that column as well.
Since you already automatically increment the id for each new member, you can order by id.
I am not sure I understand. If each user wants a different order how will you store individual user preferences in one single field in the "members" table?
Usually you just let users to order based on the natural order of the fields. What is the purpose of the order field?
Usually I make all my select statements order by "order, name"; Then I always insert the same value for Order (either 0 or 9999999 depending on if I want them first or last). Then the user can reorder however they like.
InnoDB supports transactions. Before the insert do a 'begin' statement and when your finished do a commit. See this article for an explanation of transactions in mySql.
What you could do is create a table with keys (member_id,position) that maps to another member_id. Then you can store the ordering in that table separate from the member list itself. (Each member retains their own list ordering, which is what I assume you want...?)
Supposing that you have a member table like this:
+-----------+--------------+
| member_id | name |
+-----------+--------------+
| 1 | John Smith |
| 2 | John Doe |
| 3 | John Johnson |
| 4 | Sue Someone |
+-----------+--------------+
Then, you could have an ordering table like this:
+---------------+----------+-----------------+
| member_id_key | position | member_id_value |
+---------------+----------+-----------------+
| 1 | 1 | 4 |
| 1 | 2 | 1 |
| 1 | 3 | 3 |
| 1 | 4 | 2 |
| 2 | 2 | 1 |
| 2 | 3 | 2 |
+---------------+----------+-----------------+
You can select the member list given the stored order by using an inner join. For example:
SELECT name
FROM members inner join orderings
ON members.member_id = orderings.member_id_value
WHERE orderings.member_id_key = <ID for member you want to lookup>
ORDER BY position;
As an example, the result of running this query for John Smith's list (ie, WHERE member_id_key = 1) would be:
+--------------+
| name |
+--------------+
| Sue Someone |
| John Smith |
| John Johnson |
| John Doe |
+--------------+
You can calculate position for adding to the bottom of the list by adding one to the max position value for a given id.