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
Related
I have a database with multiple tables, and I want to add a column to one table that will be populated with different strings based on the contents of another table.
Below are the tables of interest.
CREATE TABLE Locations(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Location VARCHAR(17) NOT NULL,
Is_Property BOOLEAN NOT NULL
);
CREATE TABLE Players(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Player_Name VARCHAR(17) NOT NULL,
Token VARCHAR(17) NOT NULL,
FOREIGN KEY (Token) REFERENCES Tokens(Token),
P_Location VARCHAR(17) NOT NULL,
FOREIGN KEY (P_Location) REFERENCES Locations(Location),
Bank_Balance INT NOT NULL DEFAULT 200);
ALTER TABLE Locations ADD INDEX `Location` (`Location`);
CREATE TABLE Properties AS SELECT id,Location FROM Locations
WHERE Is_Property = 1;
ALTER TABLE Properties
ADD CONSTRAINT PK_Properties PRIMARY KEY (id),
ADD COLUMN Colour VARCHAR(6),
ADD COLUMN Cost_And_Rent INT,
ADD COLUMN Owned VARCHAR(3);
CREATE TABLE Properties_Owned(
Player_id INT NOT NULL,
Prop_id INT NOT NULL,
PRIMARY KEY(Player_id, Prop_id),
FOREIGN KEY (Player_id) REFERENCES Players(id),
FOREIGN KEY (Prop_id) REFERENCES Properties(id));
The Properties and Properties_Owned tables are of interest in this case. I want to create a column called Owned in Properties and populate it with "Yes" or "No" based on if the primary key appears under Prop_id in Properties_Owned. Ergo if it does, Properties.Owned will show "Yes", and if not, "No".
I've tried using the CASE function, but I'm unsure of if it can be used without calling a SELECT query. Below is my last attempt to do so, but the syntax is wrong somewhere or just misguided altogether.
CASE
WHEN id IS IN properties_owned.Prop_id THEN Properties.Owned = "Yes"
ELSE "No" ;
It generates the error code:
Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CASE WHEN id IS IN properties_owned.Prop_id THEN Properties.Owned = "Yes" ELSE ' at line 1
Edit: As there was a request for sample data, here it is:
INSERT INTO Locations(Location,Is_Property) VALUES ("GO", 0),
("London", 1),
("Paris", 0),
("China", 1),
("New Zealand", 0),
("Sydney", 1),;
INSERT INTO Players(Player_Name,Token,P_Location,Bank_Balance) VALUES
("Mary","Battleship","London",190),
("Bill","Dog","Paris",500),
("Jane","Car","China",150),
("Norman","Thimble","London",250);
INSERT INTO Properties_Owned(Player_id,Prop_id) VALUES
(1,1),
(2,2),
(3,3),
(4,4),
(4,5);
Thus the Properties_Owned table will look like this:
Player_id | Prop_id
----------|---------
1 |1
2 |2
3 |3
4 |4
4 |5
And so in the Properties table under Owned, if Properties.id appears in Prop_id above, the Owned column should yield "Yes".
The table Properties_Owned reflects an (n:n)-relation (many-to-many). But according to your comment, a property cannot be owned by multiple players at the same time. And that would be an (n:1)-relation (many-to-one). In that case you do not need the Properties_Owned table and can just add a column Player_id (or owned_by_player_id) to the Properties table as foreign key referencing the Players table.
alter table Properties
add column Player_id int default null,
add foreign key (Player_id) references Players(id);
Then the information required for the Owned column will be already in the same table. You just need to "manipulate" it in your SELECT statements. For example with:
select
p.*,
case when Player_id is null then 'No' else 'Yes' end as Owned
from Properties p;
No need to store the same information redundantly. That would "bite" you sooner or later. Avoid redundancy when possible.
If your MySQL version (5.7+ required) supports Generated Columns you can also let the database maintain the redundancy.
alter table Properties
drop column Owned,
add column Owned varchar(3)
as (case when Player_id is null then 'No' else 'Yes' end) virtual;
Now the (genrated) column is dependent on Player_id column and you don't need (and cannot) store anything there but can select it. virtual means that it is not stored but generated (on the fly) when it's needed. Now you can read it in your queries as if it is normal column.
See example on db-fiddle.com
And again: Avoid redundant data when possible. At least use foreign keys to avoid data inconsistency.
You could create a view that extends your table by the column you want. There you can use a CASE statement.
CASE WHEN id IN SELECT Prop_id FROM properties_owned THEN 'Yes' ELSE 'No'
If this is not what you want, you could possibly use triggers on both tables that fill/update the column on on create/on delete
Initially you could fill the column with something like this:
UPDATE Prop_id SET properties_owned = CASE WHEN id IN SELECT Prop_id FROM properties_owned THEN 'Yes' ELSE 'No' WHERE
I have created 3 tables: item, shop and stock. Plus a stored procedure called inserting
which inserts to the shop table with a given item from the item table
CREATE TABLE item(
i_id int(11) auto_increment,
i_name varchar(255) not null,
primary key(i_id));
CREATE TABLE shop(
s_id int(11) auto_increment,
s_name varchar(255) not null,
s_item int(11) not null,
s_qty int(11) not null,
primary key(s_id),
foreign key(s_item) references item(i_id)
);
CREATE TABLE stock(
item int(11) not null,
total int(11) not null
);
CREATE PROCEDURE inserting (
IN shop_name varchar(225),
IN shop_item int(11),
IN shop_qty int(11)
)
BEGIN
INSERT INTO shop(s_name, s_item, s_qty)
VALUES
(shop_name, shop_item, shop_qty);
INSERT INTO STOCK(item, total)
SELECT s_item, SUM(s_qty) FROM shop GROUP BY s_item
ON DUPLICATE KEY UPDATE
item = VALUES(item),
total = VALUES(total);
The first insert works, but on the second insert when it populates the stock table it gives me extra columns, which i'm not expecting.
I have tried using REPLACE INTO and ON DUPLICATE KEY UPDATE to get single results, still the results comes as the following:
SELECT * FROM `stock`;
+------+-------+
| ITEM | TOTAL |
+------+-------+
| 1 | 5 |
| 1 | 9 |
+------+-------+
what I am trying to achieve is, group the ITEM column, and sum up the TOTAL to a single row.
what am I doing wrong here, or missing from the query?
thanks.
For the on duplicate key syntax to work as expected, you need a unique or primary key constraint on the target table, so the database can identify the "duplicate" rows. Same goes for the REPLACE syntax.
But your stock table does not have a primary key. Consider the following DDL instead:
CREATE TABLE stock(
item int(11) primary key,
total int(11) not null
);
Side note: there is no need to reassign column item in the on duplicate key clause, since it's what is used to identify the conflict in the first place. This is good enough:
INSERT INTO STOCK(item, total)
SELECT s_item, SUM(s_qty) FROM shop GROUP BY s_item
ON DUPLICATE KEY UPDATE total = VALUES(total);
If you run this one time, it should work as you expected. But subsequent runs may bring duplicate ITEM because of what #gmb said. The table must have a UNIQUE index or PRIMARY KEY. See more details here
https://dev.mysql.com/doc/refman/5.7/en/insert-on-duplicate.html
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'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.
after searching up and down, reading all possible articles and tutorials, I grasped the basics of the concept, but still cannot do it, and so as many others as I can see.
Can someone please post 100% practical and dummy proof guide to creation and most basic usage of MySQL many to many relationship, I'm so sure many will benefit from it.
What I have is a table that has a number of items, say I1, I2, I3...
I have another table, with a number of properties, say P1, P2, P3...
For each of the items, each of the properties may hold false or true, for example
I1 has properties P2 and P3
I2 has properties P1, P2 and P3
I3 has properties P1
...
So how to go about creating the relationship? (please give code if possible)
And once created, how to
insert properties for some item I
read which properties apply to some existing item I
Thanks in advance
Step 1 - Setup tables:
You should have a table structure like below (*'s are primary keys):
Item
---------
ItemId*
ItemName
ItemProperties
--------------
ItemId
PropertyId
Properties
----------
PropertyId*
PropertyName
Step 2 - Set foreign key relationships:
Both columns in the ItemProperties table are foreign keys to their corresponding table (ItemId to Item table, PropertyId to Properties table)
Step 3 - Code:
To associate the properties with PropertyIds 35 and 44 to the Item with ID 111 you would run the following:
INSERT INTO ItemProperties (ItemId,PropertyId) VALUES (111,35)
INSERT INTO ItemProperties (ItemId,PropertyId) VALUES (111,44)
To select all properties associated with an item you would run the following:
SELECT ip.PropertyId, ip.PropertyName
FROM Item as i
INNER JOIN ItemProperties as ip ON i.ItemId = ip.ItemId
WHERE i.ItemId = 111
Create an intermediary table between the two, that has ids from both the other tables. That way there can be multiple references (rows) in this table connecting different items to multiple different properties. Does this make sense?
what I would do is create a table called ItemProperties with columns ItemId, PropertyId and PropertyValue.
the key (ItemId, PropertyId) would unique for this table.
This links products to properties, allowing multiple items with the same name.
CREATE TABLE products (
productid int(11) NOT NULL AUTO_INCREMENT,
productname varchar(20) NOT NULL,
description text NOT NULL,
PRIMARY KEY (productid),
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CREATE TABLE products_property (
relationid int(11) NOT NULL AUTO_INCREMENT,
productid int(11) NOT NULL,
propertyname int(11) NOT NULL,
PRIMARY KEY (relationid)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CREATE TABLE properties (
property varchar(30) NOT NULL,
value enum('true','false') NOT NULL,
PRIMARY KEY (property)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;