so if i have a stored procedure that contains selects how to suppress the results from these selects from appearing ?
for example if i have
create procedure xyz
begin
select * from table_name #I don't want this to be seen in the console.
do other stuff
end;
You can set the required params into variables like
SET #foo = (SELECT foo_coloumn FROM foo_table);
This will suppress the select result set.
The accepted answer didn't work for me since the resultset was multirow. I did figure out a solution, though:
CREATE TEMPORARY TABLE silence_output SELECT * FROM foo;
DROP TEMPORARY TABLE silence_output;
This avoids any multirow/multicolumn issues that might be encountered by dumping the resultset into a table that is then trashed. Hope this helps someone else. You can name the temporary table anything.
I was struggling to find a way to suppress multirow output in a stored procedure while at the same time locking all applicable rows with "FOR UPDATE".
First attempt was "SELECT ... INTO" with a "LIMIT" clause but that would only lock 1 row.
Using GROUP_CONCAT solved it for me:
SELECT GROUP_CONCAT(column) INTO #variable
FROM table
WHERE column = value
FOR UPDATE
Doing that in a transaction locked all affected rows, prevented an insert, and suppressed output.
Related
I am want to return two tables from one Stored Proc. I am not sure if it is possible or not, but it is possible in MSSQL, so, I guess it is possible in MYSQL as well.
What I want to achieve is:
select * from table1;
select * from table2;
result in dataset of two tables. As I experienced till now, where MYSQL get's the first select it returns from there.
I have tried to find on Google, but I didn't find anything that works.
Yes, you can return as many result sets as you like.
delimiter $$
create procedure sp_result_sets()
begin
select * from table1;
select * from table2;
end
$$
I need to SET a variable before my MySQL query.
Here is my query.
But it throws an error:
A new statement was found, but no delimiter between it and the previous one near (SELECT)`
I need to use this variable in my query as well. How can I solve it?
If this is outside a stored procedure, SET won't work, why not try SELECT... INTO instead?
CREATE TABLE booking_packages (adultPrice SMALLINT UNSIGNED);
INSERT INTO booking_packages VALUES (10);
SELECT adultprice INTO #adultprice FROM booking_packages;
SELECT #adultprice;
Also note that unless booking_packages only has one row, you'll need a WHERE to ensure the query only returns one row to insert into the #adultprice session variable.
Regards,
James
i have 10 tables with same structure except table name.
i have a sp (stored procedure) defined as following:
select * from table1 where (#param1 IS NULL OR col1=#param1)
UNION ALL
select * from table2 where (#param1 IS NULL OR col1=#param1)
UNION ALL
...
...
UNION ALL
select * from table10 where (#param1 IS NULL OR col1=#param1)
I am calling the sp with the following line:
call mySP('test') //it executes in 6,836s
Then I opened a new standard query window. I just copied the query above. Then replaced #param1 with 'test'.
This executed in 0,321s and is about 20 times faster than the stored procedure.
I changed the parameter value repeatedly for preventing the result to be cached. But this did not change the result. The SP is about 20 times slower than the equivalent standard query.
Please can you help me to figure out why this is happening ?
Did anybody encounter similar issues?
I am using mySQL 5.0.51 on windows server 2008 R2 64 bit.
edit: I am using Navicat for test.
Any idea will be helpful for me.
EDIT1:
I just have done some test according to Barmar's answer.
At finally i have changed the sp like below with one just one row:
SELECT * FROM table1 WHERE col1=#param1 AND col2=#param2
Then firstly i executed the standart query
SELECT * FROM table1 WHERE col1='test' AND col2='test' //Executed in 0.020s
After i called the my sp:
CALL MySp('test','test') //Executed in 0.466s
So i have changed where clause entirely but nothing changed. And i called the sp from mysql command window instead of navicat. It gave same result. I am still stuck on it.
my sp ddl:
CREATE DEFINER = `myDbName`#`%`
PROCEDURE `MySP` (param1 VARCHAR(100), param2 VARCHAR(100))
BEGIN
SELECT * FROM table1 WHERE col1=param1 AND col2=param2
END
And col1 and col2 is combined indexed.
You could say that why dont you use standart query then? My software design is not proper for this. I must use stored procedure. So this problem is highly important to me.
EDIT2:
I have gotten query profile informations. Big difference is because of "sending data row" in SP Profile Information. Sending data part takes %99 of query execution time. I am doing test on local database server. I am not connecting from remote computer.
SP Profile Informations
Query Profile Informations
I have tried force index statement like below in my sp. But same result.
SELECT * FROM table1 FORCE INDEX (col1_col2_combined_index) WHERE col1=#param1 AND col2=#param2
I have changed sp like below.
EXPLAIN SELECT * FROM table1 FORCE INDEX (col1_col2_combined_index) WHERE col1=param1 AND col2=param2
This gave this result:
id:1
select_type=SIMPLE
table:table1
type=ref
possible_keys:NULL
key:NULL
key_len:NULL
ref:NULL
rows:292004
Extra:Using where
Then i have executed the query below.
EXPLAIN SELECT * FROM table1 WHERE col1='test' AND col2='test'
Result is:
id:1
select_type=SIMPLE
table:table1
type=ref
possible_keys:col1_co2_combined_index
key:col1_co2_combined_index
key_len:76
ref:const,const
rows:292004
Extra:Using where
I am using FORCE INDEX statement in SP. But it insists on not using index. Any idea? I think i am close to end :)
Just a guess:
When you run the query by hand, the expression WHERE ('test' IS NULL or COL1 = 'test') can be optimized when the query is being parsed. The parser can see that the string 'test' is not null, so it converts the test to WHERE COL1 = 'test'. And if there's an index on COL1 this will be used.
However, when you create a stored procedure, parsing occurs when the procedure is created. At that time, it doesn't know what #param will be, and has to implement the query as a sequential scan of the table.
Try changing your procedure to:
IF #param IS NULL
THEN BEGIN
SELECT * FROM table1
UNION ALL
SELECT * FROM table2
...
END;
ELSE BEGIN
SELECT * FROM table1 WHERE col1 = #param
UNION ALL
SELECT * FROM table2 WHERE col1 = #param
...
END;
END IF;
I don't have much experience with MySQL stored procedures, so I'm not sure that's all the right syntax.
Possible character set issue? If your table character set is different from your database character set, this may be causing a problem.
See this bug report: http://bugs.mysql.com/bug.php?id=26224
[12 Nov 2007 21:32] Mark Kubacki Still no luck with 5.1.22_rc - keys
are ingored, query takes within a procedure 36 seconds and outside
0.12s.
[12 Nov 2007 22:30] Mark Kubacki After having changed charsets to UTF-8 (especially for the two used), which is used for the
connection anyways, keys are taken into account within the stored
procedure!
The question I cannot answer is: Why does the optimizer treat charset
conversions an other way within and outside stored procedures?
(Indeed, I might be wrong asking this.)
Interesting question, because I am fond of using stored procedures. Reason is maintenance and the encapsulation principle.
This is information I found:
http://dev.mysql.com/doc/refman/5.1/en/query-cache-operation.html
It states that the query cache is not used for queries that
1. are a subquery that belong to an outer query, and
2. are executed within the body of a stored procedure, trigger or event.
This implies that it works as designed.
I had seen this behavior, but it wasn't related to the character set.
I had a table that held self-referencing hierarchical data (a parent with children, and some children had children of their own, etc.). Since the parent_id had to reference the primary id's (and the column specified a constraint to that effect), I couldn't set the parent id to NULL or 0 (zero) to disassociate a child from a parent, so I simply referenced it to itself.
When I went to run a stored procedure to perform the recursive query to find all children (at all levels) of a particular parent, the query took between 30 & 40 times as long to run. I found that altering the query used by the stored procedure to make sure it excluded the top-level parent record (by specifying WHERE parent_id != id) restored the performance of the query.
The stored procedure I'm using is based on the one shown in:
https://stackoverflow.com/questions/27013093/recursive-query-emulation-in-mysql.
I'm trying to select a column from a record variable in a function I'm calling from an Update rule and am getting the following error:
'could not identify column "name" in record data type'
The following is what I'm doing to produce the error:
From within an Update rule:
SELECT * INTO TEMPORARY TABLE TempTable FROM NEW;
SELECT MyFunction();
From within MyFunction()
DECLARE RecordVar Record;
SELECT * INTO STRICT RecordVar FROM TempTable;
EXECUTE 'UPDATE AnotherTable SET column = $1.name' USING RecordVar;
Note: I realise that there are easier ways to achieve what the above code is achieving but I've simplified the actual implementation to focus on the problem I'm having, which has opened up other possible solutions but I'd really like to get the above code working if possible.
I just figured it out. Rather than inserting the columns from NEW into the Temporary Table, I insert the NEW record as a single column into the Temporary Table and refer to it as RecordVar."NEW" inside my function. My rule and function now look like this:
From within an Update rule:
SELECT NEW AS "NEW" INTO TEMPORARY TABLE TempTable;
SELECT MyFuction();
From within MyFunction()
DECLARE RecordVar Record;
SELECT * INTO STRICT RecordVar FROM TempTable;
EXECUTE 'UPDATE AnotherTable SET column = $1.name' USING RecordVar."NEW";
The second part could work like this:
DO
$BODY$
DECLARE
RecordVar TempTable;
BEGIN
SELECT * INTO STRICT RecordVar FROM TempTable LIMIT 1;
EXECUTE 'UPDATE AnotherTable SET column = $1.name'
USING RecordVar;
END;
$BODY$
Note how I use the table name as type. PostgreSQL automatically creates a composite type for every table in the system.
A variable holds one row, the SELECT can return many rows. All but the first will be discarded. I added LIMIT 1 to clarify the effect. I doubt that is what you want.
You probably shouldn't have to use a temporary table in a rule to begin with. You may want to post your complete setup ...
Here is the updated question:
the current query is doing something like:
$sql1 = "TRUNCATE TABLE fubar";
$sql2 = "CREATE TEMPORARY TABLE IF NOT EXISTS fubar SELECT id, name FROM barfu";
The first time the method containing this is run, it generates an error message on the truncate since the table doesn't exist yet.
Is my only option to do the CREATE TABLE, run the TRUNCATE TABLE, and then fill the table? (3 separate queries)
original question was:
I've been having a hard time trying to figure out if the following is possible in MySql without having to write block sql:
CREATE TABLE fubar IF NOT EXISTS ELSE TRUNCATE TABLE fubar
If I run truncate separately before the create table, and the table doesn't exist, then I get an error message. I'm trying to eliminate that error message without having to add any more queries.
This code will be executed using PHP.
shmuel613, it would be better to update your original question rather than replying. It's best if there's a single place containing the complete question rather than having it spread out in a discussion.
Ben's answer is reasonable, except he seems to have a 'not' where he doesn't want one. Dropping the table only if it doesn't exist isn't quite right.
You will indeed need multiple statements. Either conditionally create then populate:
CREATE TEMPORARY TABLE IF NOT EXISTS fubar ( id int, name varchar(80) )
TRUNCATE TABLE fubar
INSERT INTO fubar SELECT * FROM barfu
or just drop and recreate
DROP TABLE IF EXISTS fubar
CREATE TEMPORARY TABLE fubar SELECT id, name FROM barfu
With pure SQL those are your two real classes of solutions. I like the second better.
(With a stored procedure you could reduce it to a single statement. Something like: TruncateAndPopulate(fubar) But by the time you write the code for TruncateAndPopulate() you'll spend more time than just using the SQL above.)
You could do the truncate after the 'create if not exists'.
That way it will always exist... and always be empty at that point.
CREATE TABLE fubar IF NOT EXISTS
TRUNCATE TABLE fubar
execute any query if table exists.
Usage: call Edit_table(database-name,table-name,query-string);
Procedure will check for existence of table-name under database-name and will execute query-string if it exists.
Following is the stored procedure:
DELIMITER $$
DROP PROCEDURE IF EXISTS `Edit_table` $$
CREATE PROCEDURE `Edit_table` (in_db_nm varchar(20), in_tbl_nm varchar(20), in_your_query varchar(200))
DETERMINISTIC
BEGIN
DECLARE var_table_count INT;
select count(*) INTO #var_table_count from information_schema.TABLES where TABLE_NAME=in_tbl_nm and TABLE_SCHEMA=in_db_nm;
IF (#var_table_count > 0) THEN
SET #in_your_query = in_your_query;
#SELECT #in_your_query;
PREPARE my_query FROM #in_your_query;
EXECUTE my_query;
ELSE
select "Table Not Found";
END IF;
END $$
DELIMITER ;
More on Mysql
how about:
DROP TABLE IF EXISTS fubar;
CREATE TABLE fubar;
Or did you mean you just want to do it with a single query?
OK then, not bad. To be more specific, the current query is doing something like:
$sql1 = "TRUNCATE TABLE fubar";
$sql2 = "CREATE TEMPORARY TABLE IF NOT EXISTS fubar SELECT id, name FROM barfu";
The first time the method containing this is run, it generates an error message on the truncate since the table doesn't exist yet.
Is my only option to do the "CREATE TABLE", run the "TRUNCATE TABLE", and then fill the table? (3 separate queries)
PS - thanks for responding so quickly!
If you're using PHP, use mysql_list_tables to check that the table exists before TRUNCATE it.