Mysql trigger ON INSERT + INNER JOIN syntax error - mysql

I have an assignment from uni where i need to simulate something like Spotify (without player).
Some context: The thing is i want to make a trigger so that when a new playlist is created (column on table playlist), the creator user (userID) is set as it's first follower. The table followingPlaylist is an intermidiate table that keeps record of which user follows which playlist. On top of that, accounts have 2 types, artists and users (so there is the table accounts that keeps the account info, users and artists that keep the accountID and userID or artistID respectively).
The problem i have is that mysql throws sintax error with this query, if anyone could help i'd be much obliged. This is the query:
CREATE TRIGGER primer_seguidor ON playlists
FOR INSERT AS
INSERT INTO followingPlaylist
(accountID, playlistID)
SELECT
playlists.playlistID, users.accountID FROM playlists
INNER JOIN usuers ON playlists.userID = users.userID;

CREATE TRIGGER primer_seguidor
AFTER INSERT
ON playlists
FOR EACH ROW
INSERT INTO followingPlaylist (accountID, playlistID)
SELECT NEW.playlistID, users.accountID
FROM users
WHERE NEW.userID = users.userID;
PS. Syntax correction only, no logic checking.
PPS. Modelling fiddle

Related

MySQL - select or insert

I have users from many external sources which I try to map to internal userId, so the table I have is:
userId, externalSourceId, externalUserId
In my code, I'm getting externalSourceId and externalUserId and want to get the userId from the database, if exists, otherwise, create one and return the newly created value. I need this action to be atomic because several processes may try to do the same thing at the same time, so I wished only the first time will create a userId.
In pseudo code it will look like that:
u = find user with (externalSourceId, externalUserId)
if no u:
2.1. u = create new user with (externalSourceId, externalUserId) and random userId
return u
INSERT INTO `users`
(`externalSourceId`, externalUserId)
VALUES( 10, 100)
ON DUPLICATE KEY
UPDATE userId=userId
You can also use insert ignore. You can read more about DUPLICATE KEY versus INSERT IGNORE
INSERT IGNORE INTO test (externalSourceId,externalUserId) VALUES (23,32);
SELECT userId FROM test WHERE externalSourceId=23 AND externalUserId=32;
You can use this if externalSourceId and externalUserId are defined unique.

Adding a new, required table to a database in mysql

Basically I have an existing users table, and I need to add a table for user metadata. When a new user is created we generate the default metadata, but for existing users this doesn't exist yet and we need it to.
Essentially add table, loop through users, and insert default data, something like this pseudo-code:
FOR EVERY user IN users
INSERT INTO `meta_data` VALUES (
'generate UUID',
'users UUID from users table'
'2014-12-29 22:57:55',
'2015-01-01 01:39:37',
);
I've dealt with a little bit of mysql but this would be my first any sort of sql script.
Use an INSERT statement with a SELECT in place of the values:
INSERT INTO meta_data
SELECT UUID(), u.uuid, '2014-12-29 22:57:55', '2015-01-01 01:39:37'
FROM users AS u
If you need to do this after you start adding metadata for new users, you can filter them out:
INSERT INTO meta_data
SELECT UUID(), u.uid, '2014-12-29 22:57:55', '2015-01-01 01:39:37'
FROM users AS u
LEFT JOIN meta_data AS m ON u.uuid = m.users_uuid
WHERE m.users_uuid IS NULL

update a table when new data is available in another table

I have two table:
Am using this query to populate my marks table with all 'id' in student table:
$module1= "insert into marks (stud_id,moduleID)
select sid, 1
from user_student
where sid not in (
select * from (
select distinct stud_id from marks where moduleID=1
) alias_name
)";
So i need to take all 'sid' from Table student and populate them into table marks my query above does all that. The problem am encountering is that every time i make a change to the data e.g column test1 , new record are inserted again.
If i populate the marks table manually, Can't i have a code that when new data is available in student table, the data is just updated in marks table...
I don't understand some points of your insert query, why insert sid in stud_id if there's a id in student table to relate them?
Maybe solve your problem the creation of a composed unique key to moduleID and stud_id and use a REPLACE in place of INSERT.
But the right way to do it is using a TRIGGER like:
DROP TRIGGER IF EXISTS `student_after_insert`;
CREATE TRIGGER `student_after_insert` AFTER INSERT ON `student`
FOR EACH ROW INSERT INTO marks (stud_id,moduleID)
SELECT NEW.`id`, `modules_table`.`id` FROM `modules_table`;
PS: I suppose you have a table of modules with name modules_table. Change it accordingly.
I haven't understand your question at the best, my tip is:
Make a unique constraint on marks table (up to you is the choice of best constraint rule).
Then use a trigger to make the right insert/update:
Something like that, (hope that syntax is right):
CREATE TRIGGER myTrigger
AFTER INSERT ON students
FOR EACH ROW
BEGIN
// check that insertion doesn't broke the constraint previously define, then
insert into marks (stud_id,moduleID) values (new.sid, 1);
END
Note: NEW is the row that you have as soon inserted/updated on students. Similar you have OLD metarow.

mysql trigger on insert many to many

I have two tables with many to many relationship.
The tables are
table user
idUser
name
table right
idRight
type
table user_has_right
idUser
idRight
When I insert a user with the rights I want him to have,
obviously the middle table (user_has_right) must have some inserts
too. Let's say I want to insert the user with id = 1 and name = 'test'
and right = 'boss' , where boss is already a row in table right with id = 1 .
The middle table must have an insert of (1,1).
I know how to do this programmatically, but can this be done with trigger on insert?
Thank you.
//The problem I'm facing is how to find the idRight for type 'boss'. Maybe a nested select inside the trigger?
//Is this task even possible?
I've come across this old question. If you're still interested in an answer then here it is
CREATE TRIGGER tg_user_insert
AFTER INSERT ON `user`
FOR EACH ROW
INSERT INTO user_has_right (idUser, idRight)
SELECT NEW.idUser, idRight
FROM `right`
WHERE type = 'boss';
Here is SQLFiddle demo

mysql insert if not exists, concurrent sessions

I want to insert new user into users table and make sure that user's nick and email are not already in the table (InnoDB).
Here is my logic:
if (SELECT COUNT(*) FROM users WHERE nick = :nick) > 0:
return "name exists";
if (SELECT COUNT(*) FROM users WHERE email = :email) > 0:
return "email exists";
# OK to insert? Or something bad can happen here?
INSERT INTO users (nick, email) VALUES (:nick, :email)
But now I'm not sure if this is the right way. Suppose that between SELECT and INSERT query some other, concurrent connection creates new record with same nick or email (is this even possible?). Then INSERT will throw an exception and I'm unable to provide any feedback to the front end (beside simple "error occurred, try again).
Another idea is to use INSERT IGNORE and then check LAST_INSERT_ID(), but can I always be sure LAST_INSERT_ID()==0 when insertion is skipped?
Is there any better way to handle this?
Why don't you use a UNIQUE INDEX? Just insert the new value and let the query fail when the unique constraint is violated. A bit of errorhandling will do the trick.
The UNIQUE contraint will also solve your problem with concurrent users.
INSERT INTO users (nick, email)
SELECT :nick, :email
FROM Dual
WHERE NOT EXISTS (
SELECT 1
FROM users
WHERE nick = :nick OR email = :email
)
most MySql connectors out there have a way to get the rows affected, or you can SELECT ROW_COUNT().
Good question.
unfortinately mysql doesnt support something like "insert into if not exists".
there are several ugly solutions.
mostly the best is to handle it in your application. select before, see if you get anything, only insert if you dont get anything.
then you can put a unique key on the fields to ensure that the database keeps consistent.
you can also directly insert and rely on the unique keys. you will get an error which you have to deal with in your application. you CAN distinguish between the errors so you can display the proper message. duplicate key will be a 1062 if i remember that correclty.
however there ARE means to accomplish this with other teqniques.
one that i know of is called a mutex table.
it works so that you create a second table "mutex" which has the syme key fields as your working table which i now call "table".
then you can do something like:
isnert into table (field1,field2) select ("input1","input2") from mutex left outer join table on(mutex.field1 = table.field1 AND mutex.field2 = table.field2) where mutex.field1 != "input1" AND mutex.field2 != "field2"
i did not test this and i hope i remember the tequnique correctly, better look it up!
it is also possible to advance this to mre flexibility so you can for example only allow a desired number of duplicates in one table.
but this does not ensure data consistency as the data table is accessible as well, so i would really recommend the first method: rely on key constraints where possible, and deal with the error number in your app, if that is not possible, deal with it in your application.
Based on the following link click here
mysql> LOCK TABLE t WRITE, t AS t1 READ;
mysql> INSERT INTO t SELECT * FROM t;
ERROR 1100: Table 't' was not locked with LOCK TABLES
mysql> INSERT INTO t SELECT * FROM t AS t1;
LOCK TABLE users WRITE, users AS t1 READ;
INSERT INTO users (nick, email)
SELECT :nick, :email
FROM Dual
WHERE NOT EXISTS (
SELECT *
FROM users AS t1
WHERE nick = :nick OR email = :email
)
UNLOCK TABLES;