I'm very beginner at MySQL and have just started to play around with foreign keys and INNER JOIN operator.
So I've made a few tables like:
CREATE TABLE `models`
(
`id` TINYINT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR (255) NOT NULL,
`price` MEDIUMINT UNSIGNED NOT NULL,
PRIMARY KEY( `id` )
);
CREATE TABLE `vendors`
(
`id` TINYINT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR (255) NOT NULL,
`id_model` TINYINT UNSIGNED NOT NULL,
PRIMARY KEY( `id` ),
FOREIGN KEY (`id_model`) REFERENCES models(`id`)
);
CREATE TABLE `cars`
(
`serial_number` MEDIUMINT UNSIGNED NOT NULL,
`id_vendor` TINYINT UNSIGNED NOT NULL,
FOREIGN KEY (`id_vendor`) REFERENCES vendors(`id`),
PRIMARY KEY( `serial_number` )
);
I know how to get output with that. However, the problem is that I don't know how to insert data properly. All I can do is insert data table by table. But how to do it in one query, and if I am inserting Honda Civic and already have Honda Accord, for example, wouldn't it duplicate Honda vendor in the database?
It seems that the structure of the database is not really coherent. Maybe I don't understand what you are trying to do, but ... anyway, here goes.
Assuming that what you want to do is store a list a of cars in a properly normalized relational database, first thing you want to do is think what is happenning in "real life":
Manufacturers (vendors) make/sell cars
Manufacturers (vendors) make different models of cars
Cars have a model (and a serial number in your case)
Models belong to a vendor (manufacturers)
Considering this, your table structure is:
Vendors
- id
- name
Models
- id
- name
- vendor ( foreign key => vendor.id )
Cars
- id
- serial_number
- model ( foreign key => model.id )
You don't need to have a reference to the vendor in the cars table becoause you have a reference to the model, which in turn has a reference to the vendor.
Whe inserting, you do it one by one, making sure that the foreign key entries already exist.
When you insert a car object, you just need to provide the model id.
When you insert a model object you need to provide a vendor id.
So the Honda Civic/Accord situation does not duplicate Honda. The Tables should be something like this:
Vendor
id, name
1, "Honda"
Model
id, name, vendor
1, "Civic", 1
2, "Accord", 1
Cars
id, serial_no, model
1, "A serial", 2 -> a honda accord
2, "Another serial", 1 -> a honda civic
Hope this helps somewhat.
You do need to check if duplicated record exists yourself.
IF EXISTS (SELECT * FROM vendors WHERE Name = 'Honda')
BEGIN
-- Insert into cars with existing vendor id
END
ELSE
BEGIN
IF EXISTIS (SELECT * FROM models WHERE Name = 'your model name')
BEGIN
-- insert into vendors with existing model id
END
ELSE
BEGIN
-- insert into models
-- insert into vendors
-- insert into cars
END
END
You can create stored procedure for it and pass car, vendor and model as parameters.
Or you can list models first, insert them; then all vendors and all cars. Just a silly answer. Welcome more sophisticated solutions.
Related
I need to load data into a DB using Sequelize on first application load. The initial excel data was given in the following format:
Car group fields: title | group_code
Car group data:
('Mercedes','M'),
('Volkswagen','VW');
Car Fields: car_code | owner | group_code
Car data:
('11-1135','Fred','M'),
('11-1146','Bob','VW');
--
Ideally what I want to end up with in the DB is the following:
Car group fields: group_id | title | group_code
Car group data:
(1, 'Mercedes','M'),
(2, 'Volkswagen','VW');
Car Fields: car_id | car_code | owner | group_id (refers to the group id created above)
Car data:
(1, '11-1135','Fred', 1),
(2, '11-1146','Bob', 2);
--
What is the best approach to doing this in Sequelize? In SQL I did the following to get around this problem:
1- Converted my Excel file into a bunch of SQL statements
2- Created the following script using those statements (and then i added my own code to fill in the group_id):
CREATE TABLE CarGroup(
group_id INT NOT NULL AUTO_INCREMENT,
title VARCHAR(100) NOT NULL,
group_code VARCHAR(5) NOT NULL,
PRIMARY KEY (`group_id`),
CONSTRAINT UN_car_group_code UNIQUE (group_code)
) ENGINE=InnoDB;
INSERT INTO CarGroup(title,group_code) VALUES ('Mercedes','M');
INSERT INTO CarGroup(title,group_code) VALUES ('Volkswagen','VW');
CREATE TABLE IF NOT EXISTS Car(
car_id INT NOT NULL AUTO_INCREMENT,
car_code VARCHAR(10),
owner VARCHAR(100) NOT NULL,
group_id SMALLINT, -- populated after insert
group_code VARCHAR(10) NOT NULL, -- deleted after insert
PRIMARY KEY (id),
CONSTRAINT `UN_car_code` UNIQUE (`car_code`),
CONSTRAINT `FK_car_group_id` FOREIGN KEY (`group_id`) REFERENCES `CarGroup` (`group_id`)
) ENGINE=InnoDB;
INSERT INTO Car(car_code,owner,group_code) VALUES ('11-1135','Fred','M');
INSERT INTO Car(car_code,owner,group_code) VALUES ('11-1146','Bob','VW');
-- GENERATE GROUP ID'S BASED ON GROUP CODE AND DROP GROUP CODE COLUMN --
update Car INNER JOIN CarGroup ON Car.group_code = CarGroup.group_code
SET Car.group_id = CarGroup.group_id;
alter table Car drop column group_code
I can't see how the above can be achieved by using migrations and seeding as I need to create the model then do seeding and then run the alteration. Is it easier to just run plain SQL statements in Sequelize in this case? Or should I just use the data as it is and link the two tables as a foreign key via the group_code (which is a string - not best performance in comparison to plain INT id).
Any direction on this is muchly appreciated!
Not sure if this is the best approach but since no one answered, but i have decided to do the following:
Create two tables, OriginalCars and Cars. OriginalCars has the original fields that the excel file has (i.e. car_code). The Cars table has the car_id and other fields.
Create the models
Sync the models
Check manually if there is any data in the tables, if not then populate the originalCars table with data. I then do an innerjoin of the OriginalCars with the group table, the resulting data is parsed and added to the Car table with car_id.
Delete the original table as its no longer needed
Feels a tad hacky but it only has to do this on initial load of the App to populate the initial data.
I have a master table, For e.g Fruits_Details(Master Table) which contains column name as:
f_name | f_price | location
I want to present a form to the user which consist of the above fields but also contains an additional "+" sign from which he can add new details as key, value pair.
For e.g :
fruit_color - red
fruit_season - spring
And many more details like this. I want that these two details should be stored in a different table(Child Table-I will implement foreign key concept).
But I am confused that how will design a query which will dynamically add column name and its related value in my child table.
The child table should have a attibute name and value there has to be nothing dynamic.
child table
-----------
fruit_id
attribute_name
attribute_value
insert into child (fruit_id, attribute_name, attribute_value)
values (1, 'color', 'red')
Since the potential is endless, don't do it by columns, but by rows...
You'll be able to extract the info one way, and display it another.
A table called fruits_attributes, that will contain the columns:
attribute_id, f_id (foreign key), attribute_name, attribute_value
CREATE TABLE `fruits_attributes` (
`attribure_id` int(8) unsigned NOT NULL AUTO_INCREMENT,
`f_id` mediumint(8) unsigned NOT NULL,
`attribure_name` varchar(50) NOT NULL,
`attribure_value` varchar(50) NOT NULL,
PRIMARY KEY (`id`),
KEY `f_id` (`offer_id`),
KEY `attribure_name` (`attribure_name`),
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
;
Then a SELECT query should be something like
SELECT f.*, fa.* FROM
Fruits_Details f
LEFT JOIN fruits_attributes fa ON fa.id = f_id
lets say I have an account object in my application, which currently represented as:
CREATE TABLE Account (
accountId int NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
PRIMARY KEY (accountId)
);
Now, Account object need to also have Solution field...and Status have 4 different possible values:
Solution1, Solution2, Solution3, Solution4
What would be the right way to represent it in the database?
Account can have few statuses, and status can have few accounts...
So at first I thought create in the db table of Solutions and than have another table to hold the relationship, but its seems too complicated for a field that have only 4 possible values...
Create a junction table to represent the relationships between accounts and solutions:
CREATE TABLE account_solution (
accountId int NOT NULL,
solutionId int NOT NULL
PRIMARY KEY (accountId, solutionId)
)
For your solution table, since there are only 4 values, you might be able to take advantage of MySQL's enum type, e.g.
CREATE TABLE solution
solutionId int NOT NULL PRIMARY KEY,
status ENUM('Solution1', 'Solution2', 'Solution3', 'Solution4')
);
You can use set Mysql SET type
CREATE TABLE Account (
accountId int NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
status set('Solution1','Solution2','Solution3','Solution4') NOT NULL,
PRIMARY KEY (accountId)
);
And if you want to select a specific status
SELECT *
FROM `Account`
WHERE FIND_IN_SET( 'Solution2', `status` ) >0
I am confused about the correct/most efficient way to place data in my dababase table when there is a OneToOne relationship.
For example, I have a users table.
I now wish for each user to be able to state his current country location.
i then want to be able to search the datatable for users by current location.
The way that I have done this is to create 3 separate tables. i.e
table one - users : just contains the user information:
CREATE TABLE users(
id MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT,
firstName VARCHAR(30) NOT NULL,
lastName VARCHAR(40) NOT NULL,
);
Table two country list: a list of countries and respective Ids for each country
PHP Code:
CREATE TABLE countrylist(
country_id MEDIUMINT UNSIGNED NOT NULL,
country VARCHAR(60) NOT NULL,
INDEX country_id ( country_id, country ),
INDEX countrylist (country, country_id ),
UNIQUE KEY (country)
);
Table 3; contains the userId and the countryId he lives in:
PHP Code:
CREATE TABLE user_countrylocation(
country_id VARCHAR(60) NOT NULL,
id MEDIUMINT UNSIGNED NOT NULL,
INDEX country_id (country_id, id ),
INDEX user_id (id, country_id )
);
Alternatively, should I place the countryId in the users table and completely get rid of the user_countrylocation. i.e in each user column, I will place a country_id for the country he lives in.
The problem is that I have over 20 similar tables as above that give details on users; i.e languages spoken, age-group, nationality etc.
My concerns is that if I place this unique information in each users column in the user table, then what would be the most efficient way to search the database: that is why I opted for the style above.
So, I really request for some advice on the most efficient/correct way to plan the database.
If you are going to have a huge data then you should keep the same approach and use the following method to keep the one to one constraint satisfied
if you don't have a huge data then you should keep the look up tables like country and use the reference for user in a column. but then you may need to allow them nulls that is make such optional information columns nullable.
The most efficient and exactly correct way is to first delete the data from the third table "user_countrylocation" for the user to be updated. Then insert the new location for the user. don't forget to use transaction.
your table 3 should have
country_id MEDIUMINT UNSIGNED NOT NULL,
instead of
country_id VARCHAR(60) NOT NULL,
and also change tyhe column name from id to user_id in all tables.
if you are using a stored procedure it would be like
create procedure sp_UpdateUserCurrentCountry (
#userID MEDIUMINT UNSIGNED,
#CountryID MEDIUMINT UNSIGNED)
begin
as
delete from user_countrylocation
where user_id = #userID
insert into user_countrylocation
(
country_id,
user_id
)
values
(
#CountryID,
#userID
)
END
One to One relations are usually mapped via Foreign Keys linking the two tables together. A third mapping table is only required for Many to Many relationships. So, you should ideally have a Foreign Key Country_ID in your Users table.
Your SELECT query would then look like
SELECT * FROM Users
WHERE Country_ID = (
SELECT Country_ID FROM Countries
WHERE Country_Name = 'USA'
);
I'm working on an application which tracks prices for certain items.
Each price has a reference to an item, a business that sells that item, and the location the item is being sold at. Now, normally, this would do just fine:
CREATE TABLE `price` (
`priceId` INT UNSIGNED NOT NULL AUTO_INCREMENT, -- PK
`businessId` INT UNSIGNED NOT NULL,
`itemId` INT UNSIGNED NOT NULL,
`locationId` INT UNSIGNED NOT NULL,
`figure` DECIMAL(19,2) UNSIGNED NOT NULL,
-- ...
)
But I have the following problem:
The application logic is such that one item at one business at one location can have multiple prices (at this point it's not really important why), and one of those prices can be an official price - an item doesn't have to have an official price, but if it does, there can be only one.
The question is; how to model this to ensure data integrity?
My initial idea was to create an additional table:
CREATE TABLE `official_price` (
`priceId` INT UNSIGNED NOT NULL -- PK + FK (references price.priceId),
-- ...
)
This table would hold priceId:s for prices that are official, and the PK/UNIQUE constraint would take care of the 'one-or-none' constraint.
This seems like a workable solution, but I'm still wondering if there's a better way to handle this situation?
You can use this dirty hack:
add a field is_official to price table, null as a value is possible in it
create an unique composite index priceId + is_official
for the official prices put 1 to is_official
for not official left it to be null
You could make the price table hold only official prices (with the figure possibly null), put a unique constraint on (businessId, itemId, locationId), and add another table of auxiliary prices referencing priceId.