Many UPDATE WHERE in one SQL - mysql

I have a database with very bad architecture and no one wants to fix anything and i have to work with what i have. So the problem is in the screen
I need to update users connections and also some more fields... The solution which i see is SET ... WHERE AND SET .. WHERE AND SET ... WHERE (and yes, at this point i'm not even sure that it would work). So may be there is more common way to solve this problem?

As long as your values are different records I think you will need to make individual updates.
You could also consider something like this:
UPDATE categories
SET display_order = CASE id
WHEN 1 THEN 3
WHEN 2 THEN 4
WHEN 3 THEN 5
END,
title = CASE id
WHEN 1 THEN 'New Title 1'
WHEN 2 THEN 'New Title 2'
WHEN 3 THEN 'New Title 3'
END
WHERE id IN (1,2,3)

Is there a special reason why you should be updating all the fields in one single query. Why not try writing individual update queries and push it to database as a batch.

Related

MySQL search and remove some text in a field

I have to update 2 fields in a table, assuming I have the following data:
Date CategoryID
2019-04-19 1,92,10
2019-04-18 4,105,10
2019-04-17 3,106,7,78
2019-04-16 3,108,10
I have to update CategoryID and remove the following category numbers if there is/are in row: 106, 107, 108 and 92
So the result will be:
Date CategoryID
2019-04-19 1,10
2019-04-18 4,105,10
2019-04-17 3,7,78
2019-04-16 3,10
Normally I use the REPLACE function, but in this case I don't know how to use it to remove that category and keep the others.
Could someone drive me?
Thank you, Lucas
EDIT: REGEXP_REPLACE from #Joakim Danielson did the trick. Thank you to all people who partecipate/reply, however, to all those who have criticized, this is not my code, it's Datalife Engine Blog :)
I use REGEXP_REPLACE with two similar patterns but with the comma , before and after to support the numbers being first, last or somewhere in the. middle
UPDATE test
SET categoryID = REGEXP_REPLACE(categoryID, '((106|107|108|92)([,]{1}))|(([,]{1})(106|107|108|92))', '')
This query is somewhat limited since it will replace both 106 and 1060 for instance. Is this a problem or is the id's limited in range so this is good enough?
Since I assume this is more of a one time thing you could divide it into 3 different updates to make sure you only get exact hits
-- id in the middle
UPDATE test
SET categoryID = REGEXP_REPLACE(categoryID, ',(106|107|108|92),', ',')
-- id at the start
UPDATE test
SET categoryID = REGEXP_REPLACE(categoryID, '^(106|107|108|92),', '')
-- id at the end
UPDATE test
SET categoryID = REGEXP_REPLACE(categoryID, ',(106|107|108|92)$', '')
you could use multiple replace calls, i.e. first run queries for for each number with a comma after it. I.e. this replaces 107, with empty string.
Then run queries for each number as single entry. I.e. replace 107 with empty string.
In both cases be aware of partial matches. So if you replace 97 with empty string it will also change id 197 to 1. Or when replacing 97, with empty string you might turn 197,4 into 14.
That is a horrible schema, at least for use in a relational database.
However, for getting what you asked for, see if this will work:
UPDATE thetable
SET CategoryID = "1,10"
WHERE Date = "2019-04-19"
To make this work, the sql query will have to be generated by a programming language which inspects strings and has some other way to figure out which row to update.
REGEXP_REPLACE from #Joakim Danielson did the trick. Thank you to all people who partecipate/reply, however, to all those who have criticized, this is not my code, it's Datalife Engine Blog :)

Combining multiple queries into a single query

I have code that I've written in an ORM syntax. It reads blog comments data from a file, and inserts them into blogs and comments tables. I'd like to take this ORM code back to mysql, because I need to combine as many queries as possible into a single query, and this optimization wouldn't be easy in the ORM language. The reason I need this optimization is because I'm working with a remote server, so the fewer the queries, the better. I wrote the code below in mysql pseudo-code, because I somewhat forgot mysql.
This is the comments file that contains all the comments for all the blogs. from blog url tells me which blog this comment belongs to.
comment text from blog url
------------------------------------------
first comment text first-blog-url
second comment text first-blog-url
third comment text first-blog-url
fourth comment text blog-2-url
fifth comment text blog-2-url
sixth comment text 3rd-blog-url
This is the ORM code that I use to process the file. (at the very bottom, I added the description of the tables).
//I read a comment from the comments file, `comment text` and `from blog url`
//does a blog exist that has 'link' that matches 'from blog url'
$blog = //SELECT FROM blogs where 'link' has value 'first-blog-url'
//if it doesn't exist, create it
if($blog == null){
$blog = INSERT INTO blogs a new record and set 'link' to 'first-blog-url'
}
//then read the id of the (existing or just-created) blog row
$blog_id = $blog->getId();
//then use the $blog_id to insert the comment into the 'comments' table.
//does this comment text already exist for this blog id?
$comment = SELECT FROM comments where `commenttext' has value 'whatever comment text' and 'blogid' has value $blog_id
//if it doesn't exist, create it
if($comment == null){
$comment = INSERT INTO comments a new record and set 'commenttext' to 'the comment text' and 'blogid' to $blog_id.
}
$comment_id = $comment->getId();
So my question: is it possible to write this in a single mysql query?
I found a similar question here but it doesn't fully solve my problem, and I'm not sure if it's the most efficient way to do it.
The 2 tables are blogs and comments where each row in comments has a field blogid that links it to the right blog in blogs. So it's basically a 1:many relationship where each blog row can be linked to many comment rows. They look like this:
blogs:
id link other fields
--------------------------------------------
1 first-blog-url
2 blog-2-url
3 3rd-blog-url
comments:
id commenttext blogid
-----------------------------
1 random 1
2 comment 1
3 goes 1
4 here 2
5 any 2
6 thing 3
You can use this technique to insert a row if not exists:
INSERT INTO blogs (link)
select 'first-blog-url'
from dual
where not exists
( select 1
from blogs
where link = 'first-blog-url'
);
As you can see, select clause will return a only one row with data to be inserted only when not yet exists in database. You can test it at SQLFIDDLE.
To insert into comment table you can use same technique. You can get Blog id for second query with LAST_INSERT_ID() if inserted is dued (if not, you need a new query).
This is only a point to start, perhaps you can reduce to 3 your 4 queries. Any comment are welcome to figure up final solution.
As you know, MySQL don't has MERGE statement. I think that replace don't match your requeriments.

DBIx::Class update only one row

I am using DBIx::Class and I would like to only update one row in my table. Currently this is how I do it:
my $session = my_app->model("DB::Session")->find(1);
$session->update({done_yn=>'y',end_time=>\'NOW()'});
It works, but the problem is that when it does find to find the row, it does this whole query:
SELECT me.id, me.project_id, me.user_id, me.start_time, me.end_time, me.notes, me.done_yn FROM sessions me WHERE ( me.id = ? ): '8'
Which seems a bit much when all I want to do is update a row. Is there anyway to update a row without having to pull the whole row out of the database first? Something like this is what I am looking for:
my_app->model("DB::Session")->update({done_yn=>'y',end_time=>\'NOW()'},{id=>$id});
Where $id is the WHERE id=? part of the query. Does anyone know how to do this? Thanks!
You can run update on a restricted resultset which only matches this single row:
my_app->model("DB::Session")->search_rs({ id=> 1 })->update({done_yn=>'y',end_time=>\'NOW()'});
I suggest you use a DateTime->now object instead of literal SQL for updating the end_time column because it uses the apps servers date and time instead of the database servers and makes your schema more compatible with different RDBMSes.
Do you have a check if the row was found to prevent an error in case it wasn't?
You might want to use update_or_create instead.
You could use the "columns" attribute:
my $session = my_app->model("DB::Session")->find(1, {columns => "id"});

Update multiple mysql rows with 1 query?

I am porting client DB to new one with different post titles and rows ID's , but he wants to keep the hits from old website,
he has over 500 articles in new DB , and updating one is not an issue with this query
UPDATE blog_posts
SET hits=8523 WHERE title LIKE '%slim charger%' AND category = 2
but how would I go by doing this for all 500 articles with 1 query ? I already have export query from old db with post title and hits so we could find the new ones easier
INSERT INTO `news_items` (`title`, `hits`) VALUES
('Slim charger- your new friend', 8523 )...
the only reference in both tables is product name word within the title everything else is different , id , full title ...
Make a tmp table for old data in old_posts
UPDATE new_posts LEFT JOIN old_posts ON new_posts.title = old_posts.title SET new_posts.hits = old_posts.hits;
Unfortunately that's not how it works, you will have to write a script/program that does a loop.
articles cursor;
selection articlesTable%rowtype;
WHILE(FETCH(cursor into selection)%hasNext)
Insert into newTable selection;
END WHILE
How you bridge it is up to you, but that's the basic pseudo code/PLSQL.
The APIs for selecting from one DB and putting into another vary by DBMS, so you will need a common intermediate format. Basically take the record from the first DB, stick it into a struct in the programming language of your choice, and prefrom an insert using those struct values using the APIs for the other DBMS.
I'm not 100% sure that you can update multiple records at once, but I think what you want to do is use a loop in combination with the update query.
However, if you have 2 tables with absolutely no relationship or common identifiers between them, you are kind of in a hard place. The hard place in this instance would mean you have to do them all manually :(
The last possible idea to save you is that the id's might be different, but they might still have the same order. If that is the case you can still loop through the old table and update the number table as I described above.
You can build a procedure that'll do it for you:
CREATE PROCEDURE insert_news_items()
BEGIN
DECLARE news_items_cur CURSOR FOR
SELECT title, hits
FROM blog_posts
WHERE title LIKE '%slim charger%' AND category = 2;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN news_items_cur;
LOOP
IF done THEN
LEAVE read_loop;
END IF;
FETCH news_items_cur
INTO title, hits;
INSERT INTO `news_items` (`title`, `hits`) VALUES (title, hits);
END LOOP;
CLOSE news_items_cur;
END;

How do i get this IF statement to work in MYSQL (it's in a stored procedure)?

I can't find an example anywhere that doesn't give me syntax errors
My code is
BEGIN
UPDATE Room_Descriptions
IF(STRCMP(Bed_Type,'King')) THEN SET Max_People = Number_Beds * 3
END
Basically it's supposed to go through the table and look at the column "Bed_Type", if it finds the word "King" it'll multiply that row's Number_Beds by 3 and set that in the column Max_People
I was hoping to eventually get some if elses going on but I'll settle for just one if that works.
UPDATE Room_Descriptions SET Max_People = Number_Beds*3 WHERE STRCMP(Bed_Type,'King')
All it takes is a conditional UPDATE.