I have a MySql table called Person, and one day I accidentally deleted someone from this table. I have a backup table, called PersonBak so I was going to restore my deletion from the backup. However, in the course of moving forward on my application I renamed all the fields in Person, except for the primary key, PersonID. Now Person and PersonBak have the same data, but only one matching column name.
Is there any way to restore my missing person to Person from PersonBak without doing a lot of work? I have quite a few columns. Of course I could just do the work now, but I can imagine this coming up again.
Is there some way to tell MySql that these are really the same table, with the columns in the same order, just different column names? Or any way at all to do this without writing out specifics of which columns in PersonBak match which ones in Person?
If the column datatypes are the same between the tables, the column count is the same, and they are all in the same order, then MySQL will do all of the work for you:
INSERT INTO t1 SELECT * FROM t2;
The column names are ignored. The server uses ordinal position only, to decide how to line up the from/to columns.
What about this:
insert into Person(id, col11, col12) (select id, col21, col22 from personBak where id=5)
person schema:
columns (id, col11, col12)
personBak schema:
columns (id, col21, col22)
Look at Mysql SELECT INTO and you can specify the field names & create an insert statement
Related
I have 5 tables, each with 10+ columns. They all share some similar columns but each table has columns unique to themselves. The tables are not related to each other, meaning that one record in one table won't be able to exist in another table. Therefore, when I try to concatenate them using UNION ALL, I get a very complicated MySQL statement since the tables have so many columns. For example, I have 2 tables:
Table1: ID, Name, Parts, Comments, End_Date
Table2: ID, Name, Machines, End_Date
If I were to combine these two tables, I would use the MySQL statement
SELECT
ID,
Name,
Parts,
'' as Machines,
Comments,
End_Date
FROM Table1
UNION ALL
SELECT
ID,
Name,
'' as Parts,
Machines,
'' as Comments,
End_Date
FROM Table2
As you can see, the statement gets much larger the more columns and more tables there are. Is there an elegant way to concatenate these tables in a more concise statement? Thanks!
For combining tables, you can use the FOREIGN KEY method from SQL that will work in MySQL. To do this, outside of the creation of your table:
ALTER TABLE Table1
ADD FOREIGN KEY (End_Date) REFERENCES Table2(End_Date);
To do this inside the creation of your table, you would just code it in after your primary key and use the bit that includes FOREIGN KEY and everything after except the ' ; '. This method will only work with one column from each table though.
For extra help that you could research if you so choose to, this website has the basic methods of all SQL languages and is extremely helpful:
SQL Tutorials
I have a table (People) with columns (id, name, year). Is there any way I can get all the ids ( SELECT id FROM people ) and use them for creating new rows in other table (people_id, additional_info). I mean that for every id in table People I want to add new row in other table containing the id and some additional information. Maybe something like for-loop is needed here ?
Well, usually you have information on a person and write one record with this information. It makes litte sense to write empty records for all persons. Moreover, when it's just one record per person, why not simply add an information column to the people table?
Anyway, you can create mock records thus:
insert into people_info (people_id, additional_info)
select id, null from people;
Insert into targetTable (id, additional_info)
select id,'additionalinfo' from PEOPLE
No for loop is needed, Just use the above query.
You can use INSERT ... SELECT syntax for MySQL to insert the rows into people_info table (documentation here).
e.g.
insert into people_info(...)
select (...) from people; <and posibly other tables>
I have a table with a field (Name) I'd like to create a unique index on, however it seems there are existing duplicates. I dont' want to just get rid of dupes since some might have information in other fields that I need. Essentially I have:
ID
ParentID
Name
Code
RelatedID
So Goal 1 is I want to keep the record that has values in the secondary fields other then ID and Name. In most cases this will be one of the dupes only.
Goal 2 is in case two identical Names both have values but in different fields I want to 'merge' those since it is remotely possible one duplicate will have values in one key field and one in the other.
Finally Goal 3 is in the case that two names both have values in a key field I'd probably want to manually review those first.
It seems to me my first step as I read this would be Goal 3; manually review duplicates where Name Field is identical, and more then one record has a non-Null/non-empty value in a key field.
Once I address this the goal would be to 'mere' the remaining records i.e keep one record with Name and any non-null/non-empty key fields from the others.
Any thoughts much appreciated.
Sounds like a solid plan - hope you have a development environment you can dry run it in.
Here is some code that may help you along
Starting with Step 3.
This statement should help you find which records need to be reviewed.
SELECT *
FROM (
SELECT name,
GROUP_CONCAT(DISTINCT parentID) AS parentID,
GROUP_CONCAT(DISTINCT code) AS code,
GROUP_CONCAT(DISTINCT RelatedID) AS RelatedID,
FROM foo
GROUP BY name
HAVING COUNT(*)>1) as summarized
WHERE parentID LIKE '%,%'
OR code LIKE '%,%'
OR RelatedID LIKE '%,%';
Anything that comes up in that query you will probably have to manually fix after figuring out why there are multiple values for the same field.
Once those fixes are in place, it's times for the merge. I would create a holding / temporary table with the correct values. MAX should take care of the logic to choose non-null values
CREATE TABLE foo_values
SELECT name, MAX(parentID) as parentID, MAX(code) AS code, MAX(RelatedID) AS RelatedID.
FROM foo
GROUP BY name
HAVING COUNT(*)>1;
In theory, now you have the merged values. You can remove the duplicate name rows using whatever technique you are most comfortable with(See here) while adding your unique index. Finally, update the secondary fields by JOINing back to foo values.
(MySQL) I am trying to migrate a "subscription" table into 3 new tables: "product", "subscription", "actual" where "actual" is the name of the actual product, say, newsletter. The subscription has a FK reference to product and the actual has FK reference into subscription.
I know the INSERT INTO SELECT statement can copy data probably from many table to one; is there a statement to do the opposite, one to many tables for my case?
I'm not aware of an SQL statement that will do what you want. Just do several INSERT INTO SELECTs one after the other. It may be faster to do them one at a time anyway.
I think you can use three seperate insert into select statements. First you convert the product table, then the subscription where you can use an embedded select to find the id in the product table:
insert into subscription (some_column, FK_id,...)
select something, (select id from product where <your where clause>),...
and finally convert the actual table using an embedded select to get the id from the subscription table.
I'm using MySQL 4.1. Some tables have duplicates entries that go against the constraints.
When I try to group rows, MySQL doesn't recognise the rows as being similar.
Example:
Table A has a column "Name" with the Unique proprety.
The table contains one row with the name 'Hach?' and one row with the same name but a square at the end instead of the '?' (which I can't reproduce in this textfield)
A "Group by" on these 2 rows return 2 separate rows
This cause several problems including the fact that I can't export and reimport the database. On reimporting an error mentions that a Insert has failed because it violates a constraint.
In theory I could try to import, wait for the first error, fix the import script and the original DB, and repeat. In pratice, that would take forever.
Is there a way to list all the anomalies or force the database to recheck constraints (and list all the values/rows that go against them) ?
I can supply the .MYD file if it can be helpful.
To list all the anomalies:
SELECT name, count(*) FROM TableA GROUP BY name HAVING count(*) > 1;
There are a few ways to tackle deleting the dups and your path will depend heavily on the number of dups you have.
See this SO question for ways of removing those from your table.
Here is the solution I provided there:
-- Setup for example
create table people (fname varchar(10), lname varchar(10));
insert into people values ('Bob', 'Newhart');
insert into people values ('Bob', 'Newhart');
insert into people values ('Bill', 'Cosby');
insert into people values ('Jim', 'Gaffigan');
insert into people values ('Jim', 'Gaffigan');
insert into people values ('Adam', 'Sandler');
-- Show table with duplicates
select * from people;
-- Create table with one version of each duplicate record
create table dups as
select distinct fname, lname, count(*)
from people group by fname, lname
having count(*) > 1;
-- Delete all matching duplicate records
delete people from people inner join dups
on people.fname = dups.fname AND
people.lname = dups.lname;
-- Insert single record of each dup back into table
insert into people select fname, lname from dups;
-- Show Fixed table
select * from people;
Create a new table, select all rows and group by the unique key (in the example column name) and insert in the new table.
To find out what is that character, do the following query:
SELECT HEX(Name) FROM TableName WHERE Name LIKE 'Hach%'
You will se the ascii code of that 'square'.
If that character is 'x', you could update like this:(but if that column is Unique you will have some errors)
UPDATE TableName SET Name=TRIM(TRAILING 'x' FROM Name);
I'll assume this is a MySQL 4.1 random bug. Somes values are just changing on their own for no particular reason even if they violates some MySQL constraints. MySQL is simply ignoring those violations.
To solve my problem, I will write a prog that tries to resinsert every line of data in the same table (to be precise : another table with the same caracteristics) and log every instance of failures.
I will leave the incident open for a while in case someone gets the same problem and someone else finds a more practical solution.