MySQL - compare two tables and generate a diff SQL file - mysql

In my database, I have a default table (named "mytable") that I download from the internet. The table has say 100 rows and 10 columns (fields).
I am changing some values in the table but I'm not deleting nor inserting any rows or columns.
Say, in the fifth row of the table, I change the value of field "Name" from "Fox" to "Bear".
Then I download the table again from the internet, and I add it to the database with a different name.
So now I have the tables "oldtable" (containing the default values) and "mytable", where only a field in one row is changed.
Now, I want to show to others what I changed in the database and to give them the SQL script that they can run so they apply the same changes. I can't give them my own "mytable" because they can't use it. They also have it and they changed some values in it, as they see fit. They don't want my table, they just want to apply the changes that I made, on top of the changes that they already made to the table.
So I can give them this file named "patch.sql":
connect myDatabase;
update mytable set name="Bear" where name like "Fox";
However, I would like to create such a "patch.sql" file automatically, so I don't have to remember what I have changed and write the script manually. A program can check the differences between the two tables and generate that SQL file automatically.
Is it possible to do that in MySQL console or with any other existing tool?
Update: the table has a primary key.

if You edit with colleagues different rows, script could be easy.
But if You think You can edit same rows, but different columns, it look like next:
You have 2 tables
table_1:
id, col1, col2, col3
1 10 50 1
2 10 60 9
3 12 50 3
4 12 60 4
5 11 70 5
table_2:
id, col1, col2, col3
1 20 50 1
2 30 60 2
3 12 60 3
4 12 60 5
5 15 77 22
and run this script:
SELECT CONCAT('UPDATE table_1 SET '
, CASE WHEN t1.col1 != t2.col1 THEN CONCAT(' col1 = ', t2.col1) ELSE '' END
, CASE WHEN t1.col1 != t2.col1 AND t1.col2 != t2.col2 THEN ', ' ELSE ''END
, CASE WHEN t1.col2 != t2.col2 THEN CONCAT(' col2 = ', t2.col2) ELSE '' END
, CASE WHEN t1.col3 != t2.col3 AND (t1.col2 != t2.col2 OR t1.col1 != t2.col1) THEN ', ' ELSE ''END
, CASE WHEN t1.col3 != t2.col3 THEN CONCAT(' col3 = ', t2.col3) ELSE '' END
, CONCAT(' WHERE id = ', t1.id)) as update_txt
FROM table_1 t1 JOIN table_2 t2 ON t1.id = t2.id WHERE t1.col1 != t2.col1 OR t1.col2 != t2.col2 OR t1.col3 != t2.col3
Your result will be:
UPDATE table_1 SET col1 = 20 WHERE id = 1
UPDATE table_1 SET col1 = 30, col3 = 2 WHERE id = 2
UPDATE table_1 SET col2 = 60 WHERE id = 3
UPDATE table_1 SET col3 = 5 WHERE id = 4
UPDATE table_1 SET col1 = 15, col2 = 77, col3 = 22 WHERE id = 5
Then You need just copy result column to text file and send to other parts.
This is work for UPDATE, if You plan INSERT / DELETE rows, script will be more complicated, but use the same logic

Related

SQL - Return all unique pairs of values from one column, for each value in another column

Suppose the table looks like
col1 col2
---- ----
1 a
2 a
3 a
4 b
5 b
6 b
and I want to get all pairs from col1 for each value in col2, meaning the result should look like:
col1a col1b col2
---- ----- ----
1 2 a
1 3 a
2 3 a
4 5 b
4 6 b
5 6 b
I have tried to use
temp1 cross join temp2 where temp1.col1 < temp2.col1 order by temp1.col1, temp2.col1
as part of the full query, but it's not returning all the possible combinations. Also I'm not sure how I should write the "for each" part of the command, as in "for each value in col2, create all pairs from the value in col1". Any guidance will be much appreciated.
Maybe this is what you are looking for?
select t1.col1 as col1a, t2.col1 as col1b, t1.col2
from t as t1
join t as t2 on t1.col2 = t2.col2
where t1.col1 < t2.col1
A sample SQL Fiddle gives the same output as your example.

How to fetch changed rows by comparing a table with its older version?

I have one log table and one view.
I would like to fetch the changed rows from the view by comparing it to the log table given an ID_NO.
The ID_NO is fixed between the two tables, whereas other columns can change.
In short, I would like to fetch the rows from Table1 which have one more changed columns in comparison to Table2.
for example:
TABLE 1:
ID COL1 COL2 COL3
1 A B C
2 34 56 D
3 F XY 24
TABLE 2:
ID COL1 COL2 COL3
1 A B C
2 34 56 F
3 1 XY 24
The query should return the following from TABLE2:
ID COL1 COL2 COL3
2 34 56 F
3 1 XY 24
Please advise.
Many Thanks!
SELECT *
FROM one_view vw
WHERE EXISTS
(
SELECT 1
FROM log_table t
WHERE vw.id_no = t.id_no
)
;
A note after the question was updated:
SELECT *
FROM table_2 t1
WHERE EXISTS
(
SELECT 1
FROM table_1 t2
WHERE t1.id_no = t2.id_no
AND
(
t1.col1 <> t2.col1
OR t1.col2 <> t2.col2
OR t1.col3 <> t2.col3
)
)
;
you could add a trigger to the changing table that inserts the id in a second table that is used to identify the changed rows from the changing table. Just comparing the values between tables might work but requires a lot of work. Getting the id's of the changed rows might be easier.
Just in case you also want to have the old values, add the changed colums and values to the logging table.

How to update value in same table using mysql?

I need to replace/update values in my table according att_id for each customer_id.
The table looks like:
ID att_id customer_id value
1 5 1 name
2 30 1 12345
3 40 1
4 5 2 name2
5 30 2 12345
6 40 2
I'd like to replace it like this:
ID att_id customer_id value
1 5 1 name
2 30 1
3 40 1 12345
4 5 2 name2
5 30 2
6 40 2 12345
UPDATE: Based on your comments ...I need to find values for attribute 30, check if they are mobile phone numbers, and if it's true, write it itno value for attribute 40... your query might look like this
UPDATE table1 t1 JOIN table1 t2
ON t1.customer_id = t2.customer_id
AND t1.att_id = 40
AND t2.att_id = 30
SET t1.value = t2.value
-- ,t2.value = NULL -- uncomment if you need to clear values in att_id = 30 at the same time
WHERE t2.value REGEXP '^[+]?[0-9]+$'
You might need to tweak a regexp to match your records ("mobile phone numbers") properly
Here is SQLFiddle demo
It's hard to tell for sure from your description but if you need to swap values of att_id 30 and 40 per customer_id you may do something like this
UPDATE table1 t1 JOIN table1 t2
ON t1.customer_id = t2.customer_id
AND t1.att_id = 40
AND t2.att_id = 30
SET t1.value = t2.value,
t2.value = t1.value
Here is SQLFiddle demo
or if you need to put values of att_id = 30 to att_id = 40 and "clear" values of att_id = 30
UPDATE table1 t1 JOIN table1 t2
ON t1.customer_id = t2.customer_id
AND t1.att_id = 40
AND t2.att_id = 30
SET t1.value = t2.value,
t2.value = NULL
Here is SQLFiddle demo
Here is a general approach for swapping the values on rows with att_id equal to 30 and 40:
update t join
t t30
on t.customer_Id = t30.customer_Id and t30.att_id = 30 join
t t40
on t.customer_Id = t40.customer_Id and t40.att_id = 40 join
set t.value = (case when att_id = 30 then t40.value
when att_id = 40 then t30.value
else t.value
end)
where att_id in (30, 40);
First, you remove the value of att_id = 30
UPDATE tablename SET value="" WHERE att_id=30;
Then set the value for att_id=40
UPDATE tablename SET value="12345" WHERE att_id=40;
UPDATE tableName SET value=12345 WHERE ID=2;
UPDATE tableName SET value="" WHERE ID=3;
UPDATE tableName SET value=12345 WHERE ID=6;
UPDATE tableName SET value="" WHERE ID=5;
This are the command .See http://www.tutorialspoint.com/mysql/mysql-update-query.htm for tutorial on update.

MYSQL insert into first empty column

I have a tbl, for example:
uniqueId | col1 | col2 | col3
u1 8
u2
u3 13 89
What I want is to insert into the first empty column (can make them null if that helps). In the given if I'll add to u1 the value 2 it will be inserted into col2. If I do it for u2, it will enter col1. and for u3 it will enter to u3. These three queries will do the trick but I would rather do it in one.
INSERT INTO tbl SET col1 = $toInsertVal WHERE uniqueId=u col1=''
INSERT INTO tbl SET col2 = $toInsertVal WHERE uniqueId=u col1<>'' AND col2=''
INSERT INTO tbl SET col3 = $toInsertVal WHERE uniqueId=u col1<>'' AND col2<>'' AND col3=''
insert into tbl set
col1 = case when col1 = '' then $toInsertVal else col1 end
, col2 = case when col2 = '' and col1 <> '' then $toInsertVal else col2 end
...
where uniqueid = u
I've ignored NULLs for the sake of simplicity. Basically you can use a CASE on each column, checking on the first empty column and setting its value to its current value if no change is required.

Joined results as column names

I have this Mysql scenario
table1
--------------
id `7` `8`
--------------
1 10 20
2 20 30
table 2
---------------
id code rel
---------------
3 7 1
4 8 2
I am using following statement to get values
SELECT t2.id, t2.code,
CASE t2.code WHEN 7 THEN (SELECT `7` FROM table1 t1 where t1.id = t2.rel)
CASE t2.code WHEN 8 THEN (SELECT `8` FROM table1 t1 where t1.id = t2.rel)
END as val
FROM table2 t2
but it's neither pretty or functional, because I need these values summed, multiplied, etc, and there are a lot of columns.
Is there a way to join these tables and get table1.7 value for t2.rel,t2.code values?
Something similar to
SELECT t2.id, t2.code, eval(t1.(t2.code)) as val
FROM table2 t2
JOIN table1 t1 on t2.rel = t1.id
Thank you very much!
Every column referenced in an SQL query must be fixed at the time you prepare the query. There's no such thing as eval.
However you can use a data value to drive a CASE statement:
SELECT t2.id, t2.code,
CASE t2.code WHEN '7' THEN t1.`7` WHEN '8' THEN t1.`8` END AS `val`
FROM table2 t2
JOIN table1 t1 ON t2.rel = t1.id;
But you'd have to hard-code all the cases before you prepare the query. There's no way for SQL to generate the expressions during execution time as it finds new code values on successive rows of data.
I don't know if it is still relevant.
As you alredy know, there is no such thing as pivot in MySql, but aggregations might look rather easy if the number of columns is defined:
SELECT
SUM(IF(t2.code = 7, `7`, NULL)) as sum7,
AVG(IF(t2.code=8, `8`, NULL)) as avg8
FROM t1 JOIN t2
ON t1.id = t2.rel;
Ok I'm curious if it is possible what your trying to do but this might be a solution for now.
Do a select like this:
SELECT t2.id, t2.code, t1.*
FROM table2 t2
JOIN table1 t1 on t2.rel = t1.id
Resulting in
|| *id* || *code* || *id* || *7* || *8* ||
------------------------------------------
|| 3 || 7 || 1 || 10 || 20 ||
|| 4 || 8 || 2 || 20 || 30 ||
Then in your code concatenate in your result.
If your using php and your result is associative:
echo $result[$result['code']];
I don't think your going to make this happen in a query. You might want to rethink your database design.