Mysql how to do this without locking - mysql

I want to query one table to see whether there exist any rows with 'A' type.
so I use this sql:
SELECT EXISTS(select * from %T where type = 'A');
then I need to update another table's column value to the above result. In order to prevent an insert with 'A' type happen during update, I am thinking to use a lock. but lock is very expensive, is there other alternative way to do this without locking?
If we have to use lock, I am thinking if table has already had type A, there is no need to lock insert during update because the result will still be 1. only prevent insert when there is no row with type A. How to do that?
Thanks!

Since you want to update a table when there is a type 'A', normally I would suggest you do the update or check every time right after inserting or deleting a row.
Or you could do something like this:
UPDATE table1 t1
LEFT JOIN table2 t2 ON t1.type = t2.type
SET t1.column1 = 1
WHERE t2.type IS NOT NULL
or
UPDATE table1 t1
SET t1.column1 = 1
WHERE EXISTS (
SELECT ...
FROM table2
WHERE type = 'A'
);
Please give me more details such as what is your table like and what exactly you want to do so we can discuss further.

Related

Update row as copy of a row in another table without set

I want to synchronize multiple tables. I want to copy a row from one table and update it to another table but I donot want to specify the column names. This is because I donot want to hard code the sql query for every table separately.
I have tried several variants, it worked with insert, but I cannot find a solution for it with Update
insert into t2 select * from t1 where sno=2;
In this code, I donot need to pass the columns names to Insert, it automatically knows the columns list. I want to achieve the same with Update where I donot want to pass the columns list inside SET portion.
you always need to use SET and assign columns one by one. However you can use subquery for updating your source table using another table
update
Table1 as T1
inner join (
select *
from Table2
where ...
) as t2 on t1.Id = t2.Id
set T1.something = t2.something
Well, if the columns are the same, you could do:
delete from t2
where exists (select 1 from t1 where t1.id = t2.id);
insert into t2
select *
from t1;
I don't see why update would be used to replace data (although I would still list all the columns).
If the columns are not the same, then you need to list out the ones that change.

mysql - insert results of query into same table with joins

I use this site all the time to find answers to my questions but this is the first time I've ask one.
I have two tables and want to query both tables and insert the results into two columns on table 1. Something like this:
SELECT a.column1 from table1 a LEFT Join ( SELECT 'column1' from 'table2' ) AS a ON where a.column1 like '%column1.table2%';
Basically then insert the result into column5 and column6 on table 1
I know that this isn't correct as it doesn't work and it's not going to update any thing. For testing I'm running select statements to verify before running the update command. Another way of saying what I need would be:
If column1 in table1 is like column1 in table2 then update column5 in table1 with corresponding entry from column2 in table2 and update column6 in table1 with column7 from table1 with corresponding entry in column3 from table2;
I realize that this is not the best explanation but that is the best way I can explain what I want. Please ask questions if more information is needed and I will do my best to explain.
Thanks for any input you have.
In MySQL you can do multi-table updates in a single update statement using joins in the table list:
update t1 inner join t2 on t1.column1 like concat('%',t2.column1, '%')
set t1.column5=t2.column2, t1.column6=t2.column7
However, using like is not necessarily the best idea, since more than 1 records from t2 may match the same record within t1, therefore a single t1 record may be updated several times during a single run.
Your description of which t1 fields should be updated by which field from t2 is inaccurate, cannot really tell the logic there.

Moving Data from Table to Table with new Column

I have been trying to move some data which relates to a specific column from one table to another. They both have a matching objectID.
So what I am trying to do is:
TABLE 1
ObjectID
Field with Data
TABLE 2
ObjectID
FIELD with NEW column
So the object ID relate to each other. All it is I am trying to do is move the data from Table 1 to Table 2 with the new column.
I have tried following but cant seem to get it all working. Is there anything that can be suggested that may help or point in me the right direction.
update Table2 a
Set a.NewColumn = (Select *
From Table1 b WHERE a.OBJECTID = b.OBJECTID
)
Hm, maybe I don't get it but why don't you use a INSERT?
INSERT INTO TableB(...columns...)
SELECT ...columns...
FROM TableA
You can use join update syntax for this, need to make sure that the Table2 already has data and you are updating a new column in there from Table1
update Table2 t2
join Table1 t1 on t1.OBJECTID = t2.OBJECTID
set t2.NewColumn = t1.Field
You can write query like this.
INSERT INTO Table2(ObjectID,Field)
SELECT ObjectID,Field
FROM Table1.
And you can put any default value in extra column.

could a rows lock made with IN(,,,) generate dead locks?

My goal is to avoid dead locks and so I centralized all locks in the same place ordering by table name and then by ID ascending:
SELECT * FROM table1 WHERE ID = 1 FOR UPDATE
SELECT * FROM table1 WHERE ID = 2 FOR UPDATE
SELECT * FROM table1 WHERE ID = 3 FOR UPDATE
SELECT * FROM table1 WHERE ID = 4 FOR UPDATE
SELECT * FROM table2 WHERE ID = 1 FOR UPDATE
SELECT * FROM table2 WHERE ID = 2 FOR UPDATE
SELECT * FROM table2 WHERE ID = 3 FOR UPDATE
SELECT * FROM table2 WHERE ID = 4 FOR UPDATE
but I wonder if I can do the same using IN() (which is probably a bit faster)
SELECT * FROM table1 WHERE ID IN(1,2,3,4) FOR UPDATE
SELECT * FROM table2 WHERE ID IN(1,2,3,4) FOR UPDATE
will the rows be locked in the exact order specified by the IN() operand or the lock will be applied using the "natural table ordering" instead?
ID is a primary auto_increment field in all tables and I don't "reuse" old deleted IDs (so in theory the natural ordering should always be ascending)
thanks in advance!
added the update:
UPDATE table1 SET t1="hello1" WHERE ID = 1;
UPDATE table1 SET t1="hello2" WHERE ID = 2;
UPDATE table1 SET t1="hello3" WHERE ID = 3;
UPDATE table1 SET t1="hello4" WHERE ID = 4;
UPDATE table2 SET t2="hello1" WHERE ID = 1;
UPDATE table2 SET t2="hello2" WHERE ID = 2;
UPDATE table2 SET t2="hello3" WHERE ID = 3;
UPDATE table2 SET t2="hello4" WHERE ID = 4;
...
COMMIT;
Even though it's a little unclear but some part of the answer to your question is stated in the MySQL's documentation:
expr IN (value,...)
Returns 1 if expr is equal to any of the values in the IN list, else
returns 0. If all values are constants, they are evaluated according
to the type of expr and sorted. The search for the item then is done
using a binary search.
Here's what you should get of it: If all values in the list are constants, they are compared sorted using binary search.
So in the end, it doesn't matter if you have sorted the values or not, because MySQL will sort them even if they are not. Nevertheless this wasn't your question. Now let's get back to your question.
First of all, deadlocks are absolutely possible in MySQL when your are using InnoDb and they happen all the time (at least to me). The strategy you've chosen to prevent deadlocks is a valid one (acquiring locks according to some order). But unfortunately I don't think it's going to work in MySQL. You see, even though in your query it is clearly stated which records you want to be locked, but the truth is that they are not the only records that will be locked:
A locking read, an UPDATE, or a DELETE generally set record locks on
every index record that is scanned in the processing of the SQL
statement. It does not matter whether there are WHERE conditions in
the statement that would exclude the row. InnoDB does not remember the
exact WHERE condition, but only knows which index ranges were scanned.
The locks are normally next-key locks that also block inserts into the
“gap” immediately before the record. However, gap locking can be
disabled explicitly, which causes next-key locking not to be used.
So it's hard to say which records are actually locked. Now consider MySQL is searching the index for the first value in your list. As I've just said few more records might be locked along the way while MySQL is scanning the index. And since scanning indices does not happen in order (or at least that's what I believe), records would get locked regardless of their order. Which means that deadlocks are not prevented.
The last part is my own understanding of the situation and I've actually never read that anywhere before. But in theory it sounds right. Yet I really would like someone to prove me wrong (just so I can trust MySQL even more).
Ok so this question is not really that clear as to what you want... so this may not be an answer to your question.. but I made some test stuff to help you visualize the data and how IN() works.. so I hope thats at least helpful.
SETUP:
CREATE TABLE table1
(`id` int, `username` varchar(10), `t1` varchar(55));
INSERT INTO table1
(`id`, `username`, `t1`)
VALUES
(4, 'John', 'Hi1'),
(3, 'Ram ', 'Hi2'),
(2, 'Jack', 'Hi3'),
(1, 'Jill', 'Hi4');
CREATE TABLE table2
(`id` int, `username` varchar(10), `t1` varchar(55));
INSERT INTO table2
(`id`, `username`, `t1`)
VALUES
(1, 'Joe', 'Hey1'),
(2, 'Fes', 'Hey2'),
(3, 'Ned', 'Hey3'),
(4, 'Abe', 'Hey4');
I made table1 have a backwards ID.. aka 4, 3, 2, 1 and then table2 has the regular incremented id. 1, 2, 3, 4...
1. SELECT * FROM table1
RESULT-OF-1
2. SELECT * FROM table2
RESULT-OF-2
3. SELECT * FROM table1 WHERE id = 1 OR id = 2 OR id = 3 OR id = 4 same result as 1
4. SELECT * FROM table1 WHERE id IN(1, 2, 3, 4).. same result as 1.
5. SELECT * FROM table1 WHERE id IN(1, 4, 3, 2).. same result as 1.
IN() compares the id from each row in the table to what is specified inside the IN() statement.. if it matches it will return the row.. so it returns the data in the "natural table ordering" .. more info HERE
there is a way to do the update you posted with an IN() statement.. without writing out each update.
UPDATE table1 SET t1= CONCAT('hello', ID) WHERE ID IN(1,2,3,4);
UPDATE table2 SET t2= CONCAT('hello', ID) WHERE ID IN(1,2,3,4);
all you do here is combine the 'hello' string with the ID and set your column to it since that is what you posted. I hope that helps understand how the data gets pulled out.
output for the two updates : table1.... table2
for locking tables to update you should probably lock them to WRITE and UNLOCK to prevent a deeplock. see post
LOCK TABLES table1 WRITE, table2 WRITE;
UPDATE table1 SET t1= CONCAT('hello', ID) WHERE ID IN(1,2,3,4);
UPDATE table2 SET t1= CONCAT('hello', ID) WHERE ID IN(1,2,3,4);
UNLOCK TABLES;
Rows are locked in the order they are read, so no order is guaranteed. Even if you add an ORDER BY clause, the rows will be locked as they are read, not as they are ordered. Here is another good question with some great answers

updating multiple blank fields in one table with data from another table

I am trying to find all fields in one table that are empty and populate them with data from another table. Here is what I have:
UPDATE t1 SET col1 = (
SELECT col99
FROM t2
WHERE t1.product_ID = t2.product_ID
) WHERE col1 IS NULL
which works perfectly for updating all the blank fields in col1 of t1. But I also need to check for blanks in other fields and update them. I don't want the query to update all the fields each time any one of them is blank, just the blank field. I could run multiple queries but I have to imagine there is a cleaner, better way.
Thanks,
Matthew
Try:
UPDATE t1
SET
col1 = COALESCE(col1, (SELECT col99 FROM t2 WHERE t1.product_ID = t2.product_ID)),
col2 = COALESCE(col2, (SELECT ...)),
-- etc.
Should not perform better than your initial solution. It's just doing the job with only one UPDATE query instead of several.