I'm struggling with a simple stored procedure, that I've reduced to this:
CREATE PROCEDURE RemoveDuplicateModules()
BEGIN
SET #myvar=1;
End;
When I run this in the MySQL CLI I get: parameter #myvar has not been created. I'm struggling cause in windows it works fine!
mysql --version = 5.6.33
Works for me (debian, mysql 5.6.25):
mysql> delimiter //
mysql> CREATE PROCEDURE RemoveDuplicateModules()
-> BEGIN
-> SET #myvar=1;
-> End;
-> //
Query OK, 0 rows affected (0,66 sec)
mysql> call RemoveDuplicateModules();
Query OK, 0 rows affected (0,00 sec)
mysql> select #myvar ;
+--------+
| #myvar |
+--------+
| 1 |
+--------+
1 row in set (0,02 sec)
Seems that the problem here was not that the procedure I posted was failing, but since it was being executed in a larger context, a big file with a lot of code from a lot of people, a previous lack of a commit made my procedure to fail. Anyway, thanks for the help!
I have problem:
I created procedure :
CREATE PROCEDURE `tran_sp` ()
BEGIN
SELECT 'procedure runned!';
END
$
It's works !
mysql> CALL tran_sp()$
+-------------------+
| procedure runned! |
+-------------------+
| procedure runned! |
+-------------------+
1 row in set (0.00 sec)
Then i created trigger :
mysql> CREATE TRIGGER my_trigger1
-> AFTER INSERT ON users
-> FOR EACH ROW
-> BEGIN
-> CALL tran_sp();
-> END$
mysql> INSERT INTO users VALUES(166,156)$
ERROR 1415 (0A000): Not allowed to return a result set from a trigger
mysql>
Help me please.
The exception is I think clear enough.
You can perform additional operations inside a trigger (call a SP, perform insert / update / delete operations, ...) but all of those aren't allowed to return any result.
This means, a SP with a simple select-statement inside isn't allowed. If instead you would use this select statement within a loop for instance in order to perform updates or similar, this would be allowed, as you wouldn't return anything.
The reason is, that an insert/update/delete statement can't return anything, it can't return the result set of your stored procedure and therefor you shouldn't try to return one inside the trigger.
I want to show the result of rows affected after update, insert, or delete in mysql. I have put
DELETE FROM A WHERE ID='1';
SELECT ROW_COUNT();
With the ROW_COUNT the last statement, but the result show me is 0.
If you want to know number of rows affected by delete query in PHPMYADMIN then by running your query it will show you the result see below screenshot :
As #Flash Thunder said PHPmyadmin does not allow multiple queries sent at once
If you want to see the affected rows then you can also write a script using PHP which will exceute you sql query and returns the number of affected rows
Just to be clear.
phpMyAdmin is written in PHP, and PHP does not allow multiple queries sent at once... if you are sending two queries separately, second query is on new connection, so it has no access to previous query information. That's why SELECT ROW_COUNT(); returns 0.
But by default phpMyAdmin returns affected rows count in information after query. It probably uses mysql(i)_affected_rows() function.
FOUND_ROWS() returns number of tables in database when there was no previous query.
mysql> use hunting;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> select found_rows();
+--------------+
| found_rows() |
+--------------+
| 24 |
+--------------+
1 row in set (0.00 sec)
mysql> show tables;
(...)
24 rows in set (0.00 sec)
I've reduced my issue down to this simple SP. The column names are getting cached in the SELECT * at the end. I have no idea why or how to stop it. I tried adding SQL_NO_CACHE but that makes no difference.
DROP TABLE IF EXISTS foo;
CREATE TABLE foo(
col1 int,
col2 int);
INSERT INTO foo VALUES(1,2),(3,4),(5,6);
DROP PROCEDURE IF EXISTS mysp;
DELIMITER ;;
CREATE DEFINER=root#localhost PROCEDURE mysp(c INT)
BEGIN
DROP TABLE IF EXISTS mydata;
SET #mycol='col1';
IF c > 0 THEN SET #mycol:='col2';
END IF;
SET #s=CONCAT('CREATE TEMPORARY TABLE mydata AS SELECT ', #mycol, ' FROM foo');
PREPARE stmt FROM #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- The following select call fails on 2nd and subsequent executions of the SP
SELECT SQL_NO_CACHE * FROM mydata;
SELECT "Please see new temp table mydata" as Result;
END ;;
DELIMITER ;
Version
mysql> SELECT VERSION();
+------------+
| VERSION() |
+------------+
| 5.5.15-log |
+------------+
1 row in set (0.00 sec)
First run works fine as expected
mysql> CALL mysp(0);
+------+
| col1 |
+------+
| 1 |
| 3 |
| 5 |
+------+
3 rows in set (0.17 sec)
+----------------------------------+
| Result |
+----------------------------------+
| Please see new temp table mydata |
+----------------------------------+
1 row in set (0.17 sec)
Query OK, 0 rows affected (0.17 sec)
Now if I try and run it again using the other column
mysql> CALL mysp(1);
ERROR 1054 (42S22): Unknown column 'qlgqp1.mydata.col1' in 'field list'
mysql> SELECT #mycol;
+--------+
| #mycol |
+--------+
| col2 |
+--------+
1 row in set (0.00 sec)
If I recreate the storedprocedure again its works
mysql> CALL mysp(1);
+------+
| col2 |
+------+
| 2 |
| 4 |
| 6 |
+------+
3 rows in set (0.18 sec)
+----------------------------------+
| Result |
+----------------------------------+
| Please see new temp table mydata |
+----------------------------------+
1 row in set (0.18 sec)
Query OK, 0 rows affected (0.18 sec)
But if I try switching back to the first column - even if I try dropping the temp table first - it still doesn't work
mysql> CALL mysp(0);
ERROR 1054 (42S22): Unknown column 'qlgqp1.mydata.col2' in 'field list'
mysql> DROP TABLE mydata;
Query OK, 0 rows affected (0.03 sec)
mysql> CALL mysp(0);
ERROR 1054 (42S22): Unknown column 'qlgqp1.mydata.col2' in 'field list'
mysql>
*Additional info asked for by eggyal. Also I tried this on another mysql version with same result. *
mysql> CALL mysp(1);
+------+
| col2 |
+------+
| 2 |
| 4 |
| 6 |
+------+
3 rows in set (0.20 sec)
+----------------------------------+
| Result |
+----------------------------------+
| Please see new temp table mydata |
+----------------------------------+
1 row in set (0.20 sec)
Query OK, 0 rows affected (0.20 sec)
mysql> describe mydata;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| col2 | int(11) | YES | | NULL | |
+-------+---------+------+-----+---------+-------+
1 row in set (0.00 sec)
mysql> CALL mysp(0);
ERROR 1054 (42S22): Unknown column 'test.mydata.col2' in 'field list'
mysql> describe mydata;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| col1 | int(11) | YES | | NULL | |
+-------+---------+------+-----+---------+-------+
1 row in set (0.00 sec)
Interesting development of a fix - changing the last few lines to a prepared statement works - but using exactly the same query as before.
-- The following select call fails on 2nd and subsequent executions of the SP
PREPARE stmt FROM 'SELECT SQL_NO_CACHE * FROM mydata';
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SELECT "Please see new temp table mydata" as Result;
MySQL is reusing the statement that was prepared on the previous execution. It's not really "caching" column names; what it's "caching" (if you will) is the prepared statement.
The easy workaround is to use dynamic SQL statement to gain control over the behavior, and avoid the reuse of the previously prepared statement:
SET #s=CONCAT('SELECT ',#mycol,' FROM mydata');
PREPARE stmt FROM #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
It's not matter of the column names being "cached", or the results of the query being cached. It's a performance optimization; it's a matter of that statement already being prepared, within your session.
By using dynamic SQL, you can control when the statement is prepared (i.e. parsing the SQL text for syntax (statement formation, keywords, etc.), checked for semantics (object names exist, column names exist, user has required privileges, etc.), and preparing an execution plan.
With the static SQL, all of that happens on the first execution, and then MySQL hangs on to the prepared statement.
For performance reasons, we wouldn't want the overhead of a "hard parse" every time a static statement is executed. This is especially true on a function that gets called multiple times, from a SQL statement.
(NOTE: Oracle does the same thing, BUT, Oracle does a good job of marking prepared statements as INVALID whenever a referenced object is altered or dropped.)
MySQL opted not to do that, probably because of the overhead of tracking all the dependencies. And, in the vast majority of cases, that overhead is not required.
I think the lesson here is if you are going to use dynamic SQL to create a table that is going to have DIFFERENT columns in it, you are going to have to use dynamic SQL to query that table.
My recommendation is that you avoid using SELECT *, unless your statement is in complete control of the columns being returned, for example, from an inline view. Otherwise, SQL statements that use SELECT * are fundamentally broken... they may work now, but a change to a table (adding a column for example) will break an application.
Q: Please explain how it is not a bug.
It is not a bug because the SELECT statement in your stored procedure is really just shorthand for what is actually happening.
On the first execution of your procedure, MySQL is doing the parse of your query text, and preparing and executing a statement. Basically, equivalent to:
PREPARE s1 FROM 'SELECT * FROM mydata';
EXECUTE s1;
On the second execution of the procedure, MySQL is simply executing the statement that has been previously prepared. Basically, equivalent to:
EXECUTE s1;
On that second execution, you seem to be expecting MySQL to run the equivalent of:
DEALLOCATE PREPARE s1;
PREPARE s1 FROM 'SELECT * FROM mydata';
EXECUTE s1;
You can make a case that this is what MySQL should be doing on the second execution. You could argue that statements prepared during a previous execution of a procedure should be discarded, and re-parsed and re-prepared on subsequent executions.
It would not be wrong for a DBMS to do this. But there would be, as always, the consideration about the impact on performance.
You could also make a case that MySQL should track all the database objects that a particular prepared statement is dependent on. You could argue that whenever one of those database objects is dropped or altered, MySQL should invalidate all the prepared statements (and all other objects) that depend on the altered or dropped object. Again, it would not be wrong for a DBMS to do this. Some DBMSs (such as Oracle) do this quite well. But again, the developers of the DBMS also take performance into consideration when making these design and implementation decisions.
The bottom line is that MySQL does provide you with a way to make happen what you want to happen. It's just that the syntax in your procedure, what you are expecting to make it happen, doesn't actually make it happen.
first of all it is a temp table so really should not be expected to be there, 2nd - it is dropped
I think you are reading something different into the "TEMPORARY" keyword than is defined in the specification. A TEMPORARY table is really just like a regular table, except that it is visible only to the session that created it, and it will be automatically dropped when the MySQL session ends. (We also note that a TEMPORARY table is not displayed by a SHOW TABLES command, and does not appear in the information_schema views.)
As to which tables (TEMPORARY or otherwise) MySQL should expect "to be there", I don't believe the documentation really addresses that, except noting that when a SQL statement is executed, and that statement references an object that does not exist, MySQL will throw an exception.
The same behavior you observe with a TEMPORARY table, you will also observe with a non-TEMPORARY table. The issue is not related to whether the table is defined as TEMPORARY or not.
where does SELECT * compare to PREPARE s1 FROM SELECT *
Those two forms effectively follow the same code path. The first execution of a static SELECT * is effectively equivalent to:
PREPARE s1 FROM 'SELECT *';
EXECUTE s1;
(Note the absence of a DEALLOCATE statement following the exeuction.) On a subsequent execution, the statement is already prepared, so it's effectively equivalent to:
EXECUTE s1;
This is similar to what would happen if you were coding in PHP mysqli
$s1 = $mysqli->prepare("SELECT * FROM mydata");
$mysqli->execute($s1);
/* rename the columns in the mydata table */
$mysqli->execute($s1);
I understand this is relatively old (+6 months) but I encountered this problem in prepared statements, and the only way I got around it was to concatenate the field names and use a prepared statement that effectively calls "select *" but uses the actual field names. I'm using prepared statements to create a temporary table, and the only standard field is the first one, while the rest causes the caching problem on "Select *".
Select fields we want to use into a temp table
Iterate through table rows of field names, and on each iteration:
set sql01 = concat(sql01,',',sFieldName,''); (just fields) and: set sql02 = concat(sql02,',',sFieldName,' varchar(50) '); (fields + field type only, for create table statement)
create the output table:
set #sql = concat('CREATE TEMPORARY TABLE tOutput(FirstField varchar(50), ',sql02,');'); PREPARE STMT FROM #sql; EXECUTE STMT; DEALLOCATE PREPARE STMT;
At the end:
set #sql = concat('SELECT FirstField,',sql01,' FROM tOutput;'); PREPARE STMT FROM #sql; EXECUTE STMT; DEALLOCATE PREPARE STMT;
I'm trying to find out whether a delete query executed properly. I know how many rows its supposed to delete, and I'd like to check that the number that were deleted, matches what's expected, from within the query itself.
How do I find out the number of rows that I just deleted, from within a SQL query running against MySQL? Separate statements are fine, as long as I can bundle them into one query.
see MySQL ROW_COUNT function here http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_row-count
this is the query what you want,
SELECT ROW_COUNT()
mysql> DELETE FROM t WHERE i IN(1,2);
Query OK, 2 rows affected (0.00 sec)
mysql> SELECT ROW_COUNT() as DelRowCount;
+-------------+
| DelRowCount |
+-------------+
| 2 |
+-------------+
1 row in set (0.00 sec)