When are MYSQL delimiters useful? - mysql

I am writing SQL to create a trigger for a table in my database. This code should be in a script we can run whenever we spawn a new database.
I have been reading the SQL doc to understand how to do this and eventually came up with a query of this type:
DELIMITER $$
CREATE TRIGGER calendar_event_after_insert AFTER INSERT
ON calendar_event
FOR EACH ROW
BEGIN
IF #log_calendar_event_id = 'YES'
THEN
...
END IF;
IF #log_calendar_event_name = 'YES'
THEN
...
END IF;
...
END
$$
DELIMITER ;
Now I am getting an error on my use of DELIMITER, and I admit I don't understand much of how that works. My basic understanding is that since there are multiple queries inside this big one that all end with a ; I need to tell sql when this query ends using another delimiter.
After reading a bit about delimiters this seems like the right syntax to me, and on top of that i have been running this query in sequel pro and it works at times and at times it does not (weird, I know).
So eventually I decided to remove the delimiters part and everything works smoothly. I am a bit worried this will have side effects tho.
So my question is: when are delimiters used? are they useful in my case? if so, what am I doing wrong here?
EDIT as requested in comments
This is the error I get when running the query:
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 'DELIMITER $$ CREATE TRIGGER calendar_event_after_insert AFTER
INSERT ON calenda' at line 1
FYI we have an old version of MYSQL installed on our dev machines -- MYSQL 5.1.73

DELIMITER is not part of the SQL language. It's a command of the official command-line tool:
If you use the mysql client program to define a stored program containing semicolon characters, a problem arises. By default, mysql itself recognizes the semicolon as a statement delimiter, so you must redefine the delimiter temporarily to cause mysql to pass the entire stored program definition to the server.
To redefine the mysql delimiter, use the delimiter command.
There're some third-party programs that also implement a delimiter command in order to be able to run complex MySQL scripts (e.g. HeidiSQL).
If you are running your script in a context that doesn't allow multiple statements (e.g. a typical PHP application) the command will neither exist nor be needed at all.

Related

IF/THEN statement producing syntax error in MySQL

I have a very basic IF statement written that will be a part of a trigger, but when I try to run the query I receive a syntax error:
IF (STR_TO_DATE('09/29/2017','%m/%d/%Y') > CURDATE() - INTERVAL 1 DAY) THEN
SELECT * FROM apikeys;
END IF;
This is the error I'm getting:
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 'END IF' at line 1
I'm using MySQL 5.6
UPDATE: I now understand that IF/THEN statements can only be stored in procedures like triggers and are unable to be executed in this manner normally. Is there any way of knowing a trigger will be successful before implementing the new code into a live system? This trigger specifically controls a text messaging queue that fires SMS through Twilio, so I really cannot afford to guess and check.
Procedural logic in MySQL is only usable in stored procedures, triggers, events, etc... You cannot conditionally execute a query outside of those places (or client code obviously); the closest you can get is to make the IF's condition a part of the query's WHERE conditions. You still get a result set, but it will be empty.
SELECT *
FROM apikeys
WHERE STR_TO_DATE('09/29/2017','%m/%d/%Y') > CURDATE() - INTERVAL 1 DAY
;
Edit: In situations where you absolutely positively need procedure logic; you can create a stored procedure with it, execute that, and then drop the procedure.
Edit2:
Is there any way of knowing a trigger will be successful before
implementing the new code into a live system?
Seems, obvious but the best way to know is to run it on a test system. If that is not an option for some reason, as long as you are not using the NEW or OLD features of triggers you should be able to copy it into the body of a test procedure and run that instead...but you also won't get warned if you have queries that attempt to modify the table the trigger is on.

Having a hard time creating a procedure in SQL

I need to create a procedure for class, but I think the sql version in the book is VERY old. For example, I don't think I can't use "Create or replace" like the book says, but "create", "drop", "create", but that is beyond the scope.
My issue is that I am having trouble setting the %TYPE. I use WAMP, I created the procedure in Notepad++, and pasted it to the console. I then opened up phpmyadmin, pasted it into the query window, and was rewarded with more verbose error message. Book: "A guide to SQL" by Phil Pratt and Mary Last, Ninth Edition https://www.amazon.com/Guide-SQL-Philip-J-Pratt/dp/111152727X . Book has TAL Distributers, SOLARIS comdominium group, and COLONIAL adventure tours databases it that helps anyone. The instructor provided the sql file to create the databases as a time saver. This is for the last chapter, ch.8 Creation code:
delimiter ;;
use tal;;
CREATE PROCEDURE CHANGE_ITEM_PRICE(I_ITEM_NUM IN item.item_num%TYPE, I_NEW_PRICE IN item.price%TYPE) AS
BEGIN
UPDATE item SET price = I_NEW_PRICE
WHERE item_num = I_ITEM_NUM;
END;;
delimiter ;
2 Errors:
Unrecognized data type. (near "IN" at position 56)
and another for position 91.
Any thoughts? I'm not looking to be spoon fed here, I just need a little guidance please.
Edit: Thank you #Bill Karwin. The corrected working syntax follows:
delimiter ;;
use tal;;
CREATE PROCEDURE CHANGE_ITEM_PRICE(IN I_ITEM_NUM char(4), IN I_NEW_PRICE decimal(6,2))
BEGIN
UPDATE item SET price = I_NEW_PRICE
WHERE item_num = I_ITEM_NUM;
END;;
delimiter ;
I_ITEM_NUM IN item.item_num%TYPE
This is not a valid procedure argument declaration for MySQL. You have to name the type with something like INT or DATE or VARCHAR(length) or another known type. MySQL has no syntax like you show to dynamically query the type of a named column.
Out of curiosity, where did you get that syntax? Is it part of some other brand of SQL database? I've never seen it before.
Aha, I found it:
https://www.postgresql.org/docs/current/static/sql-createfunction.html says:
The type of a column is referenced by writing table_name.column_name%TYPE. Using this feature can sometimes help make a function independent of changes to the definition of a table.
That's in the PostgreSQL documentation. PostgreSQL and MySQL are not the same software, and there are many examples of syntax and features that each has that the other does not.
This syntax is also supported by Oracle: %TYPE attribute. Actually, I assume Oracle did it before PostgreSQL.
Re your comment:
var IN char(4)" does not work either
You said you were interested in a little guidance. The simplest guidance is that when you're learning a new syntax, it helps to read the reference documentation. :-)
I've used MySQL a lot over the past 16 years. I am a regular speaker at MySQL Conferences and users' groups. I'm a published author. And even I open the documentation pages as a first step when I'm doing something that isn't immediately familiar to me.
Here: http://dev.mysql.com/doc/refman/5.7/en/create-procedure.html
Notice when declaring procedure parameters, it's IN param_name type, not param_name IN type.
now the error is "syntax near ' AS....'
Again, refer to the documentation. There's no AS in the stored procedure syntax for MySQL. That's also Oracle syntax.
You may need to get a different book if you're going to use MySQL instead of Oracle. For example, I suggest MySQL Stored Procedure Programming: Building High-Performance Web Applications in MySQL.
But honestly, I am not a fan of using stored procedures in MySQL at all. MySQL's implementation of stored procedures is far inferior to that of Oracle. MySQL procedures have no packages or libraries, there's no procedure debugger, they're not compiled, and they don't scale well.
Most developers who use MySQL put more logic in their application code instead of stored procedures. This allows them to scale out their performance to numerous application servers, instead of piling up the load on the database server.
I don't believe MySQL has an equivalent for Oracle's %TYPE operator. You will need to specify the data types directly, for example:
CREATE PROCEDURE CHANGE_ITEM_PRICE(I_ITEM_NUM INT, I_NEW_PRICE DECIMAL) ...
I checked through the function and operator list in the most recent MySQL manual to see if they have recently added this function, but did not find it there.

Some mySQL statements only work after appending \g, other statements don't mind?

I'm trying to embrace mySQL commands in the raw form without using phpMyAdmin and I ran into this little issue so far...
I'm just wondering, I can connect to my db using wamp server and some commands won't work without typing \g after. For instance, I can connect, type my password and then immediately if I just try to create a database via:
CREATE DATABASE testing
It pushes me into a newline that looks like so:
mysql> CREATE DATABASE testing
->
1. How do I get back to a regular line to type after this happens? I keep having to close the command prompt and re initiate which is a hassle. 2. Why does it do this? Then when I type the following the command works just fine.
CREATE DATABASE testing \g
OK, now if that were the case I'd just understand and always type \g after everything because I know some things just "ARE" in programming. But then, I can type this line without the \g and it changes databases just fine.
USE firstdb
I haven't tested further on which commands do and don't work with/without the GO command but I thought I'd ask before I confuse myself a million times.
Much appreciated SO community! Thx in advance.
(Also, since I'm new to SO can someone please leave a comment on how to create those code snippets, but in the inline-block format so I don't have to always have to break my code references out onto new lines? Thanks!)
The semicolon ; is the standard statement delimiter in SQL. In the case of MySQL, the server doesn't need to see it, so the command line client doesn't actually send it... but it waits for it, and nothing is sent to the server until a delimiter followed by a newline is encountered.
Exceptions are things that don't get sent to the server, or don't get sent as SQL. (There's another way, other than the USE statement, to change the current database, using a specially-crafted packet, and afaik the MySQL cli still uses that method, which is, I assume, why USE is a strange exception.)
You can change the delimiter to something else. Commonly, you'll see something like this
mysql> DELIMITER $$
This allows you to send SQL to the server that contains a ; en bloc, without the client thinking you were done when it saw what looks like a delimiter. This is used for declaring procedures, functions, triggers, and events. At the end of the statement, or group of statements, each terminated with $$, you set it back.
mysql> DELIMITER ;
Note there's a space before the ;.

PHPMyAdmin Import/Export Same Server Fails

I've been trying to work out the best way of copying structure & data from one database to another but the PHPMyAdmin export seems to churn out pretty poor scripts. The most obvious example is if I export a database (structure & data) then try and re-import on the same server (using the drop tables function to prevent clashes), I get a syntax error!? I would have thought PHPMyAdmin would be able to parse its own exports.
The error I get is:
Error SQL query:
$$
DROP PROCEDURE IF EXISTS `CMS_identifyFileType`$$
MySQL said: Documentation
#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 '$
DROP PROCEDURE IF EXISTS `CMS_identifyFileType`' at line 1
It looks odd to me that the script has weird apostrophes?
Does anyone have any tips on what I might be doing wrong? I have to manually add the 'use myDatabasename;' to the script to get it to work, not sure if I'm missing some other stuff.
My MySQL version is 5.1.73-community running on a Windows Server 2008 R2 server.
Thanks
Bob
I suspect you've amended the output file.
For table and index definitions, mysqladmin uses the default delimiter ';' but for procedures and functions it uses '$$'. The DBMS needs to know that the delimiter has changed - hence in the export file there should be a line like this between a table definition and a procedure definition:
DELIMITER $$
BTW the weird apostrophes around (for example) CMS_identifyFileType are to be expected in MySQL - see Using backticks around field names for a discussion.
I have no idea if this is the correct way to do it but in the end this worked for me:
I did the export using the default options.
I opened the file in Dreamweaver (it seems to handle the length file better than Notepad++)
Added the 'USE mydatabaseName;' to the beginning
I removed all commented lines
I removed the 'delimiter $$' lines
I replaced any $$ at the end of lines with ;
I replaced any orphan $$ (on their own on a line) with a space
I replaced all backticks with a space
Uploaded the SQL file to PHPMyAdmin and it finally worked (I tried not doing each of the steps above and if I missed anyone of them, I got one of a number of different flavor syntax errors). Seems to me like PHPMyAdmin's Import/Export system really needs some work.
Caveat: My table, column and procedure names do not include any special characters, spaces or reserved words so I was able to get away without the backticks. If you have anything unusual you will need them.

Getting message Review the SQL script to be applied on the database

I am getting the following message while creating a stored procedure in MySQL Workbench:
"Review the SQL script to be applied on the database"
I have several tables inside the database but the stored procedure I am writing will be
used only for one table. Since, the SQL script of stored procedure is gonna apply on the whole database, I am wondering if it's gonna affect other tables as well? I don't want other tables to get disturbed because of this script.
Please provide your inputs as I am doing this for the first time.
Question #2:
Why do I see "DELIMITER $$" as the first statement while creating a routine before the following statement?
CREATE PROCEDURE `mydatabase`.`myfirstroutine` ()
BEGIN
Thanks
1) MySQL Workbench offers the option to review the generated SQL script before it is sent to the server. This way you can check it for possible problems.
2) The DELIMITER command is usually necessary to switch the current delimiter that ends a single statement (which is by default a semicolon) to something else because the stored procedure code itself needs the semicolon to separate individual commands. However the sp code must be sent as a whole to the server.
A few more details: the DELIMITER keywword is a client keyword only, that means the server doesn't know it and doesn't need it. It's an invention for clients to properly separate sql commands before sending them to the server (you cannot send a list of commands to a server, only individual statements).
In MySQL Workbench however, especially in the object editors where you edit e.g. the sp text, adding the DELIMITER command is essentially nonsense, because there's only this sp code, hence nothing to separate. This might disappear in future version but for now just ignore it.