mysql merge scripts to create table - mysql

I've came across an issue and I cant think of a way to solve it.
I need to insert country names in several languages into a table on my mysql db.
I found these links link1 (en) , link2 (de) etc but I dont know how to proceed in order to finally have a table looking like this:
CREATE TABLE `country` (
`id` varchar(2) NOT NULL,
`en` varchar(64) NOT NULL,
`de` varchar(64) NOT NULL,
...
...
PRIMARY KEY (`id`)
) ENGINE=MYISAM DEFAULT CHARSET=utf8;

Well, I finally figured it out so I'm posting to maybe help others.
I created 2 tables (country_en) and (country_de) and then ran the following statement:
DROP table if exists `countries`;
CREATE TABLE `countries` (
id varchar(2), el varchar(100), de varchar(100)
);
INSERT INTO `countries`
SELECT country_en.id, el, de
FROM country_en
JOIN country_de ON (country_en.id = country_de.id);
which creates the table countries and joins the other 2 tables on their common key id

I can suggest you another table design. Create languages table, and modify a little country table: add lang_id field and create foreign key - FOREIGN KEY (lang_id)
REFERENCES languages (id). Then populate languages and country tables.
For example:
CREATE TABLE languages(
id VARCHAR(2) NOT NULL,
name VARCHAR(64) NOT NULL,
PRIMARY KEY (id)
) ENGINE = INNODB;
CREATE TABLE country(
id VARCHAR(2) NOT NULL,
lang_id VARCHAR(2) NOT NULL DEFAULT '',
name VARCHAR(64) NOT NULL,
PRIMARY KEY (id, lang_id),
CONSTRAINT FK_country_languages_id FOREIGN KEY (lang_id)
REFERENCES languages (id) ON DELETE RESTRICT ON UPDATE RESTRICT
)
ENGINE = INNODB;
-- Populate languages
INSERT INTO languages VALUES
('en', 'English'),
('de', 'German');
-- Populate names from 'en' table
INSERT INTO country SELECT id, 'en', name FROM country_en;
-- Populate names from 'de' table
INSERT INTO country SELECT id, 'de', name FROM country_de;
...Where country_en and country_deare tables from your links.

Related

Query gets data from two different users when I try to get data just from just one user

I want to get data just from only one specific user but I get data from both users. Why is that? I don't understand. How can I solve this?.
I have three tables:
/*User*/
CREATE TABLE `User` (
`IDUser` INT NOT NULL AUTO_INCREMENT,
`Name` VARCHAR(50) NOT NULL,
PRIMARY KEY (`IDUser`)
);
/*Category*/
CREATE TABLE `Category` (
`IDCategory` CHAR(3) NOT NULL,
`FK_User` INT NOT NULL,
`CategoryName` VARCHAR(40) NOT NULL,
PRIMARY KEY (`IDCategory`, `FK_User`)
);
/*Product*/
CREATE TABLE `Product` (
`IDProduct` VARCHAR(18) NOT NULL,
`FK_User` INT NOT NULL,
`ProductName` VARCHAR(150) NOT NULL,
`FK_Category` CHAR(3) NOT NULL,
PRIMARY KEY (`IDProduct`, `FK_User`)
);
ALTER TABLE `Product` ADD FOREIGN KEY (`FK_User`) REFERENCES `User`(`IDUser`);
ALTER TABLE `Product` ADD FOREIGN KEY (`FK_Category`) REFERENCES `Category`(`IDCategory`);
ALTER TABLE `Category` ADD FOREIGN KEY (`FK_User`) REFERENCES `User`(`IDUser`);
insert into User(Name) values('User1');
insert into User(Name) values('User2');
insert into Category(IDCategory,FK_User,CategoryName) values('CT1',1,'Category1User1');
insert into Category(IDCategory,FK_User,CategoryName) values('CT1',2,'Category1User2');
If two different users insert both the same product with the same ID:
insert into Product values('001',1,'shoe','CT1');
insert into Product values('001',2,'shoe','CT1');
Why do I keep getting data from both users if I try a query like this one:
SELECT P.IDProduct,P.ProductName,P.FK_Category,C.CategoryName
FROM Product P inner join Category C on P.FK_Category=C.IDCategory
WHERE P.FK_User=1
this is the result I get:
You are getting two rows because both categories have the same IDCategory value which is the value you are JOINing on. You need to also JOIN on the FK_User values so that you don't also get User2's category values:
SELECT P.IDProduct,P.ProductName,P.FK_Category,C.CategoryName
FROM Product P
INNER JOIN Category C ON P.FK_Category=C.IDCategory AND P.FK_User = C.FK_User
WHERE P.FK_User=1
You need to add p.FK_User=C.Fk_User this condition in your join clause
SELECT P.IDProduct,P.ProductName,P.FK_Category,C.CategoryName
FROM Product P inner join Category C
on P.FK_Category=C.IDCategory and p.FK_User=C.Fk_User
WHERE P.FK_User=1
A PRIMARY KEY is a UNIQUE key. Shouldn't CategoryID be unique? That is, shouldn't Category have PRIMARY KEY(CategoryId)?
(Check other tables for a similar problem.)

INSERTing values into a child table referenced from parent table

I was up all last night trying to crack this but with no luck so I'm hoping you guys can help as I'm all out of ideas:
I have two parent tables that I want to populate a Junction table from:
Brides:
create table if not exists `Brides` (
`BrideID` INT not null auto_increment,
`MaidenName` varchar(10) unique,
primary key (`BrideID`)
) engine=InnoDB;
insert into Brides (MaidenName)
values ('Smith'),
('Jones')
;
Churches:
create table if not exists `Churches` (
`ChurchID` INT not null auto_increment,
`ChurchName` varchar(10) unique,
primary key (`ChurchID`)
) engine=InnoDB;
insert into Churches (ChurchName)
values ('St Marys'),
('St Albans')
;
I am trying to populate the ID variables for Junction table Marriages by indirectly referencing the unique names in each parent table. In addition, I'm looking to include MarriedName to identify if a Bride marries more than once:
Marriages:
create table if not exists 'Marriages' (
'BrideID' INT not null,
'ChurchID' INT not null,
'MarriedName' TEXT not null
primary key ('BrideID','ChurchID','MarriedName')
INDEX `fk_Marriages_Brides1_idx` (`BrideID` ASC),
INDEX `fk_Marriages_Churches1_idx` (`ChurchID` ASC),
CONSTRAINT `fk_Marriages_Brides1`
FOREIGN KEY (`BrideID`)
REFERENCES `Brides` (`BrideID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_Marriages_Churches1`
FOREIGN KEY (`Church_ID`)
REFERENCES `Churches` (`ChurchID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
;
I'm trying to do something like the below pseudo-code (although I'm pretty sure it wouldn't be the smart way to do it anyway as must be slow with with so many sub-queries):
insert into Marriages (Bride_ID, Church_ID, MarriedName)
select b.BrideID, c.ChurchID, m.MarriedName
from (values (Bride,Church,MarriedName)
('Smith','St Marys','Johnson'),
('Jones','St Albans','Peterson')
) m
join Brides b
on a.MaidenName=m.Bride
join Churches c
on m.Church=c.ChurchName;
Any help/insight/corrections you have would be greatly appreciated!
Give this a try:
INSERT INTO Marriages
SELECT b.BrideID, c.ChurchID, 'Johnson'
FROM Brides b, Churches c
WHERE b.MaidenName='Smith' AND c.ChurchName='St Marys'
Just for completeness, I wanted to share this solution in case it helps anyone else....First and last step requires no changes and just the 'raw' data in the second step needs adding to:
create table if not exists `_marriages` (
`BrideName` varchar(10) null,
`ChurchName` varchar(10) null,
`MarriedName` varchar(10) NULL,
primary key (`BrideName`,`ChurchName`,`MarriedName`))
engine=InnoDB
;
insert into `_marriages` (BrideName,ChurchName,MarriedName)
values
('Smith','St Albans','Johnson'),
('Jones','St Marys','Peterson')
;
insert into `Marriages` (Bride_ID, Church_ID, MarriedName)
select distinct b.BrideID, c.ChurchID, a.MarriedName
from _marriages a
inner join Brides b
on (a.BrideName=b.MaidenName)
left join Churches c
on a.ChurchName=c.ChurchName
;
...as always though, if anyone has any advancement on a better way to do it please let us know!

two composite keys from same table

In a MySQL database, I need to create a new closure table (called closure_new) that integrates a two column foreign key to another table, concept. This means adding rows to closure_new that are not in closure. How do I set up the SQL to accomplish this?
Here is my first attempt at the code for populating closure_new:
INSERT INTO `closure_new`
SELECT o.subtypeId, d.id, d.effectiveTime
FROM concept d
JOIN closure o
ON o.subtypeId = d.id;
Note that my first attempt only addresses subtypeId/subtype_effectiveTime and might not address it completely. The SQL also needs to incorporate supertypeId/supertype_effectiveTime. How do I write the SQL to populate the closure_new table with records for each of the effectiveTime values associated with each subtypeId and each supertypeId?
Here is the concept table:
CREATE TABLE `concept` (
`id` BIGINT NOT NULL DEFAULT 0,
`effectiveTime` VARCHAR(8) NOT NULL DEFAULT '',
`some other fields`,
PRIMARY KEY (`id`,`effectiveTime`)
) ENGINE=InnoDB;
Here is the old closure table:
CREATE TABLE `closure` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`subtypeId` BIGINT(20) NOT NULL ,
`supertypeId` BIGINT(20) NOT NULL ,
PRIMARY KEY (`id`)
);
Here is the closure_new table that needs to be populated with the script I started to write above:
CREATE TABLE `closure_new` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`subtypeId` BIGINT(20) NOT NULL ,
`subtype_effectiveTime` VARCHAR(8) NOT NULL DEFAULT '',
`supertypeId` BIGINT(20) NOT NULL ,
`supertype_effectiveTime` VARCHAR(8) NOT NULL DEFAULT '',
FOREIGN KEY (`supertypeId`, `supertype_effectiveTime`) references concept(`id`, `effectiveTime`),
FOREIGN KEY (`subtypeId`, `subtype_effectiveTime`) references concept(`id`, `effectiveTime`)
); ENGINE=InnoDB;
Try this:
insert into closure_new
(subtypeId, subtype_effectiveTime, supertypeId, supertype_effectiveTime)
select cl.id, co.effectiveTime, co.id, co.effectiveTime from closure cl inner join concept co
Your data better match or you will have some foreign key constraint issues
Not sure if I completely understand what you're after, but how about:
INSERT INTO `closure_new` (subtypeId, subtype_effectiveTime, supertypeId, supertype_effectiveTime)
SELECT subCon.id, subCon.effectiveTime, superCon.id, superCOn.effectiveTimed.effectiveTime
FROM closure o, concept subCon, concept superCon
where subcon.Id = o.subtypeId and supercon.Id = o.supertypeId
Or possibly, you could just create view with that select statement.

MySQL using IN/FIND_IN_SET to read multiple rows in sub query

I have two tables, locations and location groups
CREATE TABLE locations (
location_id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(63) UNIQUE NOT NULL
);
INSERT INTO locations (name)
VALUES
('london'),
('bristol'),
('exeter');
CREATE TABLE location_groups (
location_group_id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
location_ids VARCHAR(255) NOT NULL,
user_ids VARCHAR(255) NOT NULL,
name VARCHAR(63) NOT NULL,
);
INSERT INTO location_groups (location_ids, user_ids, name)
VALUES
('1', '1,2,4', 'south east'),
('2,3', '2', 'south west');
What I am trying to do is return all location_ids for all of the location_groups where the given user_id exists. I'm using CSV to store the location_ids and user_ids in the location_groups table. I know this isn't normalised, but this is how the database is and it's out of my control.
My current query is:
SELECT location_id
FROM locations
WHERE FIND_IN_SET(location_id,
(SELECT location_ids
FROM location_groups
WHERE FIND_IN_SET(2,location_groups.user_ids)) )
Now this works fine if the user_id = 1 for example (as only 1 location_group row is returned), but if i search for user_id = 2, i get an error saying the sub query returns more than 1 row, which is expected as user 2 is in 2 location_groups. I understand why the error is being thrown, i'm trying to work out how to solve it.
To clarify when searching for user_id 1 in location_groups.user_ids the location_id 1 should be returned. When searching for user_id 2 the location_ids 1,2,3 should be returned.
I know this is a complicated query so if anything isn't clear just let me know. Any help would be appreciated! Thank you.
You could use GROUP_CONCAT to combine the location_ids in the subquery.
SELECT location_id
FROM locations
WHERE FIND_IN_SET(location_id,
(SELECT GROUP_CONCAT(location_ids)
FROM location_groups
WHERE FIND_IN_SET(2,location_groups.user_ids)) )
Alternatively, use the problems with writing the query as an example of why normalization is good. Heck, even if you do use this query, it will run more slowly than a query on properly normalized tables; you could use that to show why the tables should be restructured.
For reference (and for other readers), here's what a normalized schema would look like (some additional alterations to the base tables are included).
The compound fields in the location_groups table could simply be separated into additional rows to achieve 1NF, but this wouldn't be in 2NF, as the name column would be dependent on only the location part of the (location, user) candidate key. (Another way of thinking of this is the name is an attribute of the regions, not the relations between regions/groups, locations and users.)
Instead, these columns will be split off into two additional tables for 1NF: one to connect locations and regions, and one to connect users and regions. It may be that the latter should be a relation between users and locations (rather than regions), but that's not the case with the current schema (which could be another problem of the current, non-normalized schema). The region-location relation is one-to-many (since each location is in one region). From the sample data, we see the region-user relation is many-many. The location_groups table then becomes the region table.
-- normalized from `location_groups`
CREATE TABLE regions (
`id` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(63) UNIQUE NOT NULL
);
-- slightly altered from original
CREATE TABLE locations (
`id` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(63) UNIQUE NOT NULL
);
-- missing from original sample
CREATE TABLE users (
`id` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(63) UNIQUE NOT NULL
);
-- normalized from `location_groups`
CREATE TABLE location_regions (
`region` INT UNSIGNED,
`location` INT UNSIGNED UNIQUE NOT NULL,
PRIMARY KEY (`region`, `location`),
FOREIGN KEY (`region`)
REFERENCES regions (id)
ON DELETE restrict ON UPDATE cascade,
FOREIGN KEY (`location`)
REFERENCES locations (id)
ON DELETE cascade ON UPDATE cascade
);
-- normalized from `location_groups`
CREATE TABLE user_regions (
`region` INT UNSIGNED NOT NULL,
`user` INT UNSIGNED NOT NULL,
PRIMARY KEY (`region`, `user`),
FOREIGN KEY (`region`)
REFERENCES regions (id)
ON DELETE restrict ON UPDATE cascade,
FOREIGN KEY (`user`)
REFERENCES users (id)
ON DELETE cascade ON UPDATE cascade
);
Sample data:
INSERT INTO regions
VALUES
('South East'),
('South West'),
('North East'),
('North West');
INSERT INTO locations (`name`)
VALUES
('London'),
('Bristol'),
('Exeter'),
('Hull');
INSERT INTO users (`name`)
VALUES
('Alice'),
('Bob'),
('Carol'),
('Dave'),
('Eve');
------ Location-Region relation ------
-- temporary table used to map natural keys to surrogate keys
CREATE TEMPORARY TABLE loc_rgns (
`location` VARCHAR(63) UNIQUE NOT NULL
`region` VARCHAR(63) NOT NULL,
);
-- Hull added to demonstrate correctness of desired query
INSERT INTO loc_rgns (region, location)
VALUES
('South East', 'London'),
('South West', 'Bristol'),
('South West', 'Exeter'),
('North East', 'Hull');
-- map natural keys to surrogate keys for final relationship
INSERT INTO location_regions (`location`, `region`)
SELECT loc.id, rgn.id
FROM locations AS loc
JOIN loc_rgns AS lr ON loc.name = lr.location
JOIN regions AS rgn ON rgn.name = lr.region;
------ User-Region relation ------
-- temporary table used to map natural keys to surrogate keys
CREATE TEMPORARY TABLE usr_rgns (
`user` INT UNSIGNED NOT NULL,
`region` VARCHAR(63) NOT NULL,
UNIQUE (`user`, `region`)
);
-- user 3 added in order to demonstrate correctness of desired query
INSERT INTO usr_rgns (`user`, `region`)
VALUES
(1, 'South East'),
(2, 'South East'),
(2, 'South West'),
(3, 'North West'),
(4, 'South East');
-- map natural keys to surrogate keys for final relationship
INSERT INTO user_regions (`user`, `region`)
SELECT user, rgn.id
FROM usr_rgns AS ur
JOIN regions AS rgn ON rgn.name = ur.region;
Now, the desired query for the normalized schema:
SELECT DISTINCT loc.id
FROM locations AS loc
JOIN location_regions AS lr ON loc.id = lr.location
JOIN user_regions AS ur ON lr.region = ur.region
;
Result:
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
+----+

MySql database schema referencing problem

I have the following tables; which will be holding information about various types of articles.
I need some help with coming up with a proper schema for this.
Tables are:
CREATE TABLE IF NOT EXISTS `math_articles` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` char(250) NOT NULL,
`body` text,
PRIMARY KEY (`id`),
UNIQUE KEY `title` (`title`)
)
CREATE TABLE IF NOT EXISTS `news_articles` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` char(250) NOT NULL,
`body` text,
PRIMARY KEY (`id`),
UNIQUE KEY `title` (`title`)
)
CREATE TABLE IF NOT EXISTS `other_articles` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` char(250) NOT NULL,
`body` text,
PRIMARY KEY (`id`),
UNIQUE KEY `title` (`title`)
)
CREATE TABLE IF NOT EXISTS `references` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`article_from_table_name` text NOT NULL,
`from_id` int(11) NOT NULL,
`article_to_table_name` text NOT NULL,
`to_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
)
inserting test data:
INSERT INTO `TEST`.`math_articles` (
`id` ,
`title` ,
`body`
)
VALUES (
NULL , 'fibonacci sequences', 'fib sequences are: 0,1,1,2,3,5...also see article Leonardo of Pisa'
);
Since this math_articles.title = 'fibonacci sequences' mentions that article 'Leonardo of Pisa' my program will insert in to other_articles table the following data:
INSERT INTO `TEST`.`other_articles` (
`id` ,
`title` ,
`body`
)
VALUES (
NULL , 'Leonardo of Pisa', 'Leonardo of Pisa also known as Leonardo of Pisa, Leonardo Pisano, Leonardo Bonacci, Leonardo Fibonacci, or, most commonly, simply Fibonacci, was.....'
);
The schema problem regarding table references
Since the table other_articles.title = 'Leonardo of Pisa' was referenced in the table math_articles.title = 'fibonacci sequences' i was to save this reference in the references table as follows:
not sure/problem insert into references table
INSERT INTO `TEST`.`references`
(`id`, `article_from_table_name`, `from_id`, `article_to_table_name`, `to_id`)
VALUES
(NULL, 'math_articles', '1', 'other_articles', '1');
Whats the best way of going about saving these references?
My issues with the references table schema!
The data type of the two columns article_from_table_name and article_to_table_name is text but they are actual tables in my database.
from_id and to_id should be forign keys of their prespective tables as
from_id = article_from_table_name.id and to_id = article_to_table_name.id
I don't know how to define this in the schema.
what if i delete the article math_articles.title = 'fibonacci sequences' then the references table to also be updated, I know I should use some sort of "ON DELETE CASCADE' trigger.
Regards
Your database design is causing most of your issues here. Your three articles tables, maths, news and other should all be the same table with a type column to distinguish between the different types. Then it will be straight forward to set up a references table that contains two foreign keys to the articles table, one for the source article and one for the reference article.
I usually manage referential integrity in the application itself rather than in the database layer so that all your business logic is in one place. So if you delete an article then any reference entries should be deleted by the application itself.
Hope that helps!