sql if exists simple syntax error - mysql

I keep getting this syntax error but can't find anything wrong with it when comparing to other examples.
if EXISTS (select 1 from City where name = 'Perth')
THEN Print 'Record exits - Update'
ELSE Print 'Record doesn''t exist - Insert'
I find error:
#1064 - 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 'if EXISTS (select
1 from City where name = 'Perth') THEN Print 'Record e' at line 1
I get this both on zend cloud and normal phpmyadmin mysql 5

That isn't actually a valid MySQL query. It looks like you are trying to mix together SQL with how you want to display output based on the whether the query exists or not. You can use this to return whether or not Perth exists in SQL:
SELECT EXISTS(SELECT 1 FROM City WHERE name = 'Perth')
This will return 1 or 0, which you can then parse with your server-side scripts. The reason it is giving you a syntax error is because MySQL IF statements take the form IF(condition, <action if true>, <action if false>), with no use of THEN or ELSE (as is common in programming languages). Also, MySQL doesn't have an explicit PRINT statement, but you could use SELECT to somewhat accomplish what you want above (note that we can remove EXISTS as False will be implied if the result returns nothing):
SELECT IF(
(SELECT 1 FROM City WHERE name = 'Perth'),
(SELECT 'Record exists - update'),
(SELECT 'Record does not exist - Insert')
)

You need to use 'select' instead of print in following way
select IF((select 1 from city where name='Perth'),
'Record exits - Update','Record does not exist - Insert');
SQL Fiddle Demo. Following shows the use of IF in select Statement
IF((select 1 from city where name='Perth'),
'Record exits - Update','Record does not exist - Insert');
IF contains two messages.
First : 'Record exits - Update' Second : 'Record does not exist - Insert'
First message is printed if (select 1 from city where name='Perth') has some results(equivalent to EXISTS) otherwise you will get second message

An alternative way: using a grouping function will always return a record. If there are no records to operate on, the result of the group by function will be NULL. You could use that as a decision mechanism.
postgres=# create table city(name text);
CREATE TABLE
postgres=#
postgres=# select COALESCE( max('Record exists - Update'), 'Record doesn''t exist - Insert' ) as state
postgres-# from city
postgres-# where name = 'Perth';
state
-------------------------------
Record doesn't exist - Insert
(1 row)
postgres=#
postgres=# insert into city values('Perth');
INSERT 0 1
postgres=#
postgres=# select COALESCE( max('Record exists - Update'), 'Record doesn''t exist - Insert' ) as state
postgres-# from city
postgres-# where name = 'Perth';
state
------------------------
Record exists - Update
(1 row)

Related

A variable is cut in a wrong way but now sure why?

I'm writing a script that locates all branches of a specific repo that haven't received any commits for more than 6 months and deletes them (after notifying committers).
This script will run from Jenkins every week, will store all these branches in some MySQL database and then in the next run (after 1 week), will pull the relevant branch names from the database and will delete them.
I want to make sure that if for some reason the script is run twice on the same day, relevant branches will not get added again to the database, so I check it using a SQL query:
def insert_data(branch_name):
try:
connection = mysql.connector.connect(user=db_user,
host=db_host,
database=db_name,
passwd=db_pass)
cursor = connection.cursor(buffered=True)
insert_query = """insert into {0}
(
branch_name
)
VALUES
(
\"{1}\"
) where not exists (select 1 from {0} where branch_name = \"{1}\" and deletion_date is NULL) ;""".format(
db_table,
branch_name
)
cursor.execute(insert_query, multi=True)
connection.commit()
except Exception as ex:
print(ex)
finally:
cursor.close()
connection.close()
When I run the script, for some reason, the branch_name variable is cut in the middle and then the query that checks if the branch name already exists in the database fails:
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 'where not exists (select 1 from branches_to_delete where branch_name = `AUT-1868' at line 8
So instead of checking for 'AUT-18681_designer_create_new_name_if_illegal_char_exist' it checks for 'AUT-1868' which doesn't exist in the database.
I've tried the following:
'{1}'
"{1}"
{1}
But to no avail.
What am I doing wrong?
Using WHERE statement in INSERT INTO query is illegal:
INSERT INTO `some_table`(`some_column`)
VALUES ('some_value') WHERE [some_condition]
So, the above example is not valid MySQL query. For prevent duplication of branch_name you should add unique index on your table like:
ALTER TABLE `table` ADD UNIQUE INDEX `unique_branch_name` (`branch_name`);
And after this you can use next query:
INSERT INTO `table` (`branch_name`) VALUES ('branch_name_1')
ON DUPLICATE KEY UPDATE `branch_name` = `branch_name`;
Pay attention: If your table have auto-increment id, it will be incremented on each insert attempt
Since MySQL 8.0 you can use JASON_TABLE function for generate pseudo table from your values filter it from already exists values and use it fro insert. Look here for example
I don't see anything wrong assuming the source of the branch_name is safe (you are not open to SQL Injection attacks), but as an experiment you might try:
insert_query = f"""insert into {db_table}(branch_name) VALUES(%s) where not exists
(select 1 from {db_table} where branch_name = %s and deletion_date is NULL)"""
cursor.execute(insert_query, (branch_name, branch_name))
I am using a prepared statement (which is also SQL Injection-attack safe) and thus passing the branch_name as a parameters to the execute method and have also removed the multi=True parameter.
Update
I feel like a bit of a dummy for missing what is clearly an illegal WHERE clause. Nevertheless, the rest of the answer suggesting the use of a prepared statement is advice worth following, so I will keep this posted.

MySQL workbench error 1064 when adding trigger

I am new to SQL and more specifically using MySQL Workbench.
I have created a database with two tables Grades and GPAList.
I want to take the average value of every entry in Grades (grouped by student id [sid is the name of the column]) once I have those averages, store them in the GPAList table with their corresponding students. This is intended to trigger every time a new entry is added to Grades.
This is the trigger that I have created:
CREATE DEFINER = CURRENT_USER TRIGGER `ProjectName`.`Grades_AFTER_UPDATE_1` AFTER UPDATE ON `Grades` FOR EACH ROW
BEGIN
SELECT sid, SUM ( CASE grade
when 'A' then 4.0
when 'B' then 3.5
when 'C' then 3.0
when 'D' then 2.5
when 'F' then 1.0
else 0
end
) / COUNT(*) Grades
INTO GPAList
FROM Grades
GROUP BY sid;
END
The error that I am encountering is:
Error 1064: 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 '' at
line 1 SQL Statement: CREATE DEFINER = CURRENT_USER TRIGGER
`ProjectName`.`Grades_AFTER_UPDATE_1` AFTER UPDATE ON `Grades` FOR EACH ROW
FOLLOWS `Grades_AFTER_UPDATE`
When I write this code in the workbench, no syntax errors are shown. When I try to apply this trigger, my code is converted to:
DROP TRIGGER IF EXISTS `ProjectName`.`Grades_AFTER_UPDATE_1`;
DELIMITER $$
USE `ProjectName`$$
CREATE DEFINER = CURRENT_USER TRIGGER `ProjectName`.`Grades_AFTER_UPDATE_1` AFTER UPDATE ON `Grades` FOR EACH ROW FOLLOWS `Grades_AFTER_UPDATE`
$$
DELIMITER ;
Only after clicking apply once more do I see the 1064 error listed above. Is there some easy fix that I am missing?
There is a Grades_AFTER_UPDATE that Grades_AFTER_UPDATE_1 is following, so that shouldn't be the problem.
I'm not sure why you would want to store all averages after a single insert, but the correct insert logic is something like this:
INSERT INTO GPALIST(sid, grades)
SELECT sid,
AVG (CASE grade
when 'A' then 4.0
when 'B' then 3.5
when 'C' then 3.0
when 'D' then 2.5
when 'F' then 1.0
else 0
end) as Grades
FROM Grades
GROUP BY sid;
I suspect the trigger would want to access new. somewhere along the way.

IF NOT EXIST NOT WORKING

IF NOT EXISTS(SELECT * FROM `user` WHERE `name`='Rutvij' AND `lang`='python')
BEGIN
INSERT INTO `user` VALUES ('Rutvij', 'python', 25)
END
ELSE
BEGIN
UPDATE user SET `name`='Kanzaria' WHERE `name`='Rutvij'
END
I am trying the above query in phpmyadmin sql area. I am using xampp. It is throwing error stating that
1064 - 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 'IF EXISTS(SELECT * FROM user)
SELECT name FROM use' at line 1
I have also tried the below code
IF NOT EXISTS(SELECT * FROM user WHERE name='Rutvij' AND lang='python')
BEGIN
INSERT INTO user VALUES ('Rutvij', 'python', 25)
END
ELSE
BEGIN
INSERT INTO user VALUES ('Kanzaria', 'python', 25)
END
Struggling for so long. Kindly help. Thanks!!
MySQL doesn't permit if logic, unless you are in a programming block (stored procedure, trigger, or function).
Fortunately, you can do the same with WHERE logic:
INSERT INTO user
SELECT 'Rutvij', 'python', 25
FROM DUAL
WHERE NOT EXISTS (SELECT 1 FROM user WHERE name = 'Rutvij' AND lang = 'python')
UNION ALL
SELECT 'Kanzaria', 'python', 25
FROM DUAL
WHERE EXISTS (SELECT 1 FROM user WHERE name = 'Rutvij' AND lang = 'python');
MySQL should process the SELECT before the INSERT, so only one row should be inserted.
Or, you can do this as two INSERTs but in the opposite order:
INSERT INTO user
SELECT 'Kanzaria', 'python', 25
FROM DUAL
WHERE EXISTS (SELECT 1 FROM user WHERE name = 'Rutvij' AND lang = 'python');
INSERT INTO user
SELECT 'Rutvij', 'python', 25
FROM DUAL
WHERE NOT EXISTS (SELECT 1 FROM user WHERE name = 'Rutvij' AND lang = 'python');
This is not a query, this would be an sql script with control flow logic, which is not allowed in mysql outside stored programs (procedures, functions, triggers). Even if you encapsulated the above code into a stored procedure it would not work because exist / not exists can only be used in subqueries.
I would do the following:
Create a stored procedure
Declare an integer variable
Using select into fetch the count of rows where name='Rutvij' AND lang='python' into your variable.
Use the if statement to do the insertion based on the number of records.

MySQL syntax error regarding WHERE NOT EXISTS

I have a Chef recipe for creating Unix user IDs and deploying them across multiple nodes, to guarantee uniqueness and prevent devs from having to track them themselves. They merely name the application and it is granted a unique ID if an ID for that application doesn't already exist. If one does, it is simply returned to the script and user accounts are created on the webservers with the appropriate value.
I have a mysql database with a single table, called application_id_table which has two columns, id and application_name. id is autoincrementing and application name cannot be null (and must be unique).
Removing the Ruby from my script and making a couple of substitutions, my sql looks like this:
INSERT INTO application_id_table(application_name) VALUES('andy_test')
WHERE NOT EXISTS (select 1 from application_id_table WHERE
application_name = 'andy_test');
when run, I receive the syntax parsing 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 'WHERE NOT EXISTS (select 1 from
application_id_table WHERE application_name = 'a'
I recall seeing that the values statement does not allow a where clause but I don't wish to use a select statement to populate the values as I'm populating them from variables supplied from within Ruby/Chef. Anyone have an idea how to accomplish this?
You want to use insert . . . select:
INSERT INTO application_id_table(application_name)
SELECT aname
FROM (SELECT 'andy_test' as aname) t
WHERE NOT EXISTS (select 1 from application_id_table ait WHERE ait.application_name = t.aname);
You should be able to plug your variable directly into the select statement, the same you would would with the VALUES statement.
Try this:
INSERT INTO application_id_table(application_name)
select 'andy_test'
WHERE NOT EXISTS (select 1 from application_id_table WHERE application_name = 'andy_test');

Using a MySQL event to "deactivate" accounts

I setup a database and one of the columns in a table is "status" (active,inactive,locked). I want the event to compare NOW() to the value of column "pdate" (which is a timestamp), and if greater than 30 days, update the value of "status" to "inactive".
I wrote the following, but I get a few syntax errors :s
CREATE EVENT `expireAccounts_oldPwd` ON SCHEDULE EVERY DAY
DO
USE databasename;
SELECT pdate FROM tablename WHERE status = "active";
FOR EACH ( ROW IN tablename WHERE( ( SELECT DATEDIFF(NOW(),pdate) AS age ) > 30 ) ) {
UPDATE tablename SET status = "inactive";
};
ERROR 1064 (42000): You have an error in your SQL syntax near 'USE databasename' at line 2
ERROR 1064 (42000): You have an error in your SQL syntax near 'FOR EACH ROW IN "tablename" WHERE( ( SELECT DATEDIFF(NOW(),"pdate") AS age )' at line 4
ERROR 1064 (42000): You have an error in your SQL syntax near '}' at line 6
of course 'databasename' was replaced the actual database's name and 'tablename' the actual table's name.
Now at least it's doing something:
+---------------------+
| pdate |
+---------------------+
| 2011-08-11 18:01:02 |
| 2011-08-11 18:03:31 |
+---------------------+
2 rows in set (0.00 sec)
If I don't included USE databasename; on line 2, I get no output.
FINAL CODE:
USE databasename;
DELIMITER %
CREATE EVENT eventname
ON SCHEDULE EVERY 1 DAY
DO UPDATE tablename SET status = "inactive" WHERE status = "inactive" AND DATEDIFF(NOW(), columnname) > 30);
%
I didn't realize events were database-specific (so you have to be in the database when you create it).
Thanks all!
Two event specific things apart from the obvious syntax problems:
Where does your event end? You need to enclose it in a BEGIN/END block (the same way as a stored procedure).
You need to switch the DELIMITER when defining an event (the same way as when you define a stored procedure).
There are two relevant examples at the end of http://dev.mysql.com/doc/refman/5.1/en/create-event.html.
Update:
Also check http://dev.mysql.com/doc/refman/5.1/en/stored-routines-syntax.html for SQL statements which are permitted in stored procedures and events. USE is not permitted.
One more update:
It would be advisable to first try to get your SQL working without putting it in a event. After you have fixed your statements so that they work, try creating a stored procedure out of it. When you get the stored procedure working, you can replace it with an event. This way it will be much easier to sort out the rest of the problems (such as where is the output of the first SELECT supposed to go? etc.).
Is there a reason you can't use a query like this one?
UPDATE tablename SET status = "inactive" WHERE status = "active" AND DATEDIFF(NOW(),pdate) > 30;
I've never even seen FOR EACH in MySQL...
First step's going to be using valid SQL.
SELECT "pdate" FROM databasename.tablename WHERE "status" = "active";
will always cause an error, because column names shouldn't be in quotes. If you enclose a table name in anything, it'd be backticks (`).
SELECT pdate FROM databasename.tablename WHERE status="active";
You have the same problem in the rest of your query.