Using MySQL variables in a query - mysql

I am trying to use this MySQL query:
SET #a:=0; UPDATE tbl SET sortId=#a:=#a+1 ORDER BY sortId;
Unfortunately I get this error:
"Parameter '#a' must be defined"
Is it possible to batch commands into 1 query like this, or do I need to create a stored procedure for this?

You placed the variable assignment in a wrong place:
SET #a:=0; UPDATE tbl SET #a:=sortId=#a+1 ORDER BY sortId;

I think you need a stored procedure for any kind of statefullness. Is there a reason you have been reluctant to create one?
Also how are you running this code? Is it in an editor like SQL Server Manager or as a string in a program?

Your query works fine for me. I tried running it from MySQL Query Browser:
CREATE TABLE tbl (Id INT NOT NULL, SortId INT NOT NULL);
INSERT INTO tbl (Id, SortId) VALUES (1, 9), (2, 22), (3, 13);
SET #a:=0;
UPDATE tbl SET sortId=#a:=#a+1 ORDER BY sortId;
SELECT * From tbl;
Result:
Id sortId
1 1
2 3
3 2
Note that when running queries from MySQL Query Browser should enter one query per line, not two on one line as you are doing. If you want to put this in a stored procedure (probably a good idea) you can create it like this:
DELIMITER //
CREATE PROCEDURE updateSortIds()
BEGIN
SET #a:=0;
UPDATE tbl SET SortId=#a:=#a+1 ORDER BY SortId;
END //
DELIMITER ;
And to execute it, use this:
CALL updateSortIds();

Related

How to create stored procedure that inserts both input and data from select statement after first insert

I am trying to create a stored procedure in MySQL that will add rows to two different tables. The first table (sites) has an id column set to auto_increment which I would like to include in the second insert statement to the sitesByUser table. I've tried some ideas based off this excellent post: https://dba.stackexchange.com/questions/2973/how-to-insert-values-into-a-table-from-a-select-query-in-postgresql but I get various errors, such as the one listed below. I suspect that part of my problem is that I'm trying to both add both userInput and SELECT id FROM sites WHERE id=LAST_INSERT_ID() to the same table, but I'm not sure what to do to get that to work.
CREATE PROCEDURE createSite(IN siteName VARCHAR(2048), IN userInput VARCHAR(255))
BEGIN
INSERT INTO sites(siteName, user) VALUES (siteName, userInput);
INSERT INTO sitesByUser(user, site) userInput, SELECT id FROM sites WHERE id=LAST_INSERT_ID();
SELECT * FROM sitesByUser WHERE id=LAST_INSERT_ID();
END
The response from MySQL:
Error while performing Query.
ER_PARSE_ERROR
ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'userInput, SELECT id FROM sites WHERE id=LAST_INSERT_ID();
SELECT * FROM sitesBy' at line 3
Try this
SET #last_id_in_table1 = LAST_INSERT_ID();
SELECT * FROM sitesByUser WHERE id=#last_id_in_table1;
Hope this helps
It seems that the correct way to do this is to store the LAST_INSERT_ID() in a variable as described here: How to declare a variable in MySQL? I'm not sure that I should be using the # symbol in front of the variable since that seems to make it a user-defined variable which means it is session-specific which is probably too wide in scope for my needs, but so far, this successfully creates a stored procedure that I think will work. I'll update this post if it does not.
CREATE PROCEDURE createSite(IN siteName VARCHAR(2048), IN userInput VARCHAR(255))
BEGIN
INSERT INTO sites(siteName, user) VALUES (siteName, userInput);
SET #last_id_in_sites = LAST_INSERT_ID();
INSERT INTO sitesByUser(user, site) VALUES (userInput, #last_id_in_sites);
SELECT * FROM sitesByUser WHERE id=LAST_INSERT_ID();
END

Why MySQL (MariaDB) update transaction returns '0 row affected'?

Hello everyone.
I have something weird with MySQL.
(Oh, first of all, sorry for my poor English.)
I've made the simple table and stored procedure. Table definition is...
CREATE TABLE numTable (
firstNum INT,
secondNum INT
);
INSERT INTO numTable (firstNum, secondNum) VALUES (1, 2);
and the SP is...
DELIMITER ;;
CREATE PROCEDURE updateNum (
IN num1 INT,
IN num2 INT
)
BEGIN
START TRANSACTION;
UPDATE numTable
SET firstNum = num1, secondNum = num2;
COMMIT;
END ;;
DELIMITER ;
Then I executed the SP like this...
CALL updateNum (3, 4);
And MySQL returns ...
0 row(s) affected
When I saw this result, I thought 'Is there any syntax error?' But, no. UPDATE query worked fine. numTable's data changed from (1, 2) to (3, 4).
And I also found this. I removed the 'START TRANSACTION;' and 'COMMIT' statement. and execute updateNum SP again. The result was ...
1 row(s) affected
This time, UPDATE query worked fine too. numTable's data has successfully changed.
Why this difference has happen? Is there a way I can get a right affected rows with using TRANSACTION statement?
I tested this at MySQL 5.6.27, MariaDB 10.0.21 and MariaDB 10.1.8 and results are same as above.
Thank you for read my question.
You will get the affected rows using
ROW_COUNT()
so, SELECT ROW_COUNT()
at the end
similar to #Leow's, but I have found that without a transaction, and without it happening immediately after the update, all is lost. So:
START TRANSACTION;
update ...
select row_count() into #theCount; -- saved for posterity, perhaps for use at end
COMMIT;
select #theCount;

SQL check if existing row, if not insert and return it

I'm having a problem with my sql query. I need to insert a data that needs to be checked first if it is existing or not. If the data is existing the sql query must return it, if not insert and return it. I already google it but the result is not quite suitable to my problem. I already read this.
Check if a row exists, otherwise insert
How to 'insert if not exists' in MySQL?
Here is a query that' I'm thinking.
INSERT INTO #tablename(#field, #conditional_field, #field, #conditional_field)
VALUES(
"value of field"
(SQL QUERY THAT CHECK IF THERE IS AN EXISTING DATA, IF NOT INSERT THE DATA and RETURN IT, IF YES return it),
"value of feild",
(SQL QUERY THAT CHECK IF THERE IS AN EXISTING DATA, IF NOT INSERT THE DATA and RETURN IT, IF YES return it)
);
Please take note that the conditional field is a required field so it can't be NULL.
Your tag set is quite weird, I'm unsure you require all the technologies listed but as long as Firebird is concerned there's UPDATE OR INSERT (link) construction.
The code could be like
UPDATE OR INSERT INTO aTable
VALUES (...)
MATCHING (ID, SomeColumn)
RETURNING ID, SomeColumn
Note that this will only work for PK match, no complex logic available. If that's not an option, you could use EXECUTE BLOCK which has all the power of stored procedures but is executed as usual query. And you'll get into concurrent update error if two clients execute updates at one time.
You could split it out into 2 steps
1. run a select statement to retrieve the rows that match your valus. select count (*) will give you the number of rows
2. If zero rows found, then run the insert to add the new values.
Alternatively, you could create a unique index form all your columns. If you try to insert a row where all the values exist, an error will be returned. You could then run a select statement to get the ID for this existing row. Otherwise, the insert will work.
You can check with if exists(select count(*) from #tablename) to see if there is data, but with insert into you need to insert data for all columns, so if there is only #field missing, you cant insert values with insert into, you will need to update the table and go with a little different method. And im not sure, why do you check every row? You know for every row what is missing? Are you comparing with some other table?
You can achieve it using MySQL stored procedure
Sample MySQL stored procedure
CREATE TABLE MyTable
(`ID` int, `ConditionField` varchar(10))
;
INSERT INTO MyTable
(`ID`, `ConditionField`)
VALUES
(1, 'Condition1'),
(1, 'Condition2')
;
CREATE PROCEDURE simpleproc (IN identifier INT,ConditionData varchar(10))
BEGIN
IF (SELECT ID FROM MyTable WHERE `ConditionField`=ConditionData) THEN
BEGIN
SELECT * FROM MyTable WHERE `ConditionField`=ConditionData;
END;
ELSE
BEGIN
INSERT INTO MyTable VALUES (identifier,ConditionData);
SELECT * FROM MyTable WHERE `ConditionField`=ConditionData;
END;
END IF;
END//
To Call stored procedure
CALL simpleproc(3,'Condition3');
DEMO

want to write trigger for two different databases in Mysql

Is there any way to create triggers on two different databases in Mysql? my requirement is like:-
database: test1 -> table: tmp1
database: test2 -> table: tmp2
now I have to use trigger on test1 insert operation happens on tmp1 a value has to be inserted into tmp2 of test2 database. And also vice a verse.
i.e. one more trigger on tmp2 table of test2 database, if insert into tmp2 then inserted into tmp1 table of test1 database.
I have tried to write the trigger on both but I think it will goes into loop to insert each other tables.
DELIMITER $$
CREATE TRIGGER trigger_ad_t1 AFTER insert ON `test1`.tmp1
FOR EACH ROW
Begin
INSERT INTO `test2`.tmp2 VALUES (NEW.employeeNumber,New.fname,New.lname)
END$$
DELIMITER ;
same type of trigger written for insert into tmp1 after insert into tmp2 table.
One more thing I have tested this trigger on my local pc which has mysql 5.1.63 but when I am trying this trigger on my testing server which has mysql 5.0.45 then it gives me syntax error(1064). Don't know what is the problem?
UPDATE:
Can anybody help me to get rid of it.
Thanks
Use fully qualified table names in your trigger.
I.e.
db1.test1.* and d2.test2.*
P.S. After looking at your SQL one more time I realised that you ARE doing the above already.
Edit: Comment field is to restrictive to post code, so here is how you prevent the endless insert loop (assuming employeeNumber is unique key):
Edited code:
IF NOT EXISTS(SELECT employeeNumber FROM otherDB.otherTable WHERE employeeNumber = NEW.employeeNumber) THEN
INSERT INTO otherDB.otherTable VALUES (NEW.employeeNumber,New.fname,New.lname)
END IF;
Correction was needed in the code provided originally:
... EXISTS(SELECT * FROM otherDB.otherTable ...) is replaced with
... EXISTS(SELECT employeeNumber FROM otherDB.otherTable ...)
The reason being that the first query will always return true because the inner query SELECT * FROM ... always returns one record containing the number of results =>
EXISTS(SELECT * FROM ...) is always true

Mysql Loop through selected column and execute Insert query in the loop

I'm trying to loop over selected slugs and execute little complicated INSERT INTO SELECT query.
slugs[iteration] usage is not a correct mysql syntax. But I have to access fetched slugs one by one inside the query. How Could I achieve that ?
DELIMITER $$
CREATE PROCEDURE create_sitemap_from_slugs()
BEGIN
SELECT `slug` INTO slugs FROM slug_table;
SELECT COUNT(*) INTO count FROM slug_table;
SET iteration = 0;
START TRANSACTION;
WHILE iteration < count DO
INSERT INTO line_combinations
SELECT REPLACE(`line`, '{a}', slugs[iteration]) AS `line`
FROM line_combinations
WHERE `line` LIKE CONCAT('%/', '{a}', '%');
SET iteration = iteration + 1;
END WHILE;
COMMIT;
END
$$
DELIMITER ;
Btw, I don't want to use any external programming language to make this, this procedure will be working for billions of rows. I read Loops in SQL is not a good way due to performance concerns.
If you suggest another way I would accept this also.
I asked another detailed question but couldn't get an answer. if you would like to check that also : https://stackoverflow.com/questions/35320494/fetch-placeholders-from-table-and-place-into-generated-line-combination-pattern
So for each line with {a} you need to insert COUNT(*) from slug_table times values filled with slug value.
It seems you can do that just in one INSERT from SELECT
INSERT INTO line_combinations
(SELECT REPLACE(lc.line, '{a}', st.slug) AS `line`
FROM line_combinations lc, slug_table st
WHERE lc.line LIKE CONCAT('%/', '{a}', '%');
UPDATE:
You can create a temp table line_combinations2 and insert all the records
FROM line_combinations
WHERE line LIKE CONCAT('%/', '{a}', '%')
into the temp table. Then just use the temp table in the INSERT instead of original one