MySQL Syntax : "the right syntax to use near" - right in the beginning - mysql

I am a MySQL-noob and today I tried to setup a MySQL call which is more than 5 lines long. I keep getting syntax errors which I try to fix for hours, but I don't have a clue what the problem is. Here is the code:
USE myDatabase;
DELIMITER //
CREATE PROCEDURE MYPROC()
BEGIN
SET #ID = 1;
SET #maxID = 3;
CREATE TEMPORARY TABLE resultTable(v DOUBLE, ttc DOUBLE);
WHILE (#ID < #maxID) DO
INSERT partTable1.v, partTable2.ttc
INTO
resultTable
FROM
(SELECT * FROM
(((SELECT time_sec, v FROM speedTable WHERE (trip_id = #ID)) as partTable1)
INNER JOIN
((SELECT time_sec, ttc FROM sightsTable WHERE (trip_id = #ID)) as partTable2) ON
(0.04 > abs(partTable1.time_sec - partTable2.time_sec)))
);
SET #ID := #ID + 1;
END WHILE;
END //
DELIMITER;
CALL MYPROC();
SELECT * FROM resultTable LIMIT 100;
Is there anything obvious that needs to be corrected?
Update1: Added semicolon to the "CREATE.."-statement, now first three statements are OK.
Update2: Added 3 more semicolons!
Update3: Followed the suggestion to make it a function + separate function call. Error message changed!
Update4: I fixed the issues mentioned in the two answers. Still something wrong there. See updated code above and error message below.
Updated error message:
ERROR 1064 (42000) at line 4: You have an error in your SQL syntax; check the ma
nual that corresponds to your MySQL server version for the right syntax to use n
ear ' partTable2.ttc
INTO
resultTable
FROM
(SELECT * FROM
(((SELE' at line 11
Kind Regards,
Theo

Flow control statements, of which WHILE is one, can only be used within a stored procedure, but you are attempting to use it as a plain query via the console.
If you absolutely must take this path (using mysql instead of an application language), create a store procedure with the code you want, then call it.
Creating the procedure would look like this:
DELIMITER //
CREATE PROCEDURE MYPROC()
BEGIN
WHILE (#ID < #maxID) DO
SET #partTable1 = (SELECT time_sec, v FROM speedTable WHERE (trip_id = #ID));
SET #partTable2 = (SELECT time_sec, ttc FROM sightsTable WHERE (trip_id = #ID));
INSERT v, ttc INTO resultTable FROM
(#partTable1 INNER JOIN #partTable2 ON
(0.04 > abs(partTable1.time_sec - partTable2.time_sec)));
SET #ID := #ID + 1;
END WHILE;
END//
DELIMITER ;
Then to call it:
CALL MYPROC();
See this SQLFiddle of a simplified version of this working.
Note that you do have one syntax error:
#ID = #ID + 1; -- incorrect syntax
SET #ID := #ID + 1; -- correct

Still some syntactic problems and functionality problems...
You can't use WHILE in SQL scripts. You can use WHILE only in the body of a stored routine. See http://dev.mysql.com/doc/refman/5.6/en/flow-control-statements.html
You can't use SET to assign multiple columns to a scalar. MySQL doesn't support relation-valued variables, only scalar variables. See http://dev.mysql.com/doc/refman/5.6/en/set-statement.html
You can INSERT from the results of a query with a join, but the query must be introduced with SELECT. See http://dev.mysql.com/doc/refman/5.6/en/insert-select.html
You can't use session variables as the names of tables. You would have to use a prepared statement. See http://dev.mysql.com/doc/refman/5.6/en/prepare.html But that opens a whole different can of worms, and doing it wrong can be a security vulnerability (see http://xkcd.com/327). I wouldn't recommend you start using prepared statements as a self-described MySQL-noob.
This problem is probably simpler than you're making it. You don't need a temporary table, and you don't need to read the results one row at a time.
Here's an example that I think does what you intend:
USE myDatabase
SET #ID = 1;
SET #maxID = 3;
SELECT sp.v, si.ttc
FROM speedTable AS sp
INNER JOIN sightsTable AS si
ON (sp.trip_id = si.trip_id AND 0.04 > ABS(sp.time_sec - si.time_sec))
WHERE sp.trip_id BETWEEN #ID AND #maxID;

Related

"Delimiter" is not valid at this position, expecting CREATE

I was getting an error of "Delimiter" is not valid at this position, expecting CREATE" as I was writing a stored procedure and couldn't figure out the cause. I think it might be an issue with MySQL workbench possibly, because the following code gives the same error but was copied straight off of this website.
DELIMITER $$
CREATE PROCEDURE GetTotalOrder()
BEGIN
DECLARE totalOrder INT DEFAULT 0;
SELECT COUNT(*)
INTO totalOrder
FROM orders;
SELECT totalOrder;
END$$
DELIMITER ;
Edit: My real stored procedure is:
DELIMITER //
CREATE PROCEDURE GetSimilar(inputdate char(10))
BEGIN
Declare id(tinyint) DEFAULT 0;
Set id := (select t.IdTimelineinfo
From timelineinfo t
WHERE t.Date = inputdate);
SELECT t.Date From timelineinfo t where t.date = inputdate;
SELECT o.Name, o.Race, o.Sex, o.IdOfficer
FROM timelineinfo
JOIN timelineinfo_officer ON timelineinfo.IdTimelineinfo = timelineinfo_officer.IdTimelineinfo
JOIN officers o ON timelineinfo_officer.IdOfficer = o.IdOfficer
WHERE timelineinfo.IdTimelineinfo = id
UNION
SELECT s.IdSubject, s.Name, s.Race, s.Sex
FROM timelineinfo
JOIN timelineinfo_subject ON timelineinfo.IdTimelineinfo = timelineinfo_subject.IdTimelineinfo
JOIN subjects s ON timelineinfo_subject.IdSubject = s.IdSubject
WHERE timelineinfo.IdTimelineinfo = id;
UNION
Select *
From media m
Where (m.IdTimelineinfo = id);
END //
DELIMITER ;
Watch out where you edit the procedure SQL code. There's a dedicated routine object editor (just like there are for tables, triggers, views etc.), which only accept SQL code for their associated object type. Hence they don't need a delimiter and even signal an error if you use one.
On the other hand you can always directly edit SQL code in the SQL IDE code editors, where no such special handling is implemented. In this case you need the delimiter.

Mysql error: Not allowed to return a result set from a function

I am trying to have a conditional change in a parameter for update statement.
I am getting the following error when I try the following function
/home/y/bin/mysql -u root < testpri.sql > out
ERROR 1415 (0A000) at line 4: Not allowed to return a result set from a function
Contents of testpri.sql are as follows:
use `zestdb`;
DROP FUNCTION IF EXISTS UPDATEPASSWD;
DELIMITER //
CREATE FUNCTION UPDATEPASSWD(n INT) RETURNS varchar(255) DETERMINISTIC
BEGIN
DECLARE mypasswd varchar(255);
IF (n = 1) THEN
SET mypasswd = '12ccc1e5c3c9203af7752f937fca4ea6263f07a5';
SELECT 'n is 1' AS ' ';
ELSE
SET mypasswd = '1a7bc371cc108075cf8115918547c3019bf97e5d';
SELECT 'n is 0' AS ' ';
END IF;>
SELECT CONCAT('mypasswd is ', mypasswd) AS ' ';
RETURN mypasswd;
END //
DELIMITER ;
CALL UPDATEPASSWD(0);
What am I missing?
I think it's actually your debugging SELECT calls.
From the docs:
Statements that return a result set can be used within a stored procedure but not within a stored function. This prohibition includes SELECT statements that do not have an INTO var_list clause...
I arrived in search of answers to the same question, and found another way to work around the issue, so that I can use the SELECT statement that is the heart and soul of the MySQL function that elicited the warning.
Consider the following snippet.
SET intNMatches = ( SELECT COUNT(*) ...
SET coerces the SELECT statement to return its one and only column, a row count, into intNMatches, a local variable cast to BIGINT. Since it contains trade secrets, I can't show the rest of the query. Suffice it to say that the query installs without causing the MySQL engine to issue a warning.

Weird issue with a stored procedure in MySQL

I need to add a new stored procedure on our company's MySQL server. Since it's just slightly different, I used an already existing one, added the additional field and changed the name of the procedure. The weird thing now is that when I want to execute the statement, it returns:
Error Code: 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 3
reffering to the 0 in this line: SET #update_id := 0; What makes it weird is, that I queried that stored procedure by using SHOW CREATE PROCEDURE . It's saved in our database and is working fine. I just can't use it as a new stored procedure (no matter if I try to apply it to the new test database or if I use it on the existing database by giving it a new name).
I searched the internet for a solution. Unfortunately to no avail. I even set up a new database with a new table and some demo values where I tried to execute the original, unaltered stored procedure. It returns the exact same error.
Here's the currently used and working stored procedure I'm talking about:
CREATE DEFINER=`root`#`localhost` PROCEDURE `customer_getcard`(IN Iinstance INT, IN Itimebuy DOUBLE, IN Iprice DECIMAL(10,2), IN Itariff INT, IN Icomment VARCHAR(128))
BEGIN
SET #update_id := 0;
UPDATE customer_shop SET state = 1, id = (SELECT #update_id := id), instance=Iinstance, timebuy=Itimebuy, price=Iprice, comment=Icomment WHERE tariff=Itariff AND state = 0 LIMIT 1;
SELECT * FROM customer_shop WHERE id = #update_id;
END
I hope you guys can help me as I am completely out of ideas what's wrong. :/
Regards, Mark
You need to define an alternative command delimiter, as MySQL currently thinks your CREATE PROCEDURE command ends at the first ; it encounters (on line 3, after the 0), which would be a syntax error as it's after a BEGIN but before the corresponding END:
DELIMITER ;; -- or anything else you like
CREATE PROCEDURE
...
END;; -- use the new delimiter you chose above here
DELIMITER ; -- reset to normal
MySQL stored procedures do not use ":=" for value assignment, just use "=".
Also don't think "id = (SELECT #update_id := id)" is acceptable. Here's an alternative solution (untested):
CREATE DEFINER=`root`#`localhost` PROCEDURE `customer_getcard`(IN Iinstance INT, IN Itimebuy DOUBLE, IN Iprice DECIMAL(10,2), IN Itariff INT, IN Icomment VARCHAR(128))
BEGIN
select id into #update_id from customer_shop WHERE tariff=Itariff AND state = 0 LIMIT 1;
UPDATE customer_shop SET state = 1, instance=Iinstance, timebuy=Itimebuy, price=Iprice, comment=Icomment where id = #update_id;
SELECT * FROM customer_shop WHERE id = #update_id;
END
You may also want to put error handlers in case there's no matching row to be edited.

mySQL If statement

I am trying to make this If Statement work, but I can't seem to make it do what I want. If I do a select #result, It'll give me the value 0, then why doesn't the IF statement work?
SET #message = '((sometihng here))';
select LEFT(#message, 1) into #firstChar;
select STRCMP(#firstChar,'(') into #result;
IF (#result = 0) THEN
SET #message = 'true';
//more selects and cals here;
END IF;
select #message;
I should get true, but I don't it shows me an error:
SQL query: IF( #result =0 ) THEN SET #message = 'true';
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 'IF (#result = 0) THEN SET #message = 'true'' at line 1
try use function http://dev.mysql.com/doc/refman/5.0/en/control-flow-functions.html#function_if
SELECT IF(#result = 0, 'true', '((something here))') AS message
As Max Mara pointed out, that's a good work aroud. The reason the IF wasn't working is not because the syntax is incorrect, but because flow control functions like IF ... THEN are only valid inside of stored procedures or functions, All this thanks to #TehShrike
The IF .. THEN .. ELSE syntax in MySQL is only available for procedural code (stored precudures, functions, triggers..), but not for SELECT statements.
IF ELSE USED IN STORED PROCEDURE EXAMPLE BELOW
DELIMITER //
CREATE PROCEDURE NAME(IN Number INT)
BEGIN
IF roll= 1
THEN SELECT * FROM table1 WHERE id = roll;
ELSE
SELECT * FROM table2 WHERE id = 2;
END IF;
END //
DELIMITER ;

Using variable in a LIMIT clause in MySQL

I am writing a stored procedure where I have an input parameter called my_size that is an INTEGER. I want to be able to use it in a LIMIT clause in a SELECT statement. Apparently this is not supported, is there a way to work around this?
# I want something like:
SELECT * FROM some_table LIMIT my_size;
# Instead of hardcoding a permanent limit:
SELECT * FROM some_table LIMIT 100;
For those, who cannot use MySQL 5.5.6+ and don't want to write a stored procedure, there is another variant. We can add where clause on a subselect with ROWNUM.
SET #limit = 10;
SELECT * FROM (
SELECT instances.*,
#rownum := #rownum + 1 AS rank
FROM instances,
(SELECT #rownum := 0) r
) d WHERE rank < #limit;
STORED PROCEDURE
DELIMITER $
CREATE PROCEDURE get_users(page_from INT, page_size INT)
BEGIN
SET #_page_from = page_from;
SET #_page_size = page_size;
PREPARE stmt FROM "select u.user_id, u.firstname, u.lastname from users u limit ?, ?;";
EXECUTE stmt USING #_page_from, #_page_size;
DEALLOCATE PREPARE stmt;
END$
DELIMITER ;
USAGE
In the following example it retrieves 10 records each time by providing start as 1 and 11. 1 and 11 could be your page number received as GET/POST parameter from pagination.
call get_users(1, 10);
call get_users(11, 10);
A search turned up this article. I've pasted the relevant text below.
Here's a forum post showing an example of prepared statements letting
you assign a variable value to the limit clause:
http://forums.mysql.com/read.php?98,126379,133966#msg-133966
However, I think this bug should get some attention because I can't
imagine that prepared statements within a procedure will allow for any
procedure-compile-time optimizations. I have a feeling that prepared
statements are compiled and executed at the runtime of the procedure,
which probaby has a negative impact on efficiency. If the limit
clause could accept normal procedure variables (say, a procedure
argument), then the database could still perform compile-time
optimizations on the rest of the query, within the procedure. This
would likely yield faster execution of the procedure. I'm no expert
though.
I know this answer has come late, but try SQL_SELECT_LIMIT.
Example:
Declare rowCount int;
Set rowCount = 100;
Set SQL_SELECT_LIMIT = rowCount;
Select blah blah
Set SQL_SELECT_LIMIT = Default;
This feature has been added to MySQL 5.5.6.
Check this link out.
I've upgraded to MySQL 5.5 just for this feature and works great.
5.5 also has a lot of performance upgrades in place and I totally recommend it.
Another way, the same as wrote "Pradeep Sanjaya", but using CONCAT:
CREATE PROCEDURE `some_func`(startIndex INT, countNum INT)
READS SQL DATA
COMMENT 'example'
BEGIN
SET #asd = CONCAT('SELECT `id` FROM `table` LIMIT ',startIndex,',',countNum);
PREPARE zxc FROM #asd;
EXECUTE zxc;
END;
As of MySQL version 5.5.6, you can specify LIMIT and OFFSET with variables / parameters.
For reference, see the 5.5 Manual, the 5.6 Manual and #Quassnoi's answer
I've faced the same problem using MySql 5.0 and wrote a procedure with the help of #ENargit's answer:
CREATE PROCEDURE SOME_PROCEDURE_NAME(IN _length INT, IN _start INT)
BEGIN
SET _start = (SELECT COALESCE(_start, 0));
SET _length = (SELECT COALESCE(_length, 999999)); -- USING ~0 GIVES OUT OF RANGE ERROR
SET #row_num_personalized_variable = 0;
SELECT
*,
#row_num_personalized_variable AS records_total
FROM(
SELECT
*,
(#row_num_personalized_variable := #row_num_personalized_variable + 1) AS row_num
FROM some_table
) tb
WHERE row_num > _start AND row_num <= (_start + _length);
END;
Also included the total rows obtained by the query with records_total.
you must DECLARE a variable and after that set it. then the LIMIt will work and put it in a StoredProcedure not sure if it works in normal query
like this:
DECLARE rowsNr INT DEFAULT 0;
SET rowsNr = 15;
SELECT * FROM Table WHERE ... LIMIT rowsNr;