What is the best way to have a table to maintain related records of another table.
Example:
mytbl
-----
id sku
1 sk1
2 sk2
3 sk3
4 sk4
5 sk5
6 sk6
7 sk7
Lets say records 1, 4 and 3 are 'related'
So I want to maintain a table that tells me that they are.
relatedTbl
----------
sku related_sku
sk1 sk3
sk1 sk4
sk3 sk4
This solution would work but, is there a better solution?
EDIT: I used skus in the relatedTbl but I know I could (better) to use ids. The question is about the structure of the table more than what foreign key to use.
You have the correct solution. As you indicated, use the ID. If sku is unique, consider using it as a natural PK.
CREATE TABLE IF NOT EXISTS `mytbl` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`sku` VARCHAR(45) NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `relatedTbl` (
`mytbl_id` INT UNSIGNED NOT NULL,
`mytbl_id1` INT UNSIGNED NOT NULL,
PRIMARY KEY (`mytbl_id`, `mytbl_id1`),
INDEX `fk_mytbl_has_mytbl_mytbl1_idx` (`mytbl_id1` ASC),
INDEX `fk_mytbl_has_mytbl_mytbl_idx` (`mytbl_id` ASC),
CONSTRAINT `fk_mytbl_has_mytbl_mytbl`
FOREIGN KEY (`mytbl_id`)
REFERENCES `mytbl` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_mytbl_has_mytbl_mytbl1`
FOREIGN KEY (`mytbl_id1`)
REFERENCES `mytbl` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
You may want to consider adding a third field to 'mytbl' in to store a unique key for common records. for instance, field 3 would be named "uniqID", and records 1, 4 and 3 are 'related' the table would then be:
mytbl
id sku uniqID
1 sk1 1
2 sk2
3 sk3 1
4 sk4 1
5 sk5
6 sk6
7 sk7
you can then use a 'WHERE uniqID=1' clause at the end of your select statement to get the common attributes
Related
I have a table products with the follow schema:
CREATE TABLE `products` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`user_id` bigint unsigned NOT NULL,
`article_id` bigint unsigned NOT NULL,
`price_cents` int unsigned NOT NULL,
`quantity` smallint NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_products_unique` (`user_id`,`article_id`,`price_cents`),
KEY `fk_products_article` (`article_id`),
CONSTRAINT `fk_products_article` FOREIGN KEY (`article_id`) REFERENCES `articles` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_products_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB
Now I can do INSERT with this query:
INSERT INTO `products` (`user_id`,`article_id`,`price_cents`,`quantity`)
VALUES (1,1,200,1)
ON DUPLICATE KEY UPDATE `price_cents`=VALUES(`price_cents`),`quantity`=quantity+VALUES(`quantity`)
So now I have 1 product (ID 1) with quantity 1 and price 200.
Now I insert 2 more products with:
INSERT INTO `products` (`user_id`,`article_id`,`price_cents`,`quantity`)
VALUES (1,1,200,1),(1,1,199,1)
ON DUPLICATE KEY UPDATE `price_cents`=VALUES(`price_cents`),`quantity`=quantity+VALUES(`quantity`)
Now I have 2 products, one (ID 1) with quantity 2 and price 200 and the other (ID 2) with quantity 1 and price 199.
Good.
The problem comes now: I want to update the product with price 199 and set a new price to 200. What I do is:
INSERT INTO `products` (`id`,`user_id`,`article_id`,`price_cents`,`quantity`)
VALUES (2,1,1,200,1)
ON DUPLICATE KEY UPDATE `price_cents`=VALUES(`price_cents`),`quantity`=quantity+VALUES(`quantity`)
and what I would like is a single product with id 1, price 200, and quantity 3, but I get Number:0x426, Message: "Duplicate entry '1-1-200' for key 'products.idx_products_unique' because MySQL does not delete the product with ID 2.
Is there a way to achieve this in MySQL (keep in mind that I want to perform these operations in bulk)?
Don't use id in the statement. A single IODKU does the entire task:
INSERT INTO t (`user_id`,`article_id`,`price_cents`,`quantity`)
...
ON DUPLICATE KEY UPDATE
quantity = quantity + VALUES(quantity)
Where ... is either a batch: VALUES (11,22,33), ... or SELECT (uid,aid,cents) FROM temp.
(Optionally, get rid of id and upgrading the 3-column Unique index to be Primary.)
I think your design does not comply with your intent.
Get rid of
UNIQUE KEY idx_products_unique (user_id,article_id,price_cents),
You can make it a non-unique index if you plan to query by it.
Also - I think you are not using the database correctly...
You should just have the records - raw data with the values.
You should get the value you are trying to aggregate as a view or a query (use group by).
You should use a merge statement, For example:
You have two tables, Products and Products info
You want to merge both but don't want to include duplicates.
Use the Following
MERGE Products P
USING Products_Info PI
ON (PI.ProductID = P.ProductID)
WHEN MATCHED
THEN UPDATE SET
P.Product_Name = PI.Product_Name,
P.Cost = PI.Cost
WHEN NOT MATCHED BY TARGET
THEN INSERT (Product_ID, Product_Name, Cost/quantity)
VALUES(PI.ProductID,PI.Product_Name,PI.Cost)
WHEN NOT MATCHED BY SOURCE
THEN DELETE;
I'm having a problem with thinking of the way to connect two tables.
I have one table with actions (RAD):
CREATE TABLE RAD (
rad_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
spec_id INT NULL,
predp_id INT NULL,
predf_id INT NULL,
strp_ID INT NULL,
strf_ID INT NULL,
---more fileds---
FOREIGN KEY (spec_id) REFERENCES SPEC(spec_id) ON DELETE SET NULL,
FOREIGN KEY (strp_ID) REFERENCES STRANKEP(strp_ID) ON DELETE CASCADE,
FOREIGN KEY (strf_ID) REFERENCES STRANKEF(strf_ID) ON DELETE CASCADE,
FOREIGN KEY (predp_id) REFERENCES PREDMETIP(predp_id) ON DELETE CASCADE,
FOREIGN KEY (predf_id) REFERENCES PREDMETIF(predf_id) ON DELETE CASCADE
) ENGINE=InnoDB COLLATE utf8_general_ci;
And one table of specifications (SPEC) based on whom bill will be made:
CREATE TABLE SPEC (
spec_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
---more fileds---
) ENGINE=InnoDB COLLATE utf8_general_ci;
As you can see action rad_id(RAD) row will be deleted if any client (strp_ID or strf_ID) will be deleted. The same goes for case(predp_id and predf_id).
Now I want to restrict delete of action rad_id(RAD row) if its included in specification. Therefore, when specification is made it inserts spec_id(SPEC) in spec-id(RAD) filed.
When specification is deleted field goes back to null and that works. BUT it allows me to delete the action rad_id(RAD) when it was included in specification(SPEC) and has that foreign key spec_id included in RAD table. And I can not let that happen. It should delete only when its null and specification key is not present.
The problem is specification will contain MULTIPLE actions rad_id's(RAD) so I can not tie it with one more column rad_id(RAD) as foreign key.
I don't know how to approach this problem.
RAD TABLE
rad_id spec_id
1 1
2 1
3 1
4 null
SPEC TABLE
spec_id rad_id-reference
1 1,2,3
As seen above SPEC table row will be made out of 3 rad_id's, I need a way to say rad_id's 1,2 and 3 can not be deleted if spec_id 1 exists. rad_id 4 can be deleted.
The problem is that I can not make rad_id-reference on SPEC table a FOREIGN KEY made out of 3 rad_id's.
I have found a way to do this.
http://sqlfiddle.com/#!9/50de2/1 If you change a delete value into 1 it will fail.
RAD TABLE
rad_id-PK
1
2
3
4
SPEC TABLE
spec_id-PK
1
2
RESTRICTDEL TABLE
res_id-PK spec_id-FK rad_id-FK
1 1 1
2 1 2
3 2 2
4 2 3
5 2 3
I have made another table that will contain both PK id's in one column, and they are FK's. one is PK and it will be unique just like spec_id From SPEC table. second is rad_id that can be double. I just have to set SET foreign_key_checks = 0; and back 1 when I'm done with inserting a new specification.
Also will need to loop with php and for every rad_id make new resdel_id entry.
This way multiple rad_id wont be deleted if there is one spec_id connecting them.
I have a table 1 with 16 unique values considering columns A, B and C.
CREATE TABLE `monitor_periodo` (
`ano` varchar(255) DEFAULT 'NULL',
`mes` varchar(255) DEFAULT 'NULL',
`data` varchar(255) DEFAULT 'NULL',
`id_periodo` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id_periodo`),
UNIQUE KEY `UNIQUE` (`ano`,`mes`,`data`)
)
A have another table, Table 2 with millions of rows and with the same structure of columns as Table 1 (except the id.periodo), so my 16 combinations from Table 1 repeats a lot in Table 2, however I do not have a id.periodo column in Table 2 to link it with table 1.
I would like to insert in Table 2 the column id.periodo following the same "matches" as Table 1. Of course it is not going to be a unique index, since the numbers from 1 to 16 will repeat a lot, but my intention is to create foreign key in Table 2 following the Primary Key (and also index) from Table 1.
Thank you in advance,
Gabriel
You can update your table2 with the id_periodo field from monitor_periodo using following statement:
UPDATE
table2
LEFT JOIN
monitor_periodo
ON
monitor_periodo.ano = table2.ano
AND
monitor_periodo.mes = table2.mes
AND
monitor_periodo.data = table2.data
SET
table2.id_periodo = monitor_periodo.id_periodo
;
Then you can create the foreign key constraint with:
ALTER TABLE table2
ADD FOREIGN KEY (id_periodo) REFERENCES monitor_periodo(id_periodo)
;
I have a table that looks like this
Car ID Car Name Part ID Stock ID
___________________________________________________
1 Audi 1 1
2 Benz 2 2
3 Corsa 1.3 3 3
4 Corsa 2.0 3 4
Now if I want to delete Corsa 1.3, it says Foreign key constraint Part ID. It can't delete it because of Part ID.
How do I fix this?
You can't delete a recrod that refers to a foreign key; that's the whole point of them.
What you would need to do is either delete the record the key refers to or remove the constraint.
You should set the field that it's complaining to null, after that, the deletion will succeed. In your case before trying to delete corsa 1.3, set it's part id to null, thus removing the reference.
Using DELETE CASCADE Option for Foreign Keys
The constraint is specified when creating the table which dictates how to deal with primary and foreign keys when updating and deleting, you can specify cascade on update and/or delete or not which is the problem your having
create table Orgs (
id bigint unsigned auto_increment,
name varchar(100) not null,
primary key (id),
unique index name_ind (name)
) engine=InnoDB;
create table Households (
id bigint unsigned,
Orgid bigint unsigned,
household varchar(20) not null,
primary key (id),
index org_ind (Orgid),
foreign key (Orgid) references Orgs(id) on update cascade on delete cascade
) engine=InnoDB;
Each member has 0 or more orders. Each order contains at least 1 item.
memberid - varchar, not integer - that's OK (please do not mention that's not very good, I can't change it).
So, thera 3 tables: members, orders and order_items. Orders and order_items are below:
CREATE TABLE `orders` (
`orderid` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`memberid` VARCHAR( 20 ),
`Time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
`info` VARCHAR( 3200 ) NULL ,
PRIMARY KEY (orderid) ,
FOREIGN KEY (memberid) REFERENCES members(memberid)
) ENGINE = InnoDB;
CREATE TABLE `order_items` (
`orderid` INT(11) UNSIGNED NOT NULL,
`item_number_in_cart` tinyint(1) NOT NULL , --- 5 items in cart= 5 rows
`price` DECIMAL (6,2) NOT NULL,
FOREIGN KEY (orderid) REFERENCES orders(orderid)
) ENGINE = InnoDB;
So, order_items table looks like:
orderid - item_number_in_cart - price:
...
1000456 - 1 - 24.99
1000456 - 2 - 39.99
1000456 - 3 - 4.99
1000456 - 4 - 17.97
1000457 - 1 - 20.00
1000458 - 1 - 99.99
1000459 - 1 - 2.99
1000459 - 2 - 69.99
1000460 - 1 - 4.99
...
As you see, order_items table has no primary keys (and I think there is no sense to create an auto_increment id for this table, because once we want to extract data, we always extract it as WHERE orderid='1000456' order by item_number_in_card asc - the whole block, id woudn't be helpful in queries).
Once data is inserted into order_items, it's not UPDATEd, just SELECTed.
The questions are:
I think it's a good idea to put index on item_number_in_cart. Could anybody please confirm that?
Is there anything else I have to do with order_items to increase the performance, or that looks pretty good? I could miss something because I'm a newbie.
Thank you in advance.
Primary keys can span multiple columns. You can't use the PRIMARY attribute of columns to do this, but you can define a separate primary key with multiple columns:
CREATE TABLE `order_items` (
`orderid` INT(11) UNSIGNED NOT NULL,
`item_number_in_cart` tinyint(1) NOT NULL , --- 5 items in cart= 5 rows
`price` DECIMAL (6,2) NOT NULL,
PRIMARY KEY (orderid, item_number_in_cart),
FOREIGN KEY (orderid) REFERENCES orders(orderid)
) ENGINE = InnoDB;
Moreover, a primary key is simply a unique key where every column is not null with a certain name; you can create your own unique keys on non-nullable columns to get the same effects.
You'll not likely get much of a performance improvement by indexing item_number_in_cart; as the number of line items for a given order will tend to be small, sorting by item_number_in_cart won't take much time or memory. However, including the column in a primary key will help with data consistency.
Index on item_number_in_cart won't be used. It's tiny int, not selective enough, and won't even considered by the engine once you have 2 records. You can add it as a second column to the existing index on orderid (since you created FK constraint on orderid, mysql automatically adds an index on this field).
You say that data in order_items never updated, but I think it can be deleted; doing so without primary key will be problematic.
Well I'd be having an autoinc anyway, as I'm a big believer in surrogate keys, but as suggested by alex07 an index, or even primary key of orderid,item_number_in_cart should sort things out. Note the order by item_number will be using a two pass sort, (get the data and then sort it in the number order) so an index / key will chop that out straight off so you'd want that index even with a surrogate key.