MySQL insert on duplicate update multiple conditions - mysql

I have the following table "texts"
+---------+-------------+-------------+-----------+--------------------+
| txt_id | txt_lang_id | txt_section | txt_code | txt_value |
+---------+-------------+-------------+-----------+--------------------+
| 1 | 1 | home | txt_title | Home |
| 2 | 1 | home | txt_btn | I'm a button |
| 3 | 1 | home | txt_welc | Welcome to home |
etc...
I have multiple databases, one for each company, and a master database where the texts are created, besides, in each company, the administrator can customize your texts.
My idea is to create a query that inserts the new texts created in each database, and if it already exists to update the value.
It is possible to make the query INSERT INTO ... ON DUPLICATE KEY UPDATE Have several conditions like txt_lang_id = 1 AND txt_section = 'home' AND txt_code = 'txt_title' SET txt_value = 'New home'
My idea is to be that way, because the same function would use it for other tables, such as configuration, which is a table that starts empty, and is populated as the administrator of company changes the default options, so the auto id is not always in the same order for all companies.
It is possible to do something like this, or rather I look for the way that the rows are always in the same order. Thanks.

You can use UPDATE with CASE, e.g.:
INSERT INTO ... ON DUPLICATE KEY UPDATE txt_value =
(CASE WHEN txt_lang_id = 1 AND txt_section = 'home'
AND txt_code = 'txt_title' THEN 'New home' else txt_value end);
Here's the SQL Fiddle.

Related

SQL: Find value in Column A and update Column B with another value

I have a database with a few columns. Some of the values gets populated in the database but not all.
I want to search a value in one column and update another column with a certain value.
My TABLE (name = "heroes") looks like this:
-----------------------------------------------
| id | name | last_name | hero_id | status |
-----------------------------------------------
| 1 | John | Snow | 3245625 | |
| 2 | Tyrion | Lannister | 7687296 | Alive |
-----------------------------------------------
I want to search the database for the 'hero_id' (which is unique) and UPDATE the 'status' column.
The search part I can do:
SELECT idnumber, status FROM heroes WHERE idnumber=3245625
How do I go about updating the "status" column with a certain value e.g. "Alive" or "Deceased"?
H,
try this one:
UPDATE heroes
SET STATUS = "Alive"
WHERE idnumber=3245625;
Cheers
Para
update heroes set status = 'alive' where id = 12354

MySQL Moving table from varchar to int

I am moving an old Mantis table that had a varchar(64) category_id column to a new Mantis table that has a int(10) category_id column.
The simplified structure is as follows
bug_table (Old DB)
+----+-------------+-------------+--------+
| id | project_id | category_id | report |
+----+-------------+-------------+--------+
| 1 | 0 | Server | crash |
| 2 | 0 | Database | error |
| 3 | 1 | Server | bug |
| 4 | 1 | Server | crash |
+----+-------------+-------------+--------+
category_table (New DB)
+----+------------+----------+
| id | project_id | name |
+----+------------+----------+
| 0 | 1 | Server |
| 1 | 1 | Database |
| 2 | 2 | Server |
| 3 | 2 | Database |
+----+------------+----------+
I need a magical query that will replace category_id in the bug_table with the numerical category_id in the category_table. Thankfully I am able to match rows by project_id and categories by name.
Here is the query I am working on but have gotten stuck in the complexity
UPDATE bug_table b SET b.category_id = c.id USING category_table WHERE b.category_id = c.name
I like to approach such a task a little differently than you do for a new lookup/reference table.
To me, the new category table would only have id and name columns. There are only two rows based on the sample data: Server and Database. Yes, I realize there could be other names, but those can easily be added, and should be added, before proceeding to maximize the id matching that follows.
Next I would add a new column to the bug table that could be called 'category_new' with the data type that will store the new category id. Alternatively, you could rename the existing category_id column to category, and the new column for the id's could then be column_id.
After all that is done then you can update the new column by joining the category on names and set the id that matches: (note this assumes the non-alternative approach mentioned in step 2)
UPDATE bug_table JOIN category_table ON bug_table.category_id = category_table.name
SET bug_table.category_new = category_table.id
After that runs, check the new column to verify the updated id's.
Finally, after successful update, now the old category_id column (with the names) from the bugs_table can be dropped, and the category_new column can be renamed as the category_id.
=====
Note that if you decide to go with the alternative column approach mentioned, of course the query will be similar but differ slightly. Then only a column drop is needed at the end
If there are other tables to apply the same category changes, the operation (basically steps 2 through 5) would be similar for those tables too.

how to change data in db from string to id - Rails, Mysql

Hello I have maybe easy problem maybe not...
History: I wanted to replace yaml file with statuses to db(mysql) and i had in user table column: status. When i replacing logic to db i have created model Status, created table and configured relationship with user...
Describe problem: When i created status_id in user table i have 2 columns: "status" and "status_id". The column "status" is string and have a lot of string value for example "confirmed". How to (using seed migration with statuses) and fill the "status_id" column. I mean if "status" column have value "confirmed" i'd like to have in "status_id" column value: 1.
statuses table:
id name
1 confirmed
2 not confirmed
3 something else
Users table
id status status_id
1 confirmed empty
2 confirmed empty
3 confirmed empty
4 not confirmed empty
5 not confirmed empty
6 something else empty
7 something else empty
User belongs_to :status
Status has_many :users
question: Why i didnt just change name and type in "status" column on
"status_id" with data type: "id"?
answer: Because i need to deploy it using capistrano to production
server and i cant losing data and remove data from status column.
Given the following (your) sample data:
create table statuses (id int, name char(20));
insert into statuses (id, name) values
(1, 'confirmed'),
(2, 'not confirmed'),
(3, 'something else');
create table users (id int, status char(20), status_id int);
insert into users (id, status) values
(1,'confirmed'),
(2,'confirmed'),
(3,'confirmed'),
(4,'not confirmed'),
(5,'not confirmed'),
(6,'something else'),
(7,'something else');
select * from users;
+------+----------------+-----------+
| id | status | status_id |
+------+----------------+-----------+
| 1 | confirmed | NULL |
| 2 | confirmed | NULL |
| 3 | confirmed | NULL |
| 4 | not confirmed | NULL |
| 5 | not confirmed | NULL |
| 6 | something else | NULL |
| 7 | something else | NULL |
+------+----------------+-----------+
7 rows in set (0.00 sec)
This update statement updates the status_id column in users with the appropriate values from statuses:
update users u
set u.status_id=(select s.id from statuses s where u.status=s.name);
Query OK, 7 rows affected (0.01 sec)
Rows matched: 7 Changed: 7 Warnings: 0
select * from users;
+------+----------------+-----------+
| id | status | status_id |
+------+----------------+-----------+
| 1 | confirmed | 1 |
| 2 | confirmed | 1 |
| 3 | confirmed | 1 |
| 4 | not confirmed | 2 |
| 5 | not confirmed | 2 |
| 6 | something else | 3 |
| 7 | something else | 3 |
+------+----------------+-----------+
7 rows in set (0.00 sec)
Hope this is what you asked for, because my answer does neither involve ruby, yaml, nor rails.
This sounds like a one-off data migration which can be handled in several different ways. One way is to write a one-off script or rake task which will update all the users.
some_task.rake
desc 'Add status id to existing users'
namespace :users do
task assign_status: :environment do
statuses = {}
Status.all.each {|status| statuses[status.name] = status.id}
User.all.each do |user|
user.update_attribute(status_id: statuses[user.status])
end
end
end
If you have a lot of users, you may want to use find_each which is more performant as it uses batching. You may also want to add some kind of progress reporting in the rake task.
This approach allows you to test the task against a copy of your existing database.

MySQL: Finding existences between values in database and array

I'd like to know how can I make a unique query to find which values exist and which values do not. I explain.
What I have
I've got a database table with a structure as follows:
+----+--------+-----------+-----------+
| id | action | button_id | type |
+----+--------+-----------+-----------+
| 1 | 1 | 1 | button |
| 2 | 2 | 4 | button |
| 3 | 1 | 2 | attribute |
+----+--------+-----------+-----------+
As you can see, an action can have multiple button_id values. For your knowledge, a button_id can be assigned to multiple action, too, but a button_id can only have a type for an action.
So, button_id 1 can be also present in action 4 with the type "attribute" set to it, but it cannot be duplicated to the same action with another type.
The problem
The problem comes when I want to update the buttons in an action. I receive an action object with an array of the buttons it have (in PHP) with the structure below (I write it in JSON structure):
"buttons":
[
{
"id":"1",
"type":"button"
},
{
"id":"3",
"type":"attribute"
}
]
As you can see, the button with ID 1 remains the same, but I've got a new button to deal with (the button with ID 3) and the button with ID 2 is not present anymore.
What I'd want
I'd want to be able to make a unique MySQL query that returns me which values from those I receive exists and which do not, and which may be present in the database but not in that array.
To sum up: I want to know the differences between the buttons in the array received and those present in the database.
So, as an example with the received data described before and the database as we have it right now, I expect to receive something like this:
+--------+-----------+--------+------------+
| action | button_id | exists | is_present |
+--------+-----------+--------+------------+
| 1 | 1 | 1 | 1 |
| 1 | 2 | 1 | 0 |
| 1 | 3 | 0 | 1 |
+--------+-----------+--------+------------+
With this information, I'd be able to know that button with ID 2 does not exist anymore (because it's not present in the new array) and button with ID 3 is a new button because it does not exists previously but it's present in the new array.
What I've tried
There are some tests I've tried, but none of them gives me what I need, and not only tested with MySQL pure queries.
For example, I've tried to check the existence for each button I receive but that would leave me without being able to find if a button is deleted (so it's not present in the received array).
Checking that but taking as reference the buttons in the database has the same effect, as I will be able to check which have been updated or deleted, but it would skip those that are new and not present in the database.
I've tried to write some queries making COUNT queries and GROUP BY button_id, and so, but no luck neither.
(I won't write the queries because none of them have given me the expected results, so they won't be of any help for you).
Any combination of those explained before I think will be much slower than doing it purely by database queries, and that's why I'm asking for it.
The question
Is there a query that would return to me something like the response explained before in "What I'd want" section, so it would make only a call to the MySQL server?
Thank you all for your time, your responses and your patience for any lack of information you may find by my part.
Of course, any doubts, questions you have or information you may need, comment it and I'll try to explain it better or to add it.
Kind regards.
To do that in a single query would be very cubersome. Here is a solution that is not exactly what you are looking for but should do the job.
Let's say your table looks like this :
CREATE TABLE htmlComponent
(
id int auto_increment primary key,
action int,
button_id int not null,
type varchar(20),
dtInserted datetime,
dtUpdated datetime
);
CREATE UNIQUE INDEX buttonType ON htmlComponent(button_id, type);
Now we need to update the table according to the buttons / atributes you have for a specific action.
-- Reset dtInserted and dtUpdated for action 1
UPDATE htmlComponent SET dtInserted = null, dtUpdated = null WHERE action=1;
-- INSERT or UPDATE according to the data inside the json structure
INSERT INTO htmlComponent (action, button_id, type, dtInserted)
VALUES
(1, 1, 'button', NOW()),
(1, 3, 'attribute', NOW())
ON DUPLICATE KEY UPDATE
button_id = VALUES(button_id),
type = VALUES(type),
dtInserted = null,
dtUpdated = NOW();
-- Getting the result
SELECT * FROM htmlComponent where action=1;
Your should end up with this result which will make it easy to figure out what doesn't exists anymore, what is new and what was updated.
+----+--------+-----------+-----------+----------------------------+----------------------------+
| ID | ACTION | BUTTON_ID | TYPE | DTINSERTED | DTUPDATED |
+----+--------+-----------+-----------+----------------------------+----------------------------+
| 1 | 1 | 1 | button | (null) | February, 09 2015 16:21:49 |
| 3 | 1 | 2 | attribute | (null) | (null) |
| 4 | 1 | 3 | attribute | February, 09 2015 16:21:49 | (null) |
+----+--------+-----------+-----------+----------------------------+----------------------------+
Here is a fiddle. Please note I had to put the UPDATE and the INSERT in the left panel because DML are not allowed in the query panel.

Updating read/unread table upon post insertion

I'm trying to create a separate table that would track read/unread posts. Using MySQLi I will have two tables items and items_tracking. When the page is rendered it will join the the tables and check if the user read the posts or not.
items
+-------+------------+----+
| id | created_by | .. |
+-------+------------+----+
| item1 | id12 | .. |
| item2 | id433 | .. |
+-------+------------+----+
items_tracking
+---------+---------+------+
| user_id | item_id | read |
+---------+---------+------+
| id1 | item1 | 0 |
| id2 | item2 | 0 |
| id94 | item1 | 1 |
+---------+---------+------+
Now the idea was that whenever a new item/post is created in the items table, it will also create rows in the items_tracking table for all users and with column read = 0. Problem is, I have no idea how to work around this since the foreign key I would use in items_tracking is still pretty much undetermined.
Any ideas on how to approach inserting in both tables at the same time, while the second table references the first?
You don't need records with read=0 in the tracking table.
SELECT ..., t.read FROM items i LEFT JOIN items_tracking t ON (t.item_id = i.id)
This query will work even if there is no corresponding record in items_tracking; in this case, t.read in the result will be NULL. You only need to insert the records with read = 1, although you don't need even this flag, you test for t.item_id IS NOT NULL to see if you have a record in items_tracking.