Remaping numbers in table all at once - mysql

I was converting a database structure to a different one. There's this problem with ID's. The items used to reference to each other with ID - but these ID's must change because the new structure is different.
So you have a table (this is an example):
| id | ref |
+----+-----+
| 1 | 3 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
Now let's say that in new table, the refference id's must change like this:
| old | new |
+-----+-----+
| 1 | 2 |
| 2 | 1 |
| 3 | 4 |
| 4 | 3 |
See what happens if you subsequently UPDATE to replace old ref with new ones:
Replacing: 1=>2 Replacing: 2=>1 This is what we need at the end:
well, damn
| id | ref | | id | ref | | id | ref |
+----+-----+ +----+-----+ +----+-----+
| 1 | 3 | | 1 | 3 | | 1 | 4 |
| 2 | *2* | | 2 | 2 | | 2 | 2 |
| 3 | *2* | | 3 | 2 | | 2 | 2 |
| 4 | 2 | | 4 | *2* | | 2 | 1 |
So I need to replace it at one time. How can I do this?

Since the criteria don't matter, this will do the trick. The core of the solution is: update all rows in one go.
update YourTable
set ref =
case ref
when 1 then 2
when 2 then 1
when 3 then 4
when 4 then 3
end
If that is not possible:
add a new column 'newref'
update 'newref' in any way you want to contain the new ids
update the 'ref' column with the values from 'newref'
drop the 'newref'

This update all in one instruction
UPDATE t1 a
INNER JOIN t2 b
ON a.ref=b.old
SET a.ref=b.new;
Result
select * from t1
id ref
1 4
2 2
3 2
4 1
http://sqlfiddle.com/#!2/ab49c/1
Schema and data sample
create table t1 (id int, ref int);
create table t2 (old int, new int);
insert t1 values(1,3);
insert t1 values(2,1);
insert t1 values(3,1);
insert t1 values(4,2);
insert t2 values(1,2);
insert t2 values(2,1);
insert t2 values(3,4);
insert t2 values(4,3);

Related

SQL (MYSQL, Postgres) Lookup/report table

I'm basically making a lookup table for my three tables but its not doing what I want. Those 3 tables were created by loading 3 different csv files.
What I'm trying to do is inserting the ID's from those tables into the lookup one.
This is what I keep getting:
---------------Lookuptable---------------
|lookup_ID|Table1_ID|Table2_ID|Table3_ID|
| 1 | 1 | | |
| 2 | 2 | | |
| 3 | 3 | | |
| | | 1 | |
| | | 2 | |
| | | 3 | |
| | | | 1 |
| | | | 2 |
| | | | 3 |
What I need is:
---------------Lookuptable---------------
|lookup_ID|Table1_ID|Table2_ID|Table3_ID |
| 1 | 1 | 1 | 1 |
| 2 | 2 | 2 | 2 |
| 3 | 3 | 3 | 3 |
I kind of get why this is happening, it inserts one row bellow every time with single inserts like
insert into Lookuptable(Table1_ID) select T1id from Table1;
and the others...
But I've tried nested ones too like
insert into Lookuptable(Table1_ID, Table2_ID, Table3_ID)
select Table1.T1id, Table2.T2id, Table2.T2id from Table1, Table2, Table3;
but still doesn't work. In fact this one just crashes the Mysql server and has an endless query on Postgres. I've tried other nested examples but none worked.
I'm also using Foreign Keys which work when I manually input a new value, but since the other tables come from loaded CSV files I have to input the values already there manually.
I'm really not sure what to do.
If I understand correctly what you want something like this should work
https://www.db-fiddle.com/f/k6CGsVXazSqJDfwKkdr6S7/1
SET #i:=0,#j:=0,#h:=0;
INSERT INTO Lookuptable
SELECT NULL,t1.ID,t2.ID,t3.ID FROM
( SELECT #i:=(#i+1) AS temp_id,ID FROM Table1 ) t1
INNER JOIN
( SELECT #j:=(#j+1) AS temp_id ,ID FROM Table2 ) t2 ON t1.temp_id=t2.temp_id
INNER JOIN
( SELECT #h:=(#h+1) AS temp_id ,ID FROM Table3 ) t3 ON t2.temp_id=t3.temp_id;

How to insert a specify row in mysql?

Suppose I have a table t1 like
mysql> select * from t1;
+------+-------+------+
| id | level | gap |
+------+-------+------+
| 1 | 6 | 50 |
| 1 | 5 | 10 |
| 2 | 5 | 12 |
| 2 | 5 | 10 |
| 3 | 8 | 4 |
| 3 | 9 | 1 |
| 3 | 9 | 3 |
| 3 | 7 | 2 |
+------+-------+------+
I want to insert a row (3,6,7) into here.I mean it is below in first 5 row.
Is it possible in mysql?
Just do
INSERT INTO t1 (id, level,gap) VALUES (3,6,7)
Records in a table do not have a prescribed order. The order has to be defined during a SELECT by supplying a suitable ORDER BY clause.
So, if you want the new record to be listed in 5th position use ORDER BY id, level.

mysql: merge multiple rows into one

I have two tables: state_current and state_snapshots. state_current contains exactly 4 rows, the current values for 4 different keys:
+-----+-------+
| key | value |
+-----+-------+
| A | 1 |
| B | 2 |
| C | 3 |
| D | 4 |
+-----+-------+
Now, I want to add a row to state_snapshots that contains the values of each key in a seperate column:
+---+---+---+---+
| A | B | C | D |
+---+---+---+---+
| 1 | 2 | 3 | 4 |
| 1 | 2 | 3 | 5 |
| 1 | 2 | 4 | 5 |
...
+---+---+---+---+
Of course, the keys never change in state_current, only the values. What mySQL-query will create a row with the value of A in state_current in the first column, the value of B in state_current in the second and so on?
I'm new to mySQL, so thanks in advance for any help!
The simplest answer I can think about is:
insert into state_snapshots(a,b,c,d)
values ( (select value from state_current where key='A'),
(select value from state_current where key='B'),
(select value from state_current where key='C'),
(select value from state_current where key='D')
);

MySql Update Row and it's "Descendants"

I'm having trouble figuring out how to update the descendants/children of a row.
Example table, named test
+----+--------+------+
| Id | Parent | Val |
+----+--------+------+
| 1 | 0 | |
| 2 | 1 | |
| 3 | 1 | |
| 4 | 1 | |
| 5 | 0 | |
| 6 | 5 | |
| 7 | 6 | |
| 8 | 6 | |
| 9 | 0 | |
+----+--------+------+
What I'd like to have done is, when Val is set to something, update every row that is related to that row. For example, If I ran
UPDATE test SET Val=1 WHERE Id=5;
I want Val in the rows where the Id is 6, 7, and 8, to also be 1.
The best thing I could come up with was
UPDATE test t1
JOIN test t2 ON t1.Id = t2.Parent
JOIN test t3 ON t2.Id = t3.Parent
SET t1.Val=1, t2.Val=1, t3.Val=1 WHERE t1.Id=5;
+----+--------+------+
| Id | Parent | Val |
+----+--------+------+
| 1 | 0 | |
| 2 | 1 | |
| 3 | 1 | |
| 4 | 1 | |
| 5 | 0 | 1 |
| 6 | 5 | 1 |
| 7 | 6 | 1 |
| 8 | 6 | 1 |
| 9 | 0 | |
+----+--------+------+
This gives me what I want, but I'm afraid it's poor practice and it doesn't account for a variable depth. What can I do here? I thought a trigger may have been the answer, but that didn't seem to be possible. I got the error "Can't update table in stored function/trigger because it is already used by statement which invoked this stored function/trigger"
It's pretty awkward to handle this kind of case with MySQL, because MySQL doesn't support recursive queries.
I solve this problem by storing the hierarchy as a transitive closure, instead of the "parent_id" style you're using. See my answer to What is the most efficient/elegant way to parse a flat table into a tree?
Then you can update all descendants of a given node in the heirarchy:
UPDATE test JOIN testclosure AS c ON test.id = c.descendant
SET test.val = 1
WHERE c.ancestor = 5;

What does this MySQL statement do?

INSERT IGNORE INTO `PREFIX_tab_lang` (`id_tab`, `id_lang`, `name`)
(SELECT `id_tab`, id_lang, (SELECT tl.`name`
FROM `PREFIX_tab_lang` tl
WHERE tl.`id_lang` = (SELECT c.`value`
FROM `PREFIX_configuration` c
WHERE c.`name` = 'PS_LANG_DEFAULT' LIMIT 1) AND tl.`id_tab`=`PREFIX_tab`.`id_tab`)
FROM `PREFIX_lang` CROSS JOIN `PREFIX_tab`);
It's from an opensource project,and no documentation available.
Especially,what does cross-join mean? I've only used join/left join .
According to the MySQL documentation, it's basically a synonym for INNER JOIN, and INNER JOIN is the same as just JOIN (that is, "INNER" is the default).
Cross-join: http://en.wikipedia.org/wiki/Join_%28SQL%29#Cross_join
The query inserts into PREFIX_tab_lang the results of a select. The select is just two columns from the cross-product. The third column -- name -- actually comes from a totally different select, which is also pretty straight-forward except that one of it's where conditions is yet another select.
In short, this is one of the worst queries I've ever seen. It's preformance is probably horrible, and it should be replaced by a bit of TRANSATION-protected code or, at the very least, a stored procedure.
You can actually consider the following queries to be synonyms in MySQL:
SELECT *
FROM Table1
CROSS JOIN Table2;
SELECT *
FROM Table1, Table2;
SELECT *
FROM Table1
INNER JOIN Table2;
SELECT *
FROM Table1
JOIN Table2;
Test Case:
CREATE TABLE Table1 (id int, value varchar(10));
CREATE TABLE Table2 (id int, t1_id int);
INSERT INTO Table1 VALUES (1, 'Value 1');
INSERT INTO Table1 VALUES (2, 'Value 2');
INSERT INTO Table1 VALUES (3, 'Value 3');
INSERT INTO Table1 VALUES (4, 'Value 4');
INSERT INTO Table2 VALUES (1, 1);
INSERT INTO Table2 VALUES (2, 1);
INSERT INTO Table2 VALUES (3, 2);
INSERT INTO Table2 VALUES (4, 2);
INSERT INTO Table2 VALUES (5, 2);
INSERT INTO Table2 VALUES (6, 3);
INSERT INTO Table2 VALUES (7, 4);
INSERT INTO Table2 VALUES (8, 4);
INSERT INTO Table2 VALUES (9, 4);
All four queries would return the following result set:
+------+---------+------+-------+
| id | value | id | t1_id |
+------+---------+------+-------+
| 1 | Value 1 | 1 | 1 |
| 2 | Value 2 | 1 | 1 |
| 3 | Value 3 | 1 | 1 |
| 4 | Value 4 | 1 | 1 |
| 1 | Value 1 | 2 | 1 |
| 2 | Value 2 | 2 | 1 |
| 3 | Value 3 | 2 | 1 |
| 4 | Value 4 | 2 | 1 |
| 1 | Value 1 | 3 | 2 |
| 2 | Value 2 | 3 | 2 |
| 3 | Value 3 | 3 | 2 |
| 4 | Value 4 | 3 | 2 |
| 1 | Value 1 | 4 | 2 |
| 2 | Value 2 | 4 | 2 |
| 3 | Value 3 | 4 | 2 |
| 4 | Value 4 | 4 | 2 |
| 1 | Value 1 | 5 | 2 |
| 2 | Value 2 | 5 | 2 |
| 3 | Value 3 | 5 | 2 |
| 4 | Value 4 | 5 | 2 |
| 1 | Value 1 | 6 | 3 |
| 2 | Value 2 | 6 | 3 |
| 3 | Value 3 | 6 | 3 |
| 4 | Value 4 | 6 | 3 |
| 1 | Value 1 | 7 | 4 |
| 2 | Value 2 | 7 | 4 |
| 3 | Value 3 | 7 | 4 |
| 4 | Value 4 | 7 | 4 |
| 1 | Value 1 | 8 | 4 |
| 2 | Value 2 | 8 | 4 |
| 3 | Value 3 | 8 | 4 |
| 4 | Value 4 | 8 | 4 |
| 1 | Value 1 | 9 | 4 |
| 2 | Value 2 | 9 | 4 |
| 3 | Value 3 | 9 | 4 |
| 4 | Value 4 | 9 | 4 |
+------+---------+------+-------+
36 rows in set (0.01 sec)