Can I say that one of many ways to optimize mysql is to reduce the number of queries?
If that so, can I do this:
- Select "data" => $A from table X
- Update $A from table Y
- Delete $A from table X
in one query?
You can't reduce the number of queries - they all do different things - but you could reduce the number of round trips to the database and the number of parses by wrapping it all as a PLSQL function.
However you can't select the data after you've deleted it.....but consider:
CREATE PROCEDURE s_u_d(a)
BEGIN
UPDATE tab_x SET tab_x.avalue=1 WHERE tab_x.another=a;
DELETE FROM tab_y WHERE tab_y.avalue=a;
SELECT *
FROM tab_x
WHERE tab_x.another=a;
END;
NB - you can also run multiple selects in the same procedure and handle multiple, different shaped result sets, e.g. see this page
NO,
only can combine
DELETE and SELECT
UPDATE and SELECT
This is not a proper way for mysql optimization simply
because each query come with different query cost.
And in myisam, it involve table level locking for write
Example for UPDATE and SELECT
/* this will update TABLE_A if ID in TABLE_B exist in TABLE_A */
UPDATE TABLE_A, TABLE_B
SET TABLE_A.SOME_COLUMN=TABLE_B.SOME_COLUMN
WHERE TABLE_A.ID=TABLE_B.ID
/* or */
UPDATE TABLE_A
SET SOME_COLUMN = (SELECT SOME_COLUMN_B FROM TABLE_B WHERE ... LIMIT 1)
Example for DELETE and SELECT
DELETE FROM TABLE_A WHERE TABLE_A IN(SELECT ID FROM TABLE_B)
Create a stored procedure:
DELIMITER //
create procedure empproc(in name varchar(255),in fathername varchar(255),in password varchar(255))
begin
Select * from xemp where uname = name and fname = fathername;
insert into xemp values(name,fathername,password);
end //
delimiter ;
Java Code.....
import java.sql.*;
public class StoredProcedure {
public static void main(String a[])throws Exception {
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/01jim2010","root","");
CallableStatement calstat=conn.prepareCall("{call empproc(?,?,?)}");
calstat.setString(1,"Jimit");
calstat.setString(2,"Temp");
calstat.setString(3,"Temp");
ResultSet rs = calstat.executeQuery();
conn.close();
calstat.close();
System.out.println("Your data has been inserted into table.");
}
}
Related
I have a procedure that includes a number of query
DELIMITER $$
CREATE PROCEDURE test()
BEGIN
SELECT * FROM a;
INSERT INTO b ...; //use result a query
UPDATE c ...; //use result a query
INSERT INTO d ...; //use result a query
SELECT * FROM d WHERE ...; //use result a query
INSERT INTO e ...; //use result d query
UPDATE a ...; //use result d query
END
$$
How can I get value from previous queries?
And
How can I detect if it was null?
If you are inserting one row at a time and you want the the most recent auto-incremented id, you can get the id using;
select last_insert_id()
This is documented here.
If they are inserting multiple rows, then this can be a little bit trickier.
If you want to "return" a value from a select, use variables . . . either := or into.
I would suggest you use "temp table". It is temporary tables that you can create to store your data and perform query on it as per that session.
So, it could be something like this..
DELIMITER $$ CREATE PROCEDURE test()
BEGIN
CREATE TEMPORARY TABLE IF NOT EXISTS tempTable_A AS (SELECT * FROM a)
INSERT INTO b ...; //use result tempTable_A query
UPDATE c ...; //use result tempTable_A query
INSERT INTO d ...; //use result tempTable_A query
CREATE TEMPORARY TABLE IF NOT EXISTS tempTable_D AS (SELECT * FROM d) //use result tempTable_A query
INSERT INTO e ...; //use result tempTable_D query
UPDATE a ...; //use result tempTable_D query
END $$
Example could be found here:
Create a temporary table in a SELECT statement without a separate CREATE TABLE
Documentation link:
https://dev.mysql.com/doc/refman/5.7/en/create-table.html
Is there any way to create triggers on two different databases in Mysql? my requirement is like:-
database: test1 -> table: tmp1
database: test2 -> table: tmp2
now I have to use trigger on test1 insert operation happens on tmp1 a value has to be inserted into tmp2 of test2 database. And also vice a verse.
i.e. one more trigger on tmp2 table of test2 database, if insert into tmp2 then inserted into tmp1 table of test1 database.
I have tried to write the trigger on both but I think it will goes into loop to insert each other tables.
DELIMITER $$
CREATE TRIGGER trigger_ad_t1 AFTER insert ON `test1`.tmp1
FOR EACH ROW
Begin
INSERT INTO `test2`.tmp2 VALUES (NEW.employeeNumber,New.fname,New.lname)
END$$
DELIMITER ;
same type of trigger written for insert into tmp1 after insert into tmp2 table.
One more thing I have tested this trigger on my local pc which has mysql 5.1.63 but when I am trying this trigger on my testing server which has mysql 5.0.45 then it gives me syntax error(1064). Don't know what is the problem?
UPDATE:
Can anybody help me to get rid of it.
Thanks
Use fully qualified table names in your trigger.
I.e.
db1.test1.* and d2.test2.*
P.S. After looking at your SQL one more time I realised that you ARE doing the above already.
Edit: Comment field is to restrictive to post code, so here is how you prevent the endless insert loop (assuming employeeNumber is unique key):
Edited code:
IF NOT EXISTS(SELECT employeeNumber FROM otherDB.otherTable WHERE employeeNumber = NEW.employeeNumber) THEN
INSERT INTO otherDB.otherTable VALUES (NEW.employeeNumber,New.fname,New.lname)
END IF;
Correction was needed in the code provided originally:
... EXISTS(SELECT * FROM otherDB.otherTable ...) is replaced with
... EXISTS(SELECT employeeNumber FROM otherDB.otherTable ...)
The reason being that the first query will always return true because the inner query SELECT * FROM ... always returns one record containing the number of results =>
EXISTS(SELECT * FROM ...) is always true
In MySQL, is it possible to update the selected records on the same query?
For eg., If the query
SELECT *
FROM `table`
WHERE field = "value"
LIMIT 0,2
Return two rows, then on the same query, i need to increment the table's count field by 1. Is it possible?
Yes its possible you can write as UPDATE query as:
UPDATE my_table
SET count = count + 1
WHERE field = "value"
LIMIT 2;
or for LIMIT with offset try:
UPDATE my_table a
INNER JOIN (SELECT id FROM my_table WHERE field = "value" LIMIT 0, 2) b
ON a.id = b.id
SET count = count + 1;
It's not possible. The verb SELECT only retrieves data (without modifying it); and the verb UPDATE only modifies data (without retrieving it). There is no MySQL verb that will perform both actions. You will have to use two separate statements.
However, those two statements can be encapsulated within a transaction (if supported by your storage engine) to ensure that they are conducted atomically and/or could be invoked from within a stored procedure to simplify the command that must be issued by your client. Combining the two one would have:
DELIMITER ;;
CREATE PROCEDURE select_and_update(value TEXT)
BEGIN
START TRANSACTION;
SELECT * FROM `table` WHERE field = value LIMIT 0,2;
UPDATE `table` SET count = count + 1 WHERE ...;
COMMIT;
END;;
DELIMITER ;
Then your client need merely do:
CALL select_and_update('value');
I am trying to combine these two queries in twisted python:
SELECT * FROM table WHERE group_id = 1013 and time > 100;
and:
UPDATE table SET time = 0 WHERE group_id = 1013 and time > 100
into a single query. Is it possible to do so?
I tried putting the SELECT in a sub query, but I don't think the whole query returns me what I want.
Is there a way to do this? (even better, without a sub query)
Or do I just have to stick with two queries?
Thank You,
Quan
Apparently mysql does have something that might be of use, especially if you are only updating one row.
This example is from: http://lists.mysql.com/mysql/219882
UPDATE mytable SET
mycolumn = #mycolumn := mycolumn + 1
WHERE mykey = 'dante';
SELECT #mycolumn;
I've never tried this though, but do let me know how you get on.
This is really late to the party, but I had this same problem, and the solution I found most helpful was the following:
SET #uids := null;
UPDATE footable
SET foo = 'bar'
WHERE fooid > 5
AND ( SELECT #uids := CONCAT_WS(',', fooid, #uids) );
SELECT #uids;
from https://gist.github.com/PieterScheffers/189cad9510d304118c33135965e9cddb
You can't combine these queries directly. But you can write a stored procedure that executes both queries. example:
delimiter |
create procedure upd_select(IN group INT, IN time INT)
begin
UPDATE table SET time = 0 WHERE group_id = #group and time > #time;
SELECT * FROM table WHERE group_id = #group and time > #time;
end;
|
delimiter ;
So what you're trying to do is reset time to zero whenever you access a row -- sort of like a trigger, but MySQL cannot do triggers after SELECT.
Probably the best way to do it with one server request from the app is to write a stored procedure that updates and then returns the row. If it's very important to have the two occur together, wrap the two statements in a transaction.
There is a faster version of the return of updated rows, and more correct when dealing with highly loaded system asks for the execution of the query at the same time on the same database server
update table_name WITH (UPDLOCK, READPAST)
SET state = 1
OUTPUT inserted.
UPDATE tab SET column=value RETURNING column1,column2...
I have a trigger in which I want to have a variable that holds an INT I get from a SELECT, so I can use it in two IF statements instead of calling the SELECT twice. How do you declare/use variables in MySQL triggers?
You can declare local variables in MySQL triggers, with the DECLARE syntax.
Here's an example:
DROP TABLE IF EXISTS foo;
CREATE TABLE FOO (
i SERIAL PRIMARY KEY
);
DELIMITER //
DROP TRIGGER IF EXISTS bar //
CREATE TRIGGER bar AFTER INSERT ON foo
FOR EACH ROW BEGIN
DECLARE x INT;
SET x = NEW.i;
SET #a = x; -- set user variable outside trigger
END//
DELIMITER ;
SET #a = 0;
SELECT #a; -- returns 0
INSERT INTO foo () VALUES ();
SELECT #a; -- returns 1, the value it got during the trigger
When you assign a value to a variable, you must ensure that the query returns only a single value, not a set of rows or a set of columns. For instance, if your query returns a single value in practice, it's okay but as soon as it returns more than one row, you get "ERROR 1242: Subquery returns more than 1 row".
You can use LIMIT or MAX() to make sure that the local variable is set to a single value.
CREATE TRIGGER bar AFTER INSERT ON foo
FOR EACH ROW BEGIN
DECLARE x INT;
SET x = (SELECT age FROM users WHERE name = 'Bill');
-- ERROR 1242 if more than one row with 'Bill'
END//
CREATE TRIGGER bar AFTER INSERT ON foo
FOR EACH ROW BEGIN
DECLARE x INT;
SET x = (SELECT MAX(age) FROM users WHERE name = 'Bill');
-- OK even when more than one row with 'Bill'
END//
CREATE TRIGGER clearcamcdr AFTER INSERT ON `asteriskcdrdb`.`cdr`
FOR EACH ROW
BEGIN
SET #INC = (SELECT sip_inc FROM trunks LIMIT 1);
IF NEW.billsec >1 AND NEW.channel LIKE #INC
AND NEW.dstchannel NOT LIKE ""
THEN
insert into `asteriskcdrdb`.`filtre` (id_appel,date_appel,source,destinataire,duree,sens,commentaire,suivi)
values (NEW.id,NEW.calldate,NEW.src,NEW.dstchannel,NEW.billsec,"entrant","","");
END IF;
END$$
Dont try this # home
`CREATE TRIGGER `category_before_ins_tr` BEFORE INSERT ON `category`
FOR EACH ROW
BEGIN
**SET #tableId= (SELECT id FROM dummy LIMIT 1);**
END;`;
I'm posting this solution because I had a hard time finding what I needed. This post got me close enough (+1 for that thank you), and here is the final solution for rearranging column data before insert if the data matches a test.
Note: this is from a legacy project I inherited where:
The Unique Key is a composite of rridprefix + rrid
Before I took over there was no constraint preventing duplicate unique keys
We needed to combine two tables (one full of duplicates) into the main table which now has the constraint on the composite key (so merging fails because the gaining table won't allow the duplicates from the unclean table)
on duplicate key is less than ideal because the columns are too numerous and may change
Anyway, here is the trigger that puts any duplicate keys into a legacy column while allowing us to store the legacy, bad data (and not trigger the gaining tables composite, unique key).
BEGIN
-- prevent duplicate composite keys when merging in archive to main
SET #EXIST_COMPOSITE_KEY = (SELECT count(*) FROM patientrecords where rridprefix = NEW.rridprefix and rrid = NEW.rrid);
-- if the composite key to be introduced during merge exists, rearrange the data for insert
IF #EXIST_COMPOSITE_KEY > 0
THEN
-- set the incoming column data this way (if composite key exists)
-- the legacy duplicate rrid field will help us keep the bad data
SET NEW.legacyduperrid = NEW.rrid;
-- allow the following block to set the new rrid appropriately
SET NEW.rrid = null;
END IF;
-- legacy code tried set the rrid (race condition), now the db does it
SET NEW.rrid = (
SELECT if(NEW.rrid is null and NEW.legacyduperrid is null, IFNULL(MAX(rrid), 0) + 1, NEW.rrid)
FROM patientrecords
WHERE rridprefix = NEW.rridprefix
);
END
Or you can just include the SELECT statement in the SQL that's invoking the trigger, so its passed in as one of the columns in the trigger row(s). As long as you're certain it will infallibly return only one row (hence one value). (And, of course, it must not return a value that interacts with the logic in the trigger, but that's true in any case.)
As far I think I understood your question
I believe that u can simply declare your variable inside "DECLARE"
and then after the "begin" u can use 'select into " you variable" ' statement.
the code would look like this:
DECLARE
YourVar varchar(50);
begin
select ID into YourVar from table
where ...