Merging two tables with a relationship - mysql

I am building upon an existing database with a relationship construction I've seen nowhere before.
I have three tables:
legend1
legid INT(11), AUTO_INCREMENT, PRIMARY
description VARCHAR(255)
legend2
legid INT(11), AUTO_INCREMENT, PRIMARY
description VARCHAR(255)
items
id INT(11), AUTO_INCREMENT, PRIMARY
name VARCHAR(255)
legid INT(11)
legend VARCHAR(8)
Every record in items relates to data in either legend1 or legend2.
The field items.legend determines wich one it is. I want to get rid of this construction as legend1 and legend2 have an identical structure. The only thing different is the content.
I want to have this construction:
legend
legid INT(11), AUTO_INCREMENT, PRIMARY
description VARCHAR(255)
items
id INT(11), AUTO_INCREMENT, PRIMARY
name VARCHAR(255)
legid INT(11)
The problem is that the tables are full and no data may be lost. The id of both tables starts on 1 so almost every primary key will collide.
I have this query:
INSERT INTO legend1 (description) SELECT description FROM legend2;
This query doesn't work because it messes up referenced id's from legend2.

After you have executed your insert query:
INSERT INTO legend1 (description) SELECT description FROM legend2;
Perform the following query
UPDATE items SET legid = (SELECT legid FROM legend1 WHERE legend1.description = items.description) WHERE legend ='something to define that it is from the legend2 table'
Note that I haven't tried the query out but the solution is somewhat like this. If you pick out the syntax errors I've made I'm sure it will work.
What it does is the following:
After you insert your entire legend2 table into the legend1 table you update your items table to set the corresponding legendid

Related

Generate unique key for users with same email-address

We have a table with orders of customers like:
CREATE TABLE `orders` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`number` varchar(20) NOT NULL,
`ordered` datetime DEFAULT NULL,
`email` varchar(255) NOT NULL,
...
);
The table is already filled with data. I need to add a field:
`user` int(10) unsigned NOT NULL,
which contains a unique number for each customer. A customer is defined by the same email-address, so all orders with the email 'test#example.com' should get a 1, with 'something_else#example.com' should get a 2 and so on.
For this 'user'-number it doesn't matter if it starts with 1 or is somehow incrementing, it just should be different for every email-address.
Is there a way to do this in one SQL-statement? I know how to do it with some php-code for example, but we where curious if it's possible just with SQL. We know it would be a better design if there was a table "customer", but it's not our design, we just trying to fix the worst things ;)
It's not possible to do what you describe in one SQL statement.
Even if you didn't care to make the user id unique per email, your ALTER TABLE wouldn't work. You show adding a column that is NOT NULL but has no DEFAULT. So what value is it supposed to add to the table, given that the table has rows in it? It can't use NULL, and it has no DEFAULT value. You can't add the column as an AUTO_INCREMENT because you already have an id column that is AUTO_INCREMENT, and MySQL doesn't allow a table to have two such columns.
Here's the way I'd do it:
CREATE TABLE customers (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(255) NOT NULL
);
INSERT INTO customers (email)
SELECT DISTINCT email FROM orders;
ALTER TABLE orders ADD COLUMN user_id INT UNSIGNED; -- this allows NULLs until we fill it
UPDATE orders JOIN customers USING (email)
SET orders.user_id = customers.id;
Before the next step, make sure that it has populated orders.user_id the way you think is correct. Once you drop the orders.email column, there's no undo. It would be a good idea to make a backup first.
ALTER TABLE orders DROP COLUMN email,
MODIFY COLUMN user_ID INT UNSIGNED NOT NULL; -- disallow NULLs from now on

How to insert data into a table with a foreign key

I'm currently having issues with inserting values into a database table that uses a foreign key from another table to align the is together. The tables are pretty simple. One holds information about a project, and the other hold values for the project images. Here they are in detail.
The projects table
project_id int(50) PRIMARY KEY NOT NULL AUTO_INCREMENT,
project_name varchar(50) NOT NULL,
project_permitted timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT "The date that the project took place.",
project_in varchar(50) NOT NULL COMMENT 'The place where the project took place (ie the city and state).',
project_type varchar(50) NOT NULL COMMENT 'The project type (ie residentual, commercial, etc).',
project_description longtext,
project_published timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
Here is the second table called project_images
image_id int(50) PRIMARY KEY NOT NULL AUTO_INCREMENT,
project_id int(50),
image_url varchar(50) NOT NULL,
CONSTRAINT fk_projects FOREIGN KEY (project_id) REFERENCES projects(project_id)
What I am trying to do is insert values into the second table using the project_id from the projects table using a subquery. That query looks like this:
insert into project_images (project_id, project_url, project_description)
values (
(select project_id from projects where project_name = 'The Venue'),
"images/theVenue.png",
"The Venue: an appartment complex in Austin, Texas."
)
With this query I keep getting an error that says
something to the effect of "You are missing a comma or closing bracket
near project_id.
Can anyone help or point out the best way to handle this situation.
Modify your query to be like
insert into project_images (project_id, project_url, project_description)
select project_id ,
"images/theVenue.png",
"The Venue: an appartment complex in Austin, Texas."
from projects where project_name = 'The Venue';
After looking into this question a bit more, it seems that you cannot use a subquery the way I am using it to get the value of a column, However, the column can be inserted directly so long as the foreign key points to a primary key from another table that has already be inserted. The whole point to using this query was for a PHP project, so I guess I'll just do a select query in a project to get its ID then add that to the sql that queries the project_images table. This seems to be the only way to do that.

use ON DUPLICATE KEY for table that have two primary key

I have a table with 2 primary keys(user_id,post_id)
I want to insert row only if table havn't a row with this user id and post id
And if previous data exist for this keys , only that row update with the new data
I wrote this query:
INSERT INTO trust_list(`user_id`,`post_id`,`post_per`,`comment_per`,`cat_per`)
VALUES (7,1,'000','000','000')
ON DUPLICATE KEY UPDATE `post_per`='000',`comment_per`='000',`cat_per`='000'
For example if this row exist in the table:
user_id:5
post_id:1
post_per:001
comment_per:111
cat_per:101
Then ,when i execute the above query , mysql update this row,only because post_id of this row is "1"
Whereas mysql should not update this row .
I don't understand what's the problem.
DESC trust_list
result of above query is:
Field Type Null Key Default Extra
user_id int(11) NO PRI NULL
post_id int(4) NO PRI NULL
post_per tinytext YES NULL
comment_per tinytext YES NULL
cat_per tinytext YES NULL
=================
Thanks to all of my friends
When i decide to drop table and ceate it again ,I get an export from this table
and review the .sql file,i see this:
CREATE TABLE IF NOT EXISTS `trust_list` (
`user_id` int(11) NOT NULL,
`post_id` int(11) NOT NULL,
`post_per` tinytext COLLATE utf8_estonian_ci ,
`comment_per` tinytext COLLATE utf8_estonian_ci ,
`cat_per` tinytext COLLATE utf8_estonian_ci ,
PRIMARY KEY (`idea_id`,`user_id`),
UNIQUE KEY `idea_id` (`idea_id`)
)
apparently , problem is from the UNIQUE KEY ,I remove it from file ,and then drop trust_list table ,and then import .sql file
So with this ,my problem solved
Thanks again
There is something wrong with your table schema.
Assuming that your schema defined something like this
CREATE TABLE trust_list(
`user_id` int,
`post_id` int,
`post_per` varchar(12),
`comment_per` varchar(12),
`cat_per`varchar(12),
PRIMARY KEY(`user_id`, `post_id`)
);
here is SQLFiddle that demonstrates that your INSERT statement works on it just fine.
Consider to show your CREATE TABLE statement to help you find the problem, or just change PK as showed.
I think your problem is your understanding of primary key. You can't have two primary keys in the table, only one. What you have probably is a primary key that consists of two columns. In that case you only get a key violation when both columns match.
Solution:
Introduce unique indices for both columns. Or - better - change the primary key to be only one of the two columns and set the other column to have a unique index.
Thanks to peterem here is the sqlfiddle with my solution.

Triggers and multi-column Primary Keys

I have a books table and a music table. Both of these tables have a Product_ID as their primary key. I also have a products table that has a Product_ID column and a type column (0 for books, 1 for music) where the Product_Id and Type columns are the primary key for the table. In phpMyAdmin, these 2 columns are underlined and SHOW COLUMNS for the table shows Type and Product_Id marked as primary keys.
The problem I'm having is with my trigger. There are 2 triggers, with a couple of differences to handle the different tables. The music trigger for example executes this statement:
INSERT INTO products
SET
Type=1,
Product_Id=NEW.Product_ID,
Title=NEW.Album,
Price=0
The books trigger is the same, except type=0 and NEW.Album is replaced with NEW.Title. When I'm running an INSERT query now though, after some data has been inserted and deleted, I'm getting a duplicate primary key error. The problem is that the MySQL database is only reading the Product_ID column as a primary key, so when its trying to insert a duplicate there, it spits out this error even though it the value in the Type column is different. I'm stumped here.
The products table
Product_Id int(11) - PK
Title int(11)
Price double
Type int(11) - PK
NewBool tinyint(1)
The music Table
Product_ID int(11) - PK
Artist varchar(32)
Album varchar(32)
Genre varchar(32)
Year int(11)
Length double
Rating double
NumRatings int(11)
Studio varchar(64)
The books table
Product_ID int(11) - PK
ISBN bigint(20)
Title text
Author text
Year int(11)
Genre text
Pages int(11)
Publisher text
Edition int(11)
Rating double
NumRatings int(11)
It looks like you have forgot a trigger that deletes rows in Products. If you ever update the data in Books or Music you also need a trigger that makes the corresponding change in Products.
Here is your problem now
http://sqlfiddle.com/#!2/be9c93/1
Here is how I've fixed it
http://sqlfiddle.com/#!2/2ff27/2

create relationship between tables

I have tables for dogs, cats , horses containing rows of information about them , i want to create a table photo where info about photos of each can be created and so want to establish one-to-many relation b/w name attribute of each table with table photo . I am using name attribute in each table and it is set to unique but not primary , i want a way to join them so that for each name if there are multiple entries in photo table they could be shown.
I strongly recommend you use an int primary key rather than name for linking your tables.
If you need to change the name of any animal, the links effectively break.
Simple example:
CREATE TABLE `animals` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(32) DEFAULT NULL,
`species` varchar(32) DEFAULT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `images` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`animal_id` int(10) NOT NULL,
`image_url` varchar(1024) DEFAULT NULL,
PRIMARY KEY (`id`)
);
You also might do well to create a third table for species and make that a link rather than a text field.
The idea is ease of management and future-proofing.
A query to get data for a specific animal and all its images would be like this:
SELECT a.name, a.species, i.image_url
FROM animals a
LEFT JOIN images i ON (i.animal_id = a.id)
WHERE a.id = 123;
name species image_url
----- ----- -----
Fido dog images/fido1.jpg
Fido dog images/fido2.jpg
Other queries are possible, but this scheme allows you to have animals with the same name and they won't conflict.