mysql if not exist - mysql

I am coming from MSSQL, and now using Mysql, this may be a easy one but how do you execute a
if not exist statement. thanks
IF NOT EXISTS(SELECT * from users WHERE Username = spUsername)
BEGIN
INSERT into users(ID,Username,Password,Email,Birthdate,DateJoin)
VALUES(UUID(),spUsername,spPassword,spEmail,spBirthDate,NOW());
END

Im not a database expert by any means but this is how I do it.
http://www.somethinghitme.com/2010/05/06/mysql-stored-procedures-if-not-exists/
DECLARE SomeId int;
DECLARE CheckExists int;
SET CheckExists = 0;
SELECT 1 INTO CheckExists from lookup_table WHERE someField = in_SomeParam LIMIT 1;
IF (CheckExists > 0) THEN
SELECT id INTO SomeId FROM lookup_table WHERE someField = in_SomeParam;
ELSE
INSERT INTO lookup_table (someField ) VALUES(in_SomeParam);
SELECT SomeId = LAST_INSERT_ID();
END IF;

Related

SQL query for insertion multiple data using for loop

My data set
Tabel Name Users
unique_id uid
123487.1 1000
123488.1
123489.1
123490.1
As shown above this is my existing data and i want to add uid, so my data should be displayed as shown below.
unique_id uid
123487.1 1000
123488.1 1001
123489.1 1002
123490.1 1003
You don't need cursors for this. Just do an update:
select #u := max(user_id)
from users;
update users
set user_id = (#u := #u + 1)
where user_id is null
order by unique_id;
Providing that uid value is the only a single value in your data set, you can use that simple query:
select unique_id, first_value(uid) over(order by unique_id) + row_number() over(order by unique_id) - 1 fv from users;
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=d8102c3ef394d304eefa9d42b5a479ba
Best regards.
You can create a procedure like this:
CREATE PROCEDURE uid_update()
BEGIN
DECLARE Done_c INT;
DECLARE v_min_id INT;
declare number_plus int;
declare v_cur int;
DECLARE curs CURSOR FOR
select ROW_NUMBER() OVER (order by unique_id) rn
from testTable
where uid is null;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET Done_c = 1;
SELECT max(uid) INTO number_plus FROM testTable;
OPEN curs;
SET Done_c = 0;
REPEAT
FETCH curs INTO v_cur;
select min(unique_id) into v_min_id
from testTable
where uid is null;
update testTable
set uid = number_plus + v_cur
where uid is null
and unique_id = v_min_id ;
commit;
UNTIL Done_c END REPEAT;
CLOSE curs;
END
And then call that procedure like this:
call uid_update;
The values will then be updated as you asked for.
Here is the DEMO.

Mysql stored procedure cant get the id of the object

CREATE DEFINER=`root`#`localhost` PROCEDURE `add_card`(author VARCHAR(50),newtext VARCHAR(600),title VARCHAR(200),newSource VARCHAR(2300), username VARCHAR(50), tags VARCHAR(600))
BEGIN
DECLARE strLen INT DEFAULT 0;
DECLARE SubStrLen INT DEFAULT 0;
DECLARE cardId INT DEFAULT 0;
DECLARE tagId INT DEFAULT 0;
DECLARE tempTagId INT DEFAULT -1;
DECLARE temp VARCHAR(200);
INSERT INTO cards (author,text,title,username,source) VALUES (author,newtext,title,username,newSource);
SET #cardId = LAST_INSERT_ID();
Select #cardId;
IF tags IS NULL THEN
SET tags = '';
END IF;
do_this:
LOOP
SET strLen = CHAR_LENGTH(tags);
SET #temp = SUBSTRING_INDEX(tags, ',', 1);
SELECT tagId INTO tempTagId FROM tag WHERE tagName = #temp limit 1;
Select tempTagId;
SELECT tagId FROM tag WHERE tagName = 'ss';
IF tempTagId = -1 THEN
INSERT INTO tag (tagName) VALUES (#temp);
SET #tagId = LAST_INSERT_ID();
select #tagId+10;
IF NOT EXISTS (SELECT * FROM cards_tags WHERE tagId = #tagId AND cardId = #cardId) THEN
INSERT INTO cards_tags (tagId,cardId) VALUES (#tagId,#cardId);
Select #cardId;
END IF;
ELSE
IF NOT EXISTS (SELECT * FROM cards_tags WHERE tagId = tempTagId AND cardId = #cardId) THEN
INSERT INTO cards_tags (tagId,cardId) VALUES (tempTagId,#cardId);
select #tagId;
END IF;
END IF;
SET SubStrLen = CHAR_LENGTH(SUBSTRING_INDEX(tags, ',', 1)) + 2;
SET tags = MID(tags, SubStrLen, strLen);
IF tags = '' THEN
LEAVE do_this;
END IF;
END LOOP do_this;
END
It is the damnest thing i have ever seen i guess. I have this stored procedure and in the line
SELECT tagId FROM tag WHERE tagName = 'ss';
I am trying to get the id of the object but it is returning 0.
created another stored procedure
CREATE DEFINER=`root`#`localhost` PROCEDURE `adds_card`()
BEGIN
DECLARE temp VARCHAR(200);
SET #temp ='ss';
SELECT tagId FROM tag WHERE tagName = #temp;
END
And this returns 3 which is true. Why is the first one returning 0? Driving me really crazy. Spent 5 hours on it and couldnt solve it.
One line in your code is:
SELECT tagId INTO tempTagId FROM tag WHERE tagName = #temp limit 1;
#temp is not defined anywhere, although temp is. So, #temp defaults to NULL (or to the previous session value) and the WHERE clause likely fails.
I strongly recommend prepending local variables with a prefix, so they are not confused with column names. So I would recommend:
SELECT tagId INTO v_tempTagIdFROM tag WHERE tagName = v_temp limit 1;
or:
SELECT v_tempTagIdFROM := tagId
FROM tag
WHERE tagName = v_temp
LIMIT 1;

How to write this query in SQL server 2008

I have a requirement to insert more than one record into the table where the stored procedure will return the value for insertion. Please consider my logic.
Query Logic
foreach(var a in (select id from table1))
{
insert into table2 values(a,DateTime.Now)
}
I need the same above logic needs to be done in SQL server. Any help to this solution will be appreciated.
Thanks,
declare #a int=0
while(#a<10)
begin
if(#a in (select id from table1))
begin
insert into table2 values(a,DateTime.Now)
set #a=#a+1
end
end
I tried this and working well. Thanks to #Nikola Markovinović
insert into table2(idColumn, dateColumn) select id, getdate() from table1
hope this helps..
DECLARE #intFlag INT
SET #intFlag = 1
WHILE (#intFlag <=5)
BEGIN
PRINT #intFlag
SET #intFlag = #intFlag + 1
IF #intFlag = 4
BREAK;
END
GO
declare #a int = 0, #n int, #i int = 1
select #n=COUNT(*) from table1
while #i < #n
begin
insert into table2 values
select x.a,Getdate() from
(select ROW_NUMBER() over (order by [key]) as slno,* from table1 ) as x where x.slno = #i
set #i=#i+1;
end

mysql procedure syntax error

I get an error by sending the following query (MYSQL 5.0):
DELIMITER //
CREATE PROCEDURE relationTable ()
BEGIN
DECLARE articlecount int;
DECLARE keywordcount int;
DECLARE articlehits int;
DECLARE ac int DEFAULT 0;
DECLARE kc int;
DECLARE articleid int;
DECLARE word varchar(100);
DECLARE word_id int;
SET articlehits = 0;
SET articlecount = (SELECT count(id) from articles);
SET keywordcount = (SELECT count(id) from keywords);
outerloop: WHILE (ac < articlecount) DO
SET kc = 0;
SET articleid = (SELECT id from articles LIMIT 1 OFFSET ac);
innerloop: WHILE (kc < keywordcount) DO
IF (articlehits < 5) THEN
SELECT keyword, id INTO word, word_id from keywords LIMIT 1 OFFSET kc;
IF (0 < (SELECT COUNT(id) from articles WHERE id=articleid AND CONCAT(title, " ",text) REGEXP word)) THEN
INSERT INTO articles (id, articleID, keywordID, type) VALUES(NULL, articleid, word_id, 'type1');
SET articlehits = articlehits + 1;
END IF;
SET kc = kc + 1;
ELSE
SET kc = keywordcount;
END IF;
END WHILE innerloop;
SET ac = ac + 1;
END WHILE outerloop;
END;
//
DELIMITER ;
This produces the following error:
ERROR 1064 (42000): 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 'LIMIT 1 OFFSET ac); innerloop: WHILE (kc <
keywordcount) DO TO word, word_id from' at line 15
Any idea why this happens?
(Wrote this to create a relation table between articles and keywords, to enable smart-links in article view.)
Try to remove the while labels:
WHILE (ac < articlecount) DO
SET kc = 0;
SET articleid = (SELECT id from articles LIMIT 1 OFFSET ac);
WHILE (kc < keywordcount) DO
IF (articlehits < 5) THEN
SELECT keyword, id INTO word, word_id from keywords LIMIT 1 OFFSET kc;
IF (0 < (SELECT COUNT(id) from articles WHERE id=articleid AND CONCAT(title, " ",text) REGEXP word)) THEN
INSERT INTO articles (id, articleID, keywordID, type) VALUES(NULL, articleid, word_id, 'type1');
SET articlehits = articlehits + 1;
END IF;
SET kc = kc + 1;
ELSE
SET kc = keywordcount;
END IF;
END WHILE;
SET ac = ac + 1;
END WHILE;
MySQL has connection-specific user-defined variables of the form #varname and declared procedure variables of the type you are using in your code sample. In my experience with procedures, sometimes only one of the types is allowed, and if I recall correctly, one of those situations may be when SELECTing INTO. You might try using user-defined variables here, as follows:
SET articleid = (SELECT id from articles LIMIT 1 OFFSET ac);
innerloop: WHILE (kc < keywordcount) DO
IF (articlehits < 5) THEN
SELECT keyword, id INTO #word, #word_id from keywords LIMIT 1 OFFSET kc;
Just an idea.
One problem may be the SET acticleid = (SELECT...). Try with SELECT .. INTO:
SELECT id INTO #articleid FROM articles LIMIT 1 OFFSET ac;
Variable LIMIT in stored procedures is only supported in new MySQL versions. Note that since you dont have an ORDER BY you will get a random row. It looks like you want to use a CURSOR instead. See docs.
At the risk of seeming over-critical, I believe you should rewrite this procedure to use cursors for traversing your databases, instead of individual selects with LIMIT.
see Cursors in MySQL Docs
Thank for your help so far.
The idea of Tom Haws proved to be correct. The variables for a SELECT INTO statement have to be user-defined.
I edited my code to use cursors, and user-defined variables as followed:
delimiter //
CREATE PROCEDURE relationTable ()
BEGIN
DECLARE articlehits int;
DECLARE looparticles int DEFAULT TRUE;
DECLARE loopwords int DEFAULT TRUE;
DECLARE done INT DEFAULT FALSE;
DECLARE keywordcursor CURSOR FOR SELECT keyword, id FROM keywords;
DECLARE articlecursor CURSOR FOR SELECT id FROM articles;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN articlecursor;
WHILE (looparticles) DO
FETCH articlecursor INTO #articleid;
IF done THEN SET looparticles = FALSE;
ELSE
SET articlehits = 0;
OPEN keywordcursor;
WHILE (loopwords) DO
FETCH keywordcursor INTO #word, #wordid;
IF (articlehits < 5) AND NOT done THEN
IF (0 < (SELECT COUNT(id) FROM articles WHERE id=#articleid AND CONCAT(title, " ", text) REGEXP #word)) THEN
INSERT INTO keyword_article_rel (id, meldungID, wordID) VALUES(NULL, #articleid, #wordid);
SET articlehits = articlehits + 1;
END IF;
ELSE
SET loopwords = FALSE;
CLOSE keywordcursor;
SET done = FALSE;
END IF;
END WHILE;
END IF;
END WHILE;
CLOSE articlecursor;
END;
//
delimiter ;
And now I get an other error that I really can't explain:
ERROR 1064 (42000): 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 '; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN articlecursor; W' at line 6
This error confuses me because it can't have a problem with the handler. The handler is declared as in the example of the mysql-documentation. Could the problem be that I can't create two cursors like this?

How to loop the data and if username exists append incremental number e.g. JOHSMI1 or JOHSMI2

I have a userid table
UserId
JHOSMI
KALVIE
etc...
What I would like to do is create a select statement and pass user id, if the userid already exists then append 1 to the id, This gets complicated if you already have JHOSMI, JHOSMI1, then I want to return JHOSMI2.
Really appreciate help here.
Thanks in advance
edited 21-Jul
this is what i got so far.. but not working the way
select #p AS StaffID,
#old_p := #p,
#Cnt := #Cnt+1 As Lvl,
(SELECT #p :=Concat(#i, #Cnt)
FROM departmenttaff
WHERE upper(trim(UserId)) = upper(trim(StaffID))
AND upper(trim(department)) like upper(trim('SERVICE'))
) AS dummy
FROM (
SELECT
#i := upper(trim('JOHSMI')),
#p := upper(trim('JOHSMI')),
#old_p :='',
#Cnt:=0
) vars,
departmenttaff p
WHERE #p <> #old_p
order by Lvl Desc LIMIT 1;
This will do exactly what you want. You will need a unique constraint on your column.
You might also need to add in error code if success = 0.
This is in MSSQL, you will need to add the relevant commands for MySQL. I do not have MySQL so I cannot test it.
NOTE: You can replace the try catch with some IF EXISTS logic. I just prefer the try catch because its more stable for multiple threads.
begin tran
select * from #tmp
declare #success bit
declare #name varchar(50)
declare #newname varchar(50)
declare #nextid int
declare #attempts int
set #name = 'brad2something'
set #success = 0
set #attempts = 0
while #success = 0 and #attempts < 5 begin
begin try
set #attempts = #attempts + 1 -- failsafe
set #newname = #name
if exists (select * from #tmp where username = #name) begin
select #nextid = isnull(max(convert(int, substring(username, LEN(#name) + 1, 50))), 0) + 1
from #tmp where username like #name + '%' and isnumeric(substring(username, LEN(#name) + 1, 50)) = 1
set #newname = #name + CONVERT(varchar(20), #nextid)
end
insert into #tmp (username) values (#newname)
set #success = 1
end try begin catch end catch
end
--insert into #tmp (username)
--select
select #success
select * from #tmp
rollback
/*
drop table #tmp
create table #tmp (
username varchar(50) not null unique
)
insert into #tmp (username)
select 'brad'
union all select 'brad1'
union all select 'brad2something5'
union all select 'brad2'
union all select 'laney'
union all select 'laney500'
*/
I noticed you want to back fill data. If you want to back fill then this will work. It is extremely inefficient but there is no way around it. There is optimizing code you can put in for when an "error" occurs to prevent all previous counts from happening, but this will work.
begin tran
select * from #tmp
declare #success bit
declare #name varchar(50)
declare #newname varchar(50)
declare #nextid int
declare #attempts int
set #name = 'laney'
set #success = 0
set #attempts = 0
set #nextid = 1
while #success = 0 and #attempts < 5 begin
begin try
if exists (select * from #tmp where username = #name) begin
set #newname = #name + CONVERT(varchar(20), #nextid)
while exists (select * from #tmp where username = #newname) begin
set #nextid = #nextid + 1
set #newname = #name + CONVERT(varchar(20), #nextid)
end
end else
set #newname = #name
set #attempts = #attempts + 1 -- failsafe
insert into #tmp (username) values (#newname)
set #success = 1
end try begin catch end catch
end
--insert into #tmp (username)
--select
select #success
select * from #tmp
rollback
/*
drop table #tmp
create table #tmp (
username varchar(50) not null unique
)
insert into #tmp (username)
select 'brad'
union all select 'brad1'
union all select 'brad2something5'
union all select 'brad2'
union all select 'laney'
union all select 'laney500'
*/
Is it mandatory to have the count in same column? its better to have it in a different integer column. Anyways, if this is the requirement then select userid from table where userid like 'JHOSMI%', then do extract the number using mysql substr function.
For other people who might find this, here's a version in PostgreSQL:
create or replace function uniquify_username(varchar) returns varchar as $$
select $1 || coalesce((max(num) + 1)::varchar, '')
from
(select
substring(name, '^(.*?)[0-9]*$') as prefix,
coalesce(substring(name, '.*([0-9]+)$'), '0')::integer as num
from user1) users
where prefix = $1
$$ LANGUAGE sql;
I think it could be adapted to MySQL (though probably not as a stored procedure) but I don't have a MySQL server handy to do the conversion on.
Put a UNIQUE constraint on the column.
You didn't say what language you are using, so use this pseudo code
counter = 0
finished = false
while finished = false
{
try
{
if counter >= 1 then name = name + counter
counter = counter + 1
insert into table (name)
}
}
This code is extremely finicky. But will get the job done and there is no real other way to do this except for in sql, and you will always have some type of try catch to avoid two processes running at the same time. This way you use the unique key constraint to force the error, and supress it because it is expected.
I in no way condone using try/catch for business logic like this, but you are putting yourself in a situation thats unavoidable. I would say put the ID in a seperate column and make a unique constraint on both fields.
Proper solution:
Columns: Name, ID, Display Name
Unique constraint on: Name, ID
Display Name is a computed column (virtual) is Name + ID
If you do it this way, then all you have to do is INSERT INTO table (name, (select max() from table))