In MySQL, can I use procedural SQL outside a stored procedure? - mysql

In Sybase ASE and Microsoft SQL Server, you can use procedural SQL (control flow statements like IF/ELSE and WHILE, declaring and setting lexical variables, and so on) in one-off SQL statement batches, like so:
-- from https://msdn.microsoft.com/en-us/library/ms182587.aspx
DECLARE #Number INTEGER;
SET #Number = 50;
IF #Number > 100
SELECT 'The number is large.' AS large;
ELSE
BEGIN
IF #Number < 10
SELECT 'The number is small.' AS small;
ELSE
SELECT 'The number is medium.' AS medium;
END;
You can send this code directly to SQL Server, without preparing it or putting it in a stored procedure, and SQL Server will send back a table with a single tuple and column, with the value "The number is medium."
From what I can tell, in MySQL, procedural SQL code is restricted to appearing only within stored procedure definitions (CREATE PROCEDURE or CREATE FUNCTION statements):
mysql> delimiter //
mysql> if 32 = 32 then
-> select 'yes';
-> else
-> select 'no';
-> end if;
-> //
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
'if 32 = 32 then
select 'yes';
else
select 'no';
end if'
at line 1
Is this impression correct?

Yes, you are correct. Lots of constructs are only valid inside stored functions, like if. It even says so in the manual.
"The IF statement for stored programs implements a basic conditional construct."
However, the same result can be achieved using another approach, with the function if
select if(32 = 32, 'yes', 'no');
sqlfiddle

Related

stored procedure is issuing syntax error

I am trying to create a mysql stored procedure with phpmyadmin:
CREATE PROCEDURE AddTableColumn()
BEGIN
IF (SELECT COUNT (table_name)
FROM information_schema.tables
WHERE table_name IN ('authors', 'publishers') = 2 )
print 'specified tables exist...';
ELSE
print 'specified tables unavailable...';
END IF;
END​
above code is a snippet that should search information schema
for the availability of authors and publishers tables,
then proceed to add new column in each table if present.
the print statement was for debug purpose. when i clicked the
GO command, here's the error message :
MySQL said:
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 'print 'avail...'; ELSE print 'unavail...'; END IF; END' at line
7.
what am i doing wrong ? i have even tried other code as a test,
all failing with the same error. code as simple as:
BEGIN
IF (6 > 4)
print 'greater';
ELSE
print 'lesser';
END IF;
END ​
all failed. any help will be appreciated.
'print' is not recognized in MySQL.
If you want to read back the output, just use a select in the SP.
Change part of your SP as below:
DECLARE found_status VARCHAR(255) DEFAULT NULL;
IF ....
SELECT 'specified tables exist...' INTO found_status;
ELSE
SELECT 'specified tables unavailable...' INTO found_status;
END IF;
SELECT found_status;

Lua & SQL Syntax Error

I'm trying both of these ways to run a SQL query with Lua using the GMod mysqloo library.
Each query is complaining about the line with the EXISTS() having an SQL syntax error.
local SQL6 = [[INSERT INTO accounts(UniqueID,Money)
VALUES(]]..UniqueID..[[,]]..StartingCash..[[)
WHERE NOT EXISTS(SELECT 0 FROM accounts WHERE UniqueID=]]..UniqueID..[[)]]
local SQL7 = [[IF Not EXISTS (SELECT * FROM accounts WHERE UniqueID=']]..UniqueID..[[')
BEGIN
INSERT INTO accounts(UniqueID,Money)
VALUES(]]..UniqueID..[[,]]..StartingCash..[[)
END
ELSE
BEGIN
SELECT * FROM accounts WHERE UniqueID=]]..UniqueID..[[
END]]
I don't know SQL but it seems that:
you need quotes around UniqueID in line 3 and 11, as in line 4.
you probably need a space or newline before the last END.

using IF in MySQL (not the function)

I have what feels like a simple question, but can't seem to get it right. I'm just trying to execute a regular IF ... THEN ... logic, but can't seem to get it right:
set #var:=2;
if #var=1 THEN select 'hello';
I get:
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 'if #var=1 THEN select 'hello'' at line 1
What am I missing?
You can use CASE instead.
SET #var:=2;
SELECT CASE WHEN #var=1 THEN 'hello' ELSE 'no hello' END;
--prints 'no hello'
SET #var:=2;
SELECT CASE WHEN #var:=1 THEN 'hello' ELSE 'no hello' END;
--prints 'hello'
I hope the idea is clear with above examples.
Edit: to address OP's additional concerns, You can incorporate selects in case statements, but you should enclose in brackets. For eg.
SET #var:=2;
SELECT CASE WHEN #var:=1 THEN (select 'hello') ELSE (select 'no hello') END;
One thing to notice is that it should return back only one value (from one row and a column)
You can, but only inside of functions, procedures and triggers like so:
DELIMITER //
DROP PROCEDURE IF EXISTS anyname//
CREATE PROCEDURE anyname()
BEGIN
IF #var1 = 1 THEN
SELECT 'hello';
END IF;
END//
SET #var1 := 1;
CALL anyname()//

Creating a database function within Magento for a module

I have a working module in Magento that is modeled after some custom code we use outside of our install. This module currently add 5 tables to the database to store info and I have extended the Admin to CRUD the info. The ultimate goal here is to move the majority of this custom programming into Magento.
Currently our custom code sits outside Magento and hits a separate database. This database has those same 5 tables, a stored procedure, and 4 functions. What I would like to do now is move the stored procedures and the functions into Magento's database and change the custom code to call all of it's data from Magento's db. However, I can't seem to figure out how the "CREATE FUNCTION" call should be set up for Magento to execute it properly.
The SQL I am using is:
DROP FUNCTION IF EXISTS {$this->getTable('fn_Get_HardinessZone')};
CREATE FUNCTION {$this->getTable('fn_Get_HardinessZone')}(IN ZipCode varchar()) RETURNS integer AS
DECLARE Result integer;
BEGIN
SELECT MAX(Zone) into Result
FROM AMI_zones
WHERE (Hfzip <= LEFT(ZipCode, 5)) AND (Htzip >= LEFT(ZipCode, 5));
if Result is null or Result < 1 or (Result > 11 and Result <> 99) Then
/*if the left most character is alpha, then set the zone to 98 for Canada*/
if Left(zipCode, 1) >= 'A' and LEFT(zipcode,1) <= 'Z' THEN
set result = 98;
else
set Result = 99;
End if;
END if;
RETURN Result;
END;
But this always generates the following error:
SQLSTATE[42000]: Syntax error or access violation: 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 'IN ZipCode varchar()) RETURNS'
So what is the proper way to format a SQL call to be run in a module's install/update script to insert a function or stored procedure into Maganeto's database?
The problem is with your SQL statement:
You have an error in your SQL syntax; check the manual ...
for the right syntax to use near
'IN ZipCode varchar()) RETURNS'
I would recommend running the SQL through PhpMyAdmin or on the command line until you get it right, then run it through Magento. This man page describes the syntax of CREATE FUNCTION: http://dev.mysql.com/doc/refman/5.0/en/create-procedure.html. When testing stored procedures /functions in the mysql client (or PhpMyAdmin) be sure to change the delimiter so that the semicolons in your function body are interpreted correctly.
The below SQL worked for me. The things I changed from your original statement are:
IN is not allowed in function declarations (IN ZipCode varchar())
I was required to explicitly state length of the varchar
The DECLARE belongs inside the function
I am guessing that your function is DETERMINISTIC, meaning it will always produce the same results for the same input parameters. If this is not the case, remove DETERMINISTIC from the RETURNS line
Give this a shot:
DROP FUNCTION IF EXISTS {$this->getTable('fn_Get_HardinessZone')};
CREATE FUNCTION {$this->getTable('fn_Get_HardinessZone')} (ZipCode VARCHAR(15))
RETURNS INTEGER DETERMINISTIC
BEGIN
DECLARE result INTEGER;
SELECT MAX(Zone) INTO result
FROM AMI_zones
WHERE (Hfzip <= LEFT(ZipCode, 5)) AND (Htzip >= LEFT(ZipCode, 5));
IF result IS NULL OR result < 1 OR (result > 11 AND result <> 99) THEN
/* if the left most character is alpha, then set the zone to 98 for Canada */
IF LEFT(ZipCode, 1) >= 'A' AND LEFT(ZipCode, 1) <= 'Z' THEN
SET result = 98;
ELSE
SET result = 99;
END IF;
END IF;
RETURN result;
END;

Stored procedures written in MySQL 5.5.8 don't work in 5.1

I have some stored procedures and a trigger that work great in MySQL 5.5.8 but for some reason don't work in 5.1. The error descriptions aren't enough for me to figure out the problem. Here is the code and the errors.
CREATE PROCEDURE `cg_getMatchingContent`(
MatchTerm VARCHAR(255),
MaxResults INT)
BEGIN
SELECT * FROM (
SELECT t.*, INSTR(t.`Title`,MatchTerm) as Pos
FROM cg_content t ) c
WHERE Pos>0 ORDER BY Pos LIMIT 0, MaxResults;
END
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 'MaxResults' at line 8
DELIMITER ;;
CREATE TRIGGER `cg`.`cg_content_UrlDup_ConstTrig`
BEFORE INSERT ON `cg`.`cg_content`
FOR EACH ROW
Begin
DECLARE errorString VARCHAR(500);
DECLARE insert_error CONDITION FOR SQLSTATE '99001';
IF new.Url = '' THEN
SET errorString = CONCAT('Url cannot be blank
Title: ' , new.Title);
SIGNAL insert_error
SET MESSAGE_TEXT=errorString;
END if;
IF Exists(SELECT id FROM cg.cg_content WHERE Url=new.Url) THEN
SET errorString = CONCAT('Url is not unique
Title: ' , new.Title , '
Url: ' + new.Url);
SIGNAL insert_error
SET MESSAGE_TEXT=errorString;
End if;
End ;;
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 'insert_error
SET MESSAGE_TEXT=errorString;END if;IF ' at line 10
From the docs:
Within stored programs, LIMIT parameters can be specified using integer-valued routine parameters or local variables as of MySQL 5.5.6.
5.1 does not support variables in LIMIT and OFFSET.
The second one is easy to figure, hard to fix. SIGNAL and RESIGNAL commands were introduced in MySQL 5.5. You can't convert it easily to 5.1. One way to do it, would be to run a query that errors. For example a SELECT from a non-existent table.