How to update data as null in mysql using php loop? - php

I have a table named users with a column called user_subs. It looks like this.
In user_subs I have stored the specific users session username. Lets say this specific users name is James.
Now how would I loop through a specific user_subs looking for "James" and remove him from that specific user_subs without removing all the other names.
This is what I have so far and the only problem is, its deleting all the usernames in user_subs instead of just "James".
if(isset($_GET['p_id'])) {
$the_post_id = $_GET['p_id'];
$the_post_author = $_GET['author'];
}
if(isset($_POST['delete_sub'])) {
$username = $_SESSION['username'];
$query = "SELECT user_subs FROM users WHERE username = '{$username}' ";
$select_users_by_id = mysqli_query($connection, $query);
while ($row = mysqli_fetch_array($select_users_by_id)) {
$user_subs = explode(',', $row['user_subs']);
foreach($user_subs as $out) {
$query = "UPDATE users SET user_subs = null WHERE username = '{$the_post_author}' ";
$unsubscribe_user = mysqli_query($connection, $query);
echo "Unsubscribed";
}
}
}
THIS IS JUST IN TEST, PREPARED STATEMENTS WILL BE USED BEFORE GOING LIVE
Thank you for your time.

I second the other user's comment about moving this column to a different table. In the meanwhile, if you want to achieve what you are asking for, you can try removing the user name from the column value and update it with the remaining text.
if(isset($_POST['delete_sub'])) {
$username = $_SESSION['username'];
$query = "SELECT user_subs FROM users WHERE username = '{$username}' ";
$select_users_by_id = mysqli_query($connection, $query);
while ($row = mysqli_fetch_array($select_users_by_id)) {
$user_subs = str_replace($username . ',', '', $row['user_subs']);
$query = "UPDATE users SET user_subs = '{$user_subs}' WHERE username = '{$the_post_author}' ";
$unsubscribe_user = mysqli_query($connection, $query);
echo "Unsubscribed";
}
}
OPTION-2
$user_subs = explode(',', $row['user_subs']);
$user_subs_new = [];
foreach($user_subs as $out) {
if ($out !== $username) {
$user_subs_new[] = $out;
}
}
$user_subs = implode(',',user_subs_new);
$query = "UPDATE users SET user_subs = '{$user_subs}' WHERE username = '{$username}' ";
$unsubscribe_user = mysqli_query($connection, $query);
echo "Unsubscribed";
}

Let's start over. Let's start here, in fact...
DROP TABLE IF EXISTS users;
CREATE TABLE users
(user_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,email VARCHAR(20) NOT NULL UNIQUE
);
DROP TABLE IF EXISTS user_subs;
CREATE TABLE user_subs
(user_id INT NOT NULL
, sub_id INT NOT NULL
, active TINYINT NOT NULL DEFAULT 1
, PRIMARY KEY(user_id,sub_id)
);
INSERT INTO users VALUES
(1,'b.smyth634#gmail.com'),
(2,'james#gmail.com'),
(3,'f#gmail.com'),
(4,'sally#gmail.com'),
(5,'thomas#gmail.com');
INSERT INTO user_subs (user_id,sub_id) VALUES
(1,5),
(1,2),
(1,1),
(1,4),
(2,1),
(2,2),
(2,4);
SELECT * FROM users;
+---------+----------------------+
| user_id | email |
+---------+----------------------+
| 1 | b.smyth634#gmail.com |
| 2 | james#gmail.com |
| 3 | f#gmail.com |
| 4 | sally#gmail.com |
| 5 | thomas#gmail.com |
+---------+----------------------+
SELECT * FROM user_subs;
+---------+--------+--------+
| user_id | sub_id | active |
+---------+--------+--------+
| 1 | 5 | 1 |
| 1 | 2 | 1 |
| 1 | 1 | 1 |
| 1 | 4 | 1 |
| 2 | 1 | 1 |
| 2 | 2 | 1 |
| 2 | 4 | 1 |
+---------+--------+--------+
SELECT u.*
, GROUP_CONCAT(us.sub_id) subs
FROM users u
JOIN user_subs us
ON us.user_id = u.user_id
GROUP
BY u.user_id;
+---------+----------------------+---------+
| user_id | email | subs |
+---------+----------------------+---------+
| 1 | b.smyth634#gmail.com | 1,2,4,5 |
| 2 | james#gmail.com | 1,2,4 |
+---------+----------------------+---------+
From here we have a choice. We can either DELETE subs we no longer wish to consider, or simply UPDATE them as 'inactive'.
Either way, we just need a DELETE or an UPDATE. So no SELECT needed. In fact a SELECT would, as I mentioned, be counterproductive - because a user may modify the data set in between the execution of the SELECT and the execution of the UPDATE/DELETE. This is known as a 'race condition'.

Related

How to get another value from different table in php

$sql = "SELECT users.user_name, users.password, profil.name
FROM users
LEFT JOIN
profil ON users.id = profil.id
WHERE user_name='admin' AND password='123'
ORDER BY profil.name;";
$result = mysqli_query($conn, $sql);
echo $_SESSION['name']
table:user
| user_name| pass | id |
| -------- | -----|-----|
| admin | 123 | 1 |
| admini | 123 | 2 |
table : profil
| id | name |
| ---| --------|
| 1 | ajramos |
| 2 | carlo |
how can i print the name when i log in a account
i wanted to display the name when i log in a acc for example admin 123 ajramos should print
you have to execute the query and save into a session
$sql = "SELECT users.user_name as user_name, users.password, profil.name as name
FROM users
LEFT JOIN
profil ON users.id = profil.id
WHERE user_name='admin' AND password='123'
ORDER BY profil.name LIMIT 1;";
$result = mysqli_query($conn, $sql);
$data = mysqli_fetch_array($result);
$_SESSION['login_data'] = $data;
echo $_SESSION['login_data']['name'];

How can I check an other table before updating?

I have these two tables:
// users
+----+-------+-----------------------+--------+
| id | name | email | active |
+----+-------+-----------------------+--------+
| 1 | peter | peter12#hotmail.com | NULL |
| 2 | jack | most_wanted#gmail.com | NULL |
| 3 | john | john_20016#yahoo.com | NULL |
+----+-------+-----------------------+--------+
// activate
+----+---------+---------------------+
| id | post_id | random_string |
+----+---------+---------------------+
| 1 | 2 | fewklw23523kf |
+----+---------+---------------------+
Also I have an URL like this:
http://example.com/activate.php?str=fewklw23523kf
All I'm trying to do:
Comparing GET['str'] with random_string column from activate table
Checking active column for NULL where id = post_id.
And then (if there is matched row) set 1 the active column from users table. How can I do that?
$str = $_GET['str'];
$stm = $db_con->prepare( "UPDATE users SET active = 1
WHERE ( SELECT 1 FROM activate WHERE random_string = ? ) t AND
( SELECT 1 FROM users WHERE t.post_id = id AND
active IS NULL ) ");
$stmt->execute(array($str));
My query doesn't work as expected.
You can use join
UPDATE users
INNER JOIN activate on activate.post_id = user.id
SET active = 1
WHERE activate.random_string = ?
AND user.active IS NULL;
try to change
( SELECT 1 FROM users WHERE t.post_id = id AND active IS NULL )
to this
( SELECT 1 FROM users, activate as t WHERE t.post_id = id AND active IS NULL)
I do believe this one will do the trick
UPDATE users, activate SET active = 1
WHERE users.id = post_id and active is null and random_string=?

How to implement a PHP condition using pure SQL?

I have this tables structure:
// Posts
+----+------------+-----------------------+----------------+-------------+
| id | title | content | money_amount | author_id |
+----+------------+-----------------------+----------------+-------------+
| 1 | title 1 | content 1 | NULL | 12345 |
| 2 | title 2 | content 2 | 25 | 42355 |
| 3 | title 3 | content 3 | 5 | 53462 |
| 4 | title 4 | content 4 | NULL | 36346 |
| 5 | title 5 | content 5 | 15 | 13322 |
+----+------------+-----------------------+----------------+-------------+
// ^^ NULL means this post is free
// Money
+---------+--------------+
| post_id | user_id_paid |
+---------+--------------+
| 2 | 42355 | // He is author of post
| 2 | 34632 | // This row means besides author, this user 34632 can see this post too. Because he paid the money of this post.
| 3 | 53462 | // He is author of post
| 5 | 13322 | // He is author of post
| 3 | 73425 | // This row means besides author, this user 34632 can see this post too. Because he paid the money of this post.
+---------|--------------+
Note1: All post_id(s) in the Money table are belong to those posts which are non-free.
Note2: Always there is a row belong to author of post (which is non-free) in the Money table.
Note3: Money table is just to determines who can see such a post.
Now this user $_SESSION['current_user'] = '23421' wants to see this post id = 2. Here is my code:
$stm = $this->dbh->prepare(SELECT * FROM Posts WHERE id = '2');
$stm->execute();
$result = $stm->fetch(PDO::FETCH_ASSOC);
if ( $result[money] == '') { // money_amount is NULL in the Posts table
this post is free and everybody can see it
} else {
$stm = $this->dbh->prepare(SELECT count(1) FROM Money WHERE post_id = '2' and user_id = $_SESSION['current_user']);
$num_rows = $stm->fetchColumn();
if($num_rows){
$paid = true; // This means current user paid the cost of post and he can see it.
} else {
$paid = false; // this means current user didn't pay the cost of post and he cannot see it.
}
}
I want to know, can I implement those two query in one query and do that condition using MySQL instead of PHP ?
Here is solution using IF and EXISTS functions(MySql):
...
$stmt = $conn->prepare("
SELECT IF(p.money_amount,1,0) as notfree,
EXISTS(SELECT * FROM `Money` WHERE `post_id` = ? AND`user_id_paid` = ?) as paid
FROM `Posts` p WHERE p.id = ? ");
$stmt->execute([2, $_SESSION['current_user'], 2]);
$result = $stmt->fetch(\PDO::FETCH_ASSOC);
if (!$result['notfree']) { // post is free
// this post is free and everybody can see it
} else {
$paid = ($result['paid'])? true : false;
}
You can use a join, and the query below uses LEFT JOIN.
SELECT * FROM Money
LEFT JOIN Posts ON Money.post_id = Posts.id
WHERE ((Posts.money_amount IS NOT NULL AND Money.user_id_paid = :userId)
OR Posts.money_amount IS NULL) AND Posts.id = :postId
Note that :userId is a placeholder for PDO parameterized query, where you should bind the parameter to the placeholder before execution. Like:
$postId = 2;
$stmt->bindParam('userId', $_SESSION['current_user']);
$stmt->bindParam('postId', $postId);
Also note that when binding the placeholder name doesn't need the colon. Using a RIGHT JOIN means you SELECT from the Posts table and join the Money table.

Contitionally structured and ordered MySQL query

I have a table in a MySQL Database.
It is structured as such:
CREATE TABLE `wall` (
`wall_id` int(10) NOT NULL auto_increment,
`user_id` int(10) NOT NULL,
`wall_content` varchar(1024) NOT NULL,
`time_posted` varchar(64) NOT NULL,
`is_reply` int(10) NOT NULL,
PRIMARY KEY (`wall_id`)
) ENGINE=MyISAM
The column 'is_reply' will be the id of 'wall_id' to which it is a reply of. How would I structure a query to get all the rows based on an inner join of another table to cross reference the user_id, and to group the wall posts with the comments below it whilst ordering the wall posts by 'time_posted'
My current query does that without grouping the comments. It is:
SELECT wall.*, user_wall.*, users.username, users.avatar_id
FROM `wall`
INNER JOIN user_wall ON user_wall.wall_id = wall.wall_id
INNER JOIN users ON users.user_id = wall.user_id
WHERE user_wall.user_id=15
I hope you can understand this.
Edit:
The table 'user_wall' is a table that stores what values are on the users wall, and the 'wall' table stores what is actually posted. The user_id in the 'wall' table is a reference to who posted that post.
The current query as stated above is fully functional and returns data as such:
wall_id | user_id | wall_content | time_posted | is_reply | user_id | wall_id | username | avatar_id
1 | 1 | *content* | *time* | 0 | 2 | 1 | User1 | 1
2 | 1 | *content2* | *time2* | 0 | 2 | 2 | User1 | 1
3 | 1 | *content3* | *time3* | 1 | 1 | 3 | User1 | 1
Whereas my question is, how do you structure the query so the result is like so:
wall_id | user_id | wall_content | time_posted | is_reply | user_id | wall_id | username | avatar_id
1 | 1 | *content* | *time* | 0 | 2 | 1 | User1 | 1
3 | 1 | *content3* | *time3* | 1 | 1 | 3 | User1 | 1
2 | 1 | *content2* | *time2* | 0 | 2 | 2 | User1 | 1
Where the row with 'wall_id' 3 which has and 'is_reply' of 1 to be beneath the row with 'wall_id'. Similarly a row with an 'is_reply' of 2 will be under the row with the row with a 'wall_id' of 2.
Now that you've edited it I understand what you mean. This should do it:
ORDER BY IF(wall.is_reply, wall.is_reply, wall.wall_id), wall.wall_id
Format: IF(EXPRESSION, IF_TRUE, IF_FALSE)
SQL can't return multiple rows from one table (e.g. the wall_comments) and only one from the ones it is joined with. In other words, that can't be done. There is an alternative that will get the same results but use two SQL queries and some PHP code.
Query #1:
SELECT wall_comments.*
FROM `wall_comments`
INNER JOIN user_wall ON wall_comments.wall_id = user_wall.wall_id
WHERE user_wall.user_id=15
Query #2:
SELECT wall.*, user_wall.*, users.username, users.avatar_id
FROM `wall`
INNER JOIN user_wall ON user_wall.wall_id = wall.wall_id
INNER JOIN users ON users.user_id = wall.user_id
WHERE user_wall.user_id=15
PHP:
<?php
$result1 = mysql_query($query1);
$result2 = mysql_query($query2);
$comments = array();
while($row = mysql_fetch_assoc($result1))
{
$comments[$row['wall_id']][] = $row;
}
$walls = array();
while($row = mysql_fetch_assoc($result2))
{
$walls[] = array_merge(
$row,
array(
'comments' => isset($comments[$row['wall_id']]) ? $comments[$row['wall_id']] : array(),
),
);
}
?>

need advice on mysql normalization and php class structure

i am trying to build a system that logs, media (photo, video, audio) upload statistic. so i come up with 3 tables, 1 for audio, 1 for video, and 1 for photo. and here's the structure
+-----------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| member_id | int(10) | NO | | NULL | |
| counter | int(11) | NO | | NULL | |
| daydate | text | NO | | NULL | |
| epochtime | text | NO | | NULL | |
+-----------+---------+------+-----+---------+----------------+
all three tables has the same fields, since i think (so far) i need to differentiate the medias on each and particular table, is this redundant ??
anyway since each of the media is treated the same, so i think i should only build once class and kinda use the methods depending of what media i am accessing at the time. here's the class :
require_once(INC_PATH.DS.'database.php');
class Log extends DatabaseObject {
protected static $db_fields = array('id', 'member_id', 'counter', 'daydate', 'epochtime');
public $id;
public $member_id;
public $counter;
public $daydate;
public $epochtime;
public function find_counter($table_name){
global $database;
$time = date('d-m-Y');
$timestamp = time();
$sql = "SELECT * FROM ". $table_name;
$sql .= " WHERE daydate = '".$this->daydate."'";
$sql .= " AND member_id = '".$this->member_id."'";
return self::find_by_sql($sql);
}
public function add_log($table_name){
global $database;
$tes = $this->find_counter();
if(!empty($tes)){
$sql = "UPDATE ".$table_name;
$sql .= " SET counter = counter+1";
$sql .= " WHERE daydate = '".$this->daydate."'";
$sql .= " AND member_id = '".$this->member_id."'";
$database->query($sql);
return ($database->affected_rows() == 1) ? true : false;
}else{
$sql = "INSERT INTO ".$table_name;
$sql .= " (id, member_id, user_privelege, counter, daydate, epochtime)";
$sql .= " VALUES ('', '".$this->member_id."'";
$sql .= " , '".$this->user_privelege."', '1', '".$this->daydate."', '".$this->epochtime;
$sql .= "')";
$database->query($sql);
return ($database->affected_rows() == 1) ? true : false;
}
}
}
so far this is pretty much working but, i still have doubts on the way i break the table in to 3 tables, and the way i use the $table_name as parameter. any suggestions for better approach ?? i really want to improve my codes, thank you very much
Regards
UPDATE
alright, based on everybody's answer, i would like to clear somethings up:
i only need to log the uploaded media
i already have another separate table to record other information (length, filename, titles, etc) for each media.
lets just say i add a field called "media_id" and merge the table into one, and since the way that i add and update my rows is based on the day-date, it will INSERT if the given daydate and the member_id is not found, and otherwise it will UPDATE, i think i should also change the way my add_log() method works, into something like:
public function add_log($table_name, $media_id){
global $database;
$tes = $this->find_counter();
if(!empty($tes)){
$sql = "UPDATE ".$table_name;
$sql .= " SET counter = counter+1";
$sql .= " WHERE daydate = '".$this->daydate."'";
$sql .= " AND member_id = '".$this->member_id."'";
$sql .= " AND media_id = '".$media_id."'";
$database->query($sql);
return ($database->affected_rows() == 1) ? true : false;
}else{
$sql = "INSERT INTO ".$table_name;
$sql .= " (id, member_id, media_id, counter, daydate, epochtime)";
$sql .= " VALUES ('', '".$this->member_id."'";
$sql .= " , '".$media_id."', '1', '".$this->daydate."', '".$this->epochtime;
$sql .= "')";
$database->query($sql);
return ($database->affected_rows() == 1) ? true : false;
}
}
what do you guys think ??
thanks again
Put it all in one table and have a media_type column.
+-----------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| member_id | int(10) | NO | | NULL | |
| counter | int(11) | NO | | NULL | |
| daydate | text | NO | | NULL | |
| epochtime | text | NO | | NULL | |
| media_type| int | NO | | NULL | |
+-----------+---------+------+-----+---------+----------------+
Create a foreign key relationship to another table that defines media_type.
+-----------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------+------+-----+---------+----------------+
| media_type_id| int | NO | PRI | NULL | |
| description | text | NO | | NULL | |
+-----------+---------+------+-----+---------+----------------+
This would hold media_type_id (e.g. 1) and media_type_description (e.g. audio).
e.g.
1, audio
2, video
3, photo
The main table would then just include on each row the id of 1, 2, 3 to denote which media type it is. You can then use this from your application to constrain via the WHERE clause, which media you're referring to. e.g. SELECT * FROM maintable WHERE media_type_id = 3 to just get the photos.
Make it one table with an extra column "media_type". Your design would require you to make an extra table for every new media type and that is possibly poor design.

Categories