MYSQL trigger to insert data into a row. based upon some criteria - php

I have three tables
purchase_master
+--------+---------+------------+
| autoid | user_id | package_id |
+--------+---------+------------+
user_master
+--------+---------+------+------------+-----------+
| autoid | user_id | name | user_email | user_pass |
+--------+---------+------+------------+-----------+
package_master
+-------------+----------+--------------+-----------+------------+---------------+------------+
| poster_path | overview | release_date | genre_ids | package_id | original_title| **isfree** |
+-------------+----------+--------------+-----------+------------+---------------+------------+
I want that whenever a new row is created into user_master, a trigger should fire that gets all rows in package_master where isfree = true, and populate those records along with new user_master.user_id into purchase_master table.
Example
lets say package_master has 2 rows having package_id = 100 & package_id = 101, in which isfree=true so when a new record is created into user_master having user_id = C601, the purchase_master table should have 2 new entries like.
"autoid" = 10,"user_id"=C601,"package_id"=100
"autoid" = 11,"user_id"=C601,"package_id"=101
Please guide me if it is possible through mysql trigger. Else I have to do it in PHP, on form submission.
EDIT:: I am using phpmyadmin

Try something like this:
CREATE TRIGGER bi_user_master BEFORE INSERT ON user_master
INSERT INTO purchase_master (user_id, package_id)
SELECT NEW.user_id, pm.package_id
FROM package_master AS pm
WHERE isfree;

Related

Rewrite of counter by partition

I use mysql and php with phpmyadmin. I have major problem with a partition based counter that I wan't to improve but my knowledge on sql prevents me from doing that. Im struggling very much with this.
I want the duplicated data in my table to have a counter that adds a number after a value if this value gets a duplicated value and then restarts from 1 until a new value is met and so on. Here is what the final result should look like
---------------------------
1 | Josh-1
---------------------------
2 | Josh-2
--------------------------
3 | Josh-3
--------------------------
4 | Josh-4
--------------------------
5 | Fred-1
--------------------------
6 | Fred-2
--------------------------
7 | Fred-3
-------------------------
I had gotten help with this counter here before but it's not working as I wan't it to. Also when I have pressed the insert button in my form the table looks like this in phpmyadmin after I reload it
---------------------------
1 | Josh-1-1-1
---------------------------
2 | Josh-2
--------------------------
3 | Josh-3
--------------------------
4 | Josh-4
--------------------------
5 | Fred-1
--------------------------
6 | Fred-2
--------------------------
7 | Fred
-------------------------
Whats going on here? The code that I seek help with rewriting is this
UPDATE usermeta u1,
(SELECT
u1.`id`, CONCAT(u1.`name`,'-',ROW_NUMBER() OVER(PARTITION BY u1.`name` ORDER BY u1.`id`)) newname
FROM
usermeta u1 JOIN (SELECT `name` , COUNT(*) FROM usermeta GROUP BY `name` HAVING COUNT(*) > 1) u2
ON u1.`name` = u2.`name` ) u3
SET u1.`name` = u3.`newname`
WHERE u1.`id` = u3.`id`
Could this code be rewritten so it creates a table of numbered names and duplicates that looks like the first table example and work like it should in phpmyadmin ? All help is very much appreciated. Keep in mind that I am a struggling moderate sql user.
Possible solution - BEFORE INSERT trigger and additional MyISAM table with secondary autoincrement:
Working table
CREATE TABLE user (id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(127));
Additional table
CREATE TABLE user_index (id INT AUTO_INCREMENT,
name VARCHAR(127),
PRIMARY KEY (name, id)) ENGINE=MyISAM;
Trigger
CREATE TRIGGER insert_user_index
BEFORE INSERT ON user
FOR EACH ROW
BEGIN
DECLARE new_index INT;
INSERT INTO user_index (name) VALUES (NEW.name);
SET new_index = LAST_INSERT_ID();
DELETE FROM user_index WHERE name = NEW.name AND id < new_index;
SET NEW.name = CONCAT_WS('-', NEW.name, new_index);
END
Insert rows - the AI index is added to the name. Check the result.
INSERT INTO user (name) VALUES
('Josh'),
('Josh'),
('Fred'),
('Josh'),
('Fred'),
('Fred'),
('Josh');
SELECT * FROM user;
id | name
-: | :-----
1 | Josh-1
2 | Josh-2
3 | Fred-1
4 | Josh-3
5 | Fred-2
6 | Fred-3
7 | Josh-4
Look what is stored in additional table now.
SELECT * FROM user_index;
id | name
-: | :---
3 | Fred
4 | Josh
db<>fiddle here
If your working table user exists already, and it contains some data, then you'd create additional table and fill it with data using, for example,
CREATE TABLE user_index (id INT AUTO_INCREMENT,
name VARCHAR(127),
PRIMARY KEY (name, id)) ENGINE=MyISAM
SELECT MAX(SUBSTRING_INDEX(name, '-', -1) + 0) id,
SUBSTRING_INDEX(name, '-', 1) name
FROM user
GROUP BY 2;
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=38f028cfe1c9e85188ab0454463dcd78

Updating the intermediary table Best practice PHP, MySQL

Lets Say I have Many to many relationship between the two tables students and subjects. So we create an intermediary table for mapping the data. Lets say it is students_subjects. The students_subjects table has 2 columns that is student_id & subject_id.
+------------+--------------+
| student_id | student_name |
+------------+--------------+
| | |
+------------+--------------+
+------------+--------------+
| subject_id | subject_name |
+------------+--------------+
| | |
+------------+--------------+
+------------+------------+
| student_id | subject_id |
+------------+------------+
| | |
+------------+------------+
Until a recent time when there is a update in students_subjects (student selecting subjects) what I did was delete all the subjects that student had an insert the new ones.
+------------+------------+----------+
| student_id | subject_id | selected |
+------------+------------+----------+
| 1 | 2 | 1 |
+------------+------------+----------+
| 1 | 2 | 0 |
+------------+------------+----------+
But recently I added a new column to this intermediary table as selected. So if a student selected new subjects and deselect some old subjects I add active for new ones and non_active for deselect ones. (I do this in PHP by getting the newly selected subjects and previously had subjects. Then compare both. When a student select subjects I check all the subjects that student has [active and non active]. If the newly selected subjects has previously non active subjects I active them and add the new ones. )
What is the best practice for doing this. I there a better way to achieve this?
I do think your first approach (deleting all associated rows and inserting new entries) is much more simpler.
If still want to have the selected field, a simple way would be to create unique composite index and using INSERT ... ON DUPLICATE KEY UPDATE. This can also prevent accidental insert of the same user_id and subject_id pair. First create the index:
ALTER TABLE `students_subjects` ADD UNIQUE `unique_student_subject`(`student_id`, `subject_id`);
Then, simply update the selected field for the student to 0 and insert the subjects the student selected. Example using PDO:
$studentId = 1;
$newlySelectedSubjects[] = ['subject_id' => 3];
$newlySelectedSubjects[] = ['subject_id' => 4];
$db = new PDO("connection string here", $username, $password);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->beginTransaction();
try{
$qry = 'UPDATE students_subjects SET selected = 0 WHERE student_id = :studentId';
$stmt = $db->prepare($qry);
$stmt->execute(['studentId' => $studentId]);
$insertQry = 'INSERT INTO students_subjects (student_id, subject_id, selected)'
.'VALUES (:studentId, :subjectId, 1) '
.'ON DUPLICATE KEY UPDATE '
.'selected = 1';
$insertStmt = $db->prepare($insertQry);
foreach ($newlySelectedSubjects as $subject) {
$params = ['studentId' => $studentId, 'subjectId' => $subject['subject_id']];
$insertStmt->execute($params);
}
$db->commit();
} catch (PDOException $e) {
//do something with exception
$db->rollBack();
}
What will happen is, if the student with student_id = 1 and subject_id = 3 already exist in the table, the selected field will be set to 1, if not a new record will be inserted.
If you require to track the user subjects selection and the de-selection, I suggest implementing some sort of audit trails and leave the students_subjects to only hold the relationship between students and subjects. It can be easier with the help of mysql TRIGGER.A simplified example of an audit trail table:
+------------+------------+----------+---------------------+
| student_id | subject_id | action | action_datetime |
+------------+------------+----------+---------------------+
| 1 | 2 | remove | 2018-01-01 00:01:23 |
+------------+------------+----------+---------------------+
| 1 | 4 | add | 2018-01-01 01:07:45 |
+------------+------------+----------+---------------------+

Insert data using INSERT INTO command.

I have two table name users and users_images. Both table have the value of userId. like
My user table
| userId | userName | user_address |
| 2 | John | CN-2, UK |
| 3 | Amit | India |
| 4 | David | Us |
| 5 | Shan | Canada |
.
.
...... and so on
| 125000 | Naved | Ukran |
**and my images table contain userid and Image name.
Now I want to merge ImageName field to user table without using any loop (I want to do it with single query (I have millions of records and I will have to do it many times to create temorary table) )
update users u
set
u.imageName = (
select imageName
from users_images i
where i.userid = u.userid GROUP BY u.userId )
you could use ON DUPLICATE KEY
for instance:
INSERT INTO table (a,b,c) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE c=c+1;
I think you can use Update for this like:
UPDATE Users
SET ImageName =
(SELECT ImageName
FROM UserImages
WHERE UserImages.UserID = Uers.UserID)
Please take a backup of your database first

How to find last inserted varchar value in a table using MySQL query

I have a table student, table structure is follow
student_id | name | class|
-------------------------
2-12-2013 | test | 3 |
-------------------------
2-13-2013 |test2 | 5 |
-------------------------
in this table i want add new record, its student_id become 2-14-2013. For that i want to get the last inserted student_id. how can i get it by MySQL query. Am alredy use mysql_insert_id() But its not working, How to solve this issue?
Define Your student table like below:-
student_id | add_date | name | class|
--------------------------------------
1 | 2013-12-2 | test | 3 |
--------------------------------------
2 | 2013-13-2 |test2 | 5 |
--------------------------------------
student_id would be int auto increamented primary key
then execute Query like below to get last inserted id:-
select student_id from student order by student_id desc limit 1;
Hi You has to set primary key to your table as integer auto-increment then you can use this last inserted id
$con = mysql_connect("localhost", "root", "", "chirag2");
$sql = "INSERT INTO test_student ( student_id,name,class)values('3-12-2013','test1','3' )";
$res = mysql_query($con, $sql);
echo mysql_insert_id($con);
die;
Note: you need to truncate table before alter it and set new primary key to it so take backup before this

Show database entries separated by comma

I have one field in the backend, where I input IDs separated by comma - ID1, ID2, ID3....These are videos in fact. All ids are stored in the field product_videos in the database (as they are typed).
How can I echo these id's on the frontend so they all show for the product?
Storing comma separated data in one data field is a bad idea. It is a real pain to manipulate, so you should really consider revising your db structure.
You haven't shown your data structure, so I'll give a basic example and then explain how it can be improved. My example assumes product_videos is linked to particular users:
table: `users`
| user_id | user_name | product_videos |
|---------|-----------|----------------|
| 1 | User1 | 1,2,3,4,6,7 |
| 2 | User2 | 5 |
You would maybe run a query
SELECT `product_videos` FROM `users` WHERE `user_name` = 'User1'
This would give you one row, with a comma separate value - you would then need to use something like PHP's explode() to convert it into an array and then loop through that array. That is a very bad method (and it will only become harder as you try to do more advanced things).
Instead, it would be easier to use a link table. Imagine:
table: `users`
| user_id | user_name |
|---------|-----------|
| 1 | User1 |
| 2 | User2 |
table: `videos`
| video_id | user_id |
|-----------|---------|
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 1 |
| 5 | 2 |
| 6 | 1 |
| 7 | 1 |
In this example, each video is a separate row in a db table (and each video is linked to an existing user). Each row is readily able to be handled independently. This makes it really easy to handle extra data for each video, such as a title, runtime length, date of uploading, etc.
You would then need to run a JOIN query. e.g.
SELECT `videos`.`video_id` FROM `videos`
INNER JOIN `users` ON `users`.`user_id` = `videos`.`user_id`
WHERE `users`.`user_name` = 'User1'
In PHP, you would do something like:
$q = mysql_query("SELECT `videos`.`video_id` FROM `videos` INNER JOIN `users` ON `users`.`user_id` = `videos`.`user_id` WHERE `users`.`user_name` = 'User1'");
while ($row = mysql_fetch_assoc($q)) {
echo "VIDEO ID = " . $row["video_id"] . "<br/>";
}

Categories