mysql update table set column3 where table1.column1 like concat ('%',table2.column2,'%') - mysql

I saw recently (can't find it now) this syntax:
... LIKE CONCAT('%',col1,'%')
It is working for Selects but for update, it affects 0 rows
this is my query:
update locations set email = (
select col2 from vendoremail
where locations.city LIKE CONCAT('%',col1,'%')
AND locations.zip LIKE CONCAT('%',col1,'%')
)
here is a sample of col1 :
"455 N Cherokee St: Muskogee, OK 74403"
without the quotes
I hope I have given enough data to elicit an answer or two - thank you!

You have it backwards. You want to put the city and zip into the pattern.
update locations set email = (
select col2 from vendoremail
where col1 LIKE CONCAT('%', locations.city, '%', locations.zip, '%')
)
However, this may not always work properly. If you have two vendors in the same city+zip, the subquery will return 2 emails, but when you use a subquery as a value it has to return only 1 row. You can add LIMIT 1 to the subquery to prevent an error when this happens. But it will be selecting one of the vendors unpredictably -- maybe you should come up with a more reliable way to match the tables.

If col1 is = "455 N Cherokee St: Muskogee, OK 74403"
i think location.city is = Muskogee and locations.zip is = 74403
then the query should be
update locations
set email = (
select col2 from vendoremail
where col1 LIKE CONCAT('%',locations.city,'%')
AND col1 locations.zip LIKE CONCAT('%',locations.zip,'%')
)

Related

SQL Query optimization -performance issues

I have the following SQL query I want to optimize :
select table1.tiers as col1, table1.id_item as col2
from items table1
where (table1.tiers is not null)
and table1.tiers<>''
and table1.id_item = (select max(table2.id_item)
from items table2
where table1.tiers=table2.tiers)
and table1.n_version_item=(select max(table2.n_version_item)
from items table2
where table2.id_item=table1.id_item)
I tried this:
select table1.tiers as col1, table1.id_item as col2
from items table1
where (table1.tiers is not null)
and table1.tiers<> ''
and CONCAT(table1.id_item,table1.n_version_item) = (select CONCAT(max(table2.id_item),max(table2.n_version_item))
from items table2
where table2.id_item=table1.id_item
and table1.tiers=table2.tiers)
But I'am not getting the same result. Original first query is returning fewer rows than the modified one. Note that table items has a primary key (id,version) and for each couple a tier can be affected.
When using a function , it will prevent the index to be used , so CONCAT(table1.id_item,table1.n_version_item) will not read an index unless if its Function based index. however as a_horse_with_no_name mentioned in comments you can use the below :
select itm.tiers as col1, itm.id_item as col2
from items itm
where itm.tiers is not null
and itm.tiers<>''
and (itm.id_item , itm.n_version_item)= (select
max(item_sub.id_item),max(item_sub.n_version_item)
from items item_sub
where itm.tiers=item_sub.tiers)
Then you have to check the query plan of the query what index is using ( you can start an index with column tiers and other index on id_item and n_version_item )
I think you want:
select i.tiers as col1, i.id_item as col2
from items i
where i.tiers is not null and -- redundant, but I'm leaving it in
i.tiers <> ''
(id_item, n_version_item) = (select i2.id_item, max(i2.n_version_item)
from items i2
where i2.tiers = i.tiers
order by i2.id_item desc, i2.n_version_item desc
limit 1
);
For this version, you want an index on items(tiers, id_item, n_version_item).
If you hide a column inside a 'function' (CONCAT, DATE, etc, etc), no index can be used to help performance. This eliminates your second version from consideration.
Related to that is the use of "Row Constructors" (see a_horse_with_no_name's Comment). They have historically been poorly optimized; avoid them. I am referring to WHERE (a,b) IN ( (1,2), ...) or other variants.
Now, let's dissect
and table1.id_item = (select max(table2.id_item)
from items table2
where table1.tiers=table2.tiers)
table2 needs INDEX(tiers, id_item) in that order. With such, the subquery is very fast. The other subquery needs INDEX(id_item, n_version_item) Those feed into the rest:
and table1.id_item = <<value>>
Now let's look at the whole
where (table1.tiers is not null)
and table1.tiers<>''
and table1.id_item = <<value>>
and table1.n_version_item = <<value>>
= is easy to optimize; the others are not. So let's build
INDEX(id_item, n_version_item, -- in either order
tiers) -- last
By using the order I specified, you can avoid also needing INDEX(id_item, n_version_item) that was mentioned above.
(It would help if you provided SHOW CREATE TABLE; I need to know what the PK is, and some other things.)
As a bonus, these indexes will be "covering indexes".
As a final note (a minor one):
where (table1.tiers is not null)
and table1.tiers<>''
It would be better to decide on only one encoding (NULL vs empty string) to whatever you are indicating by such.

MySQL query to get fields from a table where the ID exists in another query

This must be fairly straight forward, as I tend to use ORMs I don't have to get my hands dirty often and am therefore struggling!
I have a database and want to get several fields from a table, that bit is easy..
SELECT main_table.registration_number, main_table.registered_name FROM main_table;
I want to filter the results based on another table, which is also easy..
SELECT second_table.registration_number FROM second_table WHERE this_field = '' AND that_field = '0';
Now the problem is I want to run the first query based on the second queries result set, I was thinking something like this:
SELECT main_table.registration_number, main_table.registered_name FROM main_table WHERE main_table.registration_number IN (SELECT * FROM second_table WHERE this_field = '' AND that_field = '0');
This gives me: Error Code: 1241. Operand should contain 1 column(s)
Am I handling this completely wrong?
Your subquery should do something like below,
(select * from table) in subquery is not what you really need to do your
so the subquery should return one column
(SELECT registration_number FROM second_table WHERE this_field = '' AND that_field = '0');
You cannot have multiple columns being returned in a subquery like
that, doing so it will result in such error
You have to select a column
SELECT main_table.registration_number, main_table.registered_name FROM
main_table WHERE main_table.registration_number IN (SELECT
registration_number FROM second_table WHERE this_field = '' AND
that_field = '0');

why using IN (or NOT IN) clause in a query makes it really slow

I have a query:
SELECT DISTINCT field1 FROM table1 WHERE field2 = something
(table1 contains 1 million records, execution time:0.106sec, returns: 20 records)
Another query
SELECT DISTINCT similarField1 FROM table2 WHERE similarField2 = somethingElse
(table2 contains half million records, execution time:0.078sec, returns: 20 records)
Now if I run a query, by combining above both:
SELECT DISTINCT field1 FROM table1 WHERE field2 = something AND field1 NOT IN (SELECT DISTINCT similarField1 FROM table2 WHERE similarField2 = somethingElse)
It does't give result even running for 10mins. Why it has became dramatically slow, and what could be a potential solution.
edit: I am using MySQL with dbvisualizer 6.5
You don't need to use DISTINCT on the sub-query. Try to use NOT EXISTS which probably is more efficient in SQL-Server:
SELECT DISTINCT field1
FROM table1
WHERE field2 = #something
AND NOT EXISTS
(
SELECT 1 FROM table2
WHERE table2.similarfield1 = table1.field2
AND table2.similarfield2 = #somethingelse
)
Edit: Since you have updated the tags, i'm not sure if this is more efficient in MySql. However, i'd prefer NOT EXISTS anyway since it also works with NULL values(if you use IS NULL) and is easier to read and to maintain.
my query and advice are similar to #TimSchmelter.
In fact you should not use distinct at all. First you should remove distinct and check if you are getting duplicate records you have just ask part of your problem.Table design are not clear.
You should post your complete problem and query here without any hesitant. Also don't forget to apply index on feild2, feild1,similarField1,similarField2.
SELECT DISTINCT field1
FROM table1 tbl1
WHERE field2 = something
AND NOT EXISTS (
SELECT similarField1
FROM table2 tbl2
WHERE tbl1.field1 = tbl2.similarField1
AND similarField2 = somethingElse
)

Writing a correlated sub-query in my select query

I have a funky query that works fine with static data but I need my data to be dynamic. So the static data is like this
SELECT c.my_name, c.my_id, (SELECT count(d.friendship_id) FROM another_table d WHERE d.my_id = 1 AND d.my_friends_id = 2) as count FROM myprofile c WHERE c.my_id = 1;
This returns the data I want like this:
my_name my_id count
parijat 123 1 (OR 0 if the row doesn't exist)
For reference, both another_table.my_id (foreign key), another_table.my_friends_id references myprofile.my_id (primary key). another_table.friendship_id is the primary key here and is auto incremented.
Now the actual question:
I want my subquery to be something like this:
(SELECT count(d.friendship_id) FROM another_table d WHERE d.my_id = 1 AND d.my_friends_id = CURRENT_ROW_ID)
where CURRENT_ROW_MY_ID is the c.my_id that is being selected upon in the main query.
Is this possible and if not, what should my approach be to get the results I need ?
You can do a subquery to get the current auto_increment value for that table:
select auto_increment from information_schema.tables where table_schema = 'you_db_name' and table_name = 'your_table_name'
HTH
Francisco
Sometimes I ask before I have completely explored the option. Just found out that a correlated subquery works fine even in select statements. Here is what I did to get it working:
SELECT c.my_name, c.my_id, (SELECT count(d.friendship_id) FROM another_table d WHERE d.my_id = 1 AND d.my_friends_id = c.my_id) as count FROM myprofile c WHERE c.my_id = 1;
my_id is slightly ambiguous. A better word for it would be profile_id, however dealing with a legacy database ain't fun for sure.

selecting data from 2 tables where multiple columns and rows intersect with 'X'

its tricky to explain what i am trying to do so here goes
I have 2 tables derived from a single excel spreadsheet. the spreadsheet defines causes and effects.It has 3 points of reference so i cant make it into 1 table
this spreadsheet has a list of events down the left and effects accross the top. these are associated with each other by inserting an X in the row/column matching the event to the effect. So the intersecting columns/rows form a matrix. So for eg an event could be. 'turn on lightswitch'. follow this row along untill 'X' is found. then follow column up to effects and it shows 'light turns on' (its a little more complicated than that in reality) there can be multiple effects defined by X's in the same row
My idea was in the where statement to use table1.* and table2.* but I was looking for a wildcard to search rows/columns but after research this is not possible in mysql. Using OR for all the furter row/column combinations wont work because it just shows everything with an X in
I am a bit stumped how to query the X row/column part of the table so only the 'example' result part of the query is displayed after searching all the X's A single query below is successful but i need to search table1.1-60 table2.2-61 for occurrances of 'X' by only changeing the '%example%' part of the query in a webpage mysql/php type form and then displaying the results on another page
any suggestions/alternatives welcome thanks
SELECT
table1.equipment,
table1.tagno,
table2.equipment,
table2.action,
table2.service,
table2.tagno
FROM
table1 ,
table2
WHERE
table1.tagno LIKE '%example%' AND
table1.1 = 'X' AND
table2.2 = 'X'
There is no natural way to join column N from table1 with column N+1 in table2; you'll have to specify the joins "by hand" (or in a program, both of which will be ugly).
You want:
select * from table1 t1, table2 t2
where t1.tagno like '%example%' AND t1.1 ='X' and t2.2 = 'X'
UNION
select * from table1 t1, table2 t2
where t1.tagno like '%example%' AND t1.2 ='X' and t2.3 = 'X'
UNION
-- ...
This could be very inefficient. As suggested in the comments, remodelling the data would give you cleaner queries and a happier future.
To give more insight into my suggestion, I would re-model the data like so:
CREATE TABLE effects (
id INT,
name VARCHAR(100)
);
CREATE TABLE events (
id INT,
name VARCHAR(100)
);
CREATE TABLE effects_events (
effect_id INT,
event_id INT
);
effects_events is a Junction Table
So you could query it like this:
SELECT * FROM events WHERE events.id = effects_events.event_id AND effects_events.effect_id = effects.id AND effects.name = 'light turns on';
Or:
SELECT * FROM effects WHERE effects.id = effects_events.effect_id AND effects_events.event_id = events.id AND events.name = 'turn on lightswitch';
I might be misunderstanding something in your question but this seems like the most straightforward solution to me.