I am trying to have categories in my budget2000 table be the foreign key to category in mainBudget. Category is not a unique number so it cannot be a primary key. When I run the code I get the famous error 1005. When I make category part of the primary key in mainBudget with id the code runs, however this will create problems later on. What can I do to make categories a foreign key. I am using mysql 5.5.
Here is my code
create table mainBudget(
id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
year Year NOT NULL,
amount double(10,2) NOT NULL,
category SMALLINT UNSIGNED NOT NULL,
primary key(id)
)ENGINE=INNODB;
create table budget2000(
id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
categories SMALLINT UNSIGNED NOT NULL,
INDEX categoryNumber (categories),
subCategory SMALLINT NOT NULL,
amount FLOAT(10,2) NOT NULL,
date DATE NOT NULL,
description VARCHAR(300) NOT NULL,
primary key(id),
FOREIGN KEY (categories) REFERENCES mainBudget(category)
)ENGINE=INNODB;
category is not indexed in mainBudget. The column in the referenced table has to be indexed (or the left prefix of an index).
Incidentally, are you sure it isn't better to have an additional table category and have mainBudget.category and budget200.categories both foreign keys to this table? Your current setup looks a little odd, particularly with the referenced column in mainBudget not being unique.
Having FKs referencing non-unique columns is not standard SQL. Even when MySQL InnoDB allows this, it does not mean that it is a good idea.
Make some ER-Diagrams and normalize your tables. (Use 3.NF if nothing else forces you not to do.) Having a separate table for Category seems to be the way to go. On the other hand the naming of your exiting tables makes me thinking these should be only one table or their naming is bad.
And when this 2000 has something to do with a year or what then forget about it. You can select this easy in your Queries. Just put everything in one table no matter what year it is.
Your question/problem seems to be design-related to me.
Related
What is better for multiply clients?
I create training project and can't understand what's better. Create one big stock portfolio table for all broker's clients or create individual table for each client? Individual table will require add brokerage agreement id for each table's name for it indentification.
DROP TABLE IF EXISTS portfolio;
CREATE TABLE common_portfolio (
common_portfolio_id serial,
brokerage_agreement_id BIGINT UNSIGNED NOT NULL,
type_assets_id BIGINT UNSIGNED NOT NULL,
stock_id BIGINT UNSIGNED NOT NULL,
stock_num BIGINT UNSIGNED NOT NULL,
FOREIGN KEY (brokerage_agreement_id) REFERENCES brokerage_agreement (brokerage_agreement_id),
FOREIGN KEY (type_assets_id) REFERENCES type_assets (type_assets_id),
FOREIGN KEY (stock_id) REFERENCES stock (stock_id)
);
VS
DROP TABLE IF EXISTS portfolio_12345612348; -- number generate from brokerage_agreement_id
CREATE TABLE portfolio_12345612348 (
position_id serial,
type_assets_id BIGINT UNSIGNED NOT NULL,
stock_id BIGINT UNSIGNED NOT NULL,
stock_num BIGINT UNSIGNED NOT NULL,
FOREIGN KEY (type_assets_id) REFERENCES type_assets (type_assets_id),
FOREIGN KEY (stock_id) REFERENCES stock (stock_id)
);
It is always better to keep all them in same table.
Keeping each client's data in a separate table will provide you with best performance only in case when you're looking for this particular customer.
But in all other cases it will be hell: creating/deleting a client will require you to build a dynamical create/drop table statement.
When sometime later you decided to add a column, you'll need to find ALL of those tables somehow and add new column to each one of them.
Even counting number of clients will cause you to write way more code rather than just "select count" statement.
And many more cases
So, use only one table
Im creating a user database ... i want to separate user - cellphone number from 'user' table and create another table for it (user_cellphone (table))
but i have a problem to select best index !
in user_cellphone table, we get user_id and cellphone number ... but all SELECT queries are more based on 'user_id' so i want to know if it's better to choose 'user_id' column as primary key or not !!!
(Also each user have only one cellphone number !)
which option of these 2 options are better ?
CREATE TABLE `user_cellphone_num` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`cellphone_country_code` SMALLINT UNSIGNED NOT NULL,
`cellphone_num` BIGINT UNSIGNED NOT NULL,
`user_id` INT UNSIGNED NOT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `cellphone` (`cellphone_country_code`, `cellphone_num`),
UNIQUE INDEX `user_id` (`user_id`)
)
CREATE TABLE `user_cellphone_num` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`cellphone_country_code` SMALLINT UNSIGNED NOT NULL,
`cellphone_num` BIGINT UNSIGNED NOT NULL,
`user_id` INT UNSIGNED NOT NULL,
PRIMARY KEY (`user_id`),
UNIQUE INDEX `id` (`id`),
UNIQUE INDEX `cellphone` (`cellphone_country_code`, `cellphone_num`)
)
choosing 'user_id' as primary key or just set 'user_id' as a unique key ?! is there any different here in performance ? (Im talking about when i have millions of rows)
in future im going to use some queries like this:
select u.*,cell.* FROM user AS u LEFT JOIN user_cellphone AS cell ON cell.user_id = u.id
so which one of these options give me better performance for some queries like this ?
May I offer some hard-won data design advice?
Do not use telephone numbers as any kind of unique or primary key.
Why not?
Sometimes multiple people use a single number.
Sometimes people make up fake numbers.
People punctuate numbers based on context. To my neighbors, my number is (978)555-4321. To a customer in the Netherlands it is +1.978.555.4321. Can you write a program to regularize those numbers? Of course. Can you write a correct program to do that? No. Why bother trying. Just take whatever people give you.
(Unless you work for a mobile phone provider, in which case ask your database administrator.
Read this carefully. https://github.com/google/libphonenumber/blob/master/FALSEHOODS.md
InnoDB tables are stored as a clustered index, also called an index-organized table. If the table has a PRIMARY KEY, then that is used as the key for the clustered index. The other UNIQUE KEY is a secondary index.
Queries where you look up rows by the clustered index are a little bit more efficient than using a secondary index, even if that secondary index is a unique index. So if you want to optimize for the most common query which you say is by user_id, then it would be a good idea to make that your clustered index.
In your case, it would be kind of strange to separate the cellphones into a separate table, but then make user_id alone be the PRIMARY KEY. That means that only one row per user_id can exist in this table. I would have expected that you separated cellphones into a separate table to allow each user to have multiple phone numbers.
You can get the same benefit of the clustered index if you just make sure user_id is the first column in a compound key:
CREATE TABLE `user_cellphone_num` (
`user_id` INT UNSIGNED NOT NULL,
`num` TINYINT UNSIGNED NOT NULL,
`cellphone_country_code` SMALLINT UNSIGNED NOT NULL,
`cellphone_num` BIGINT UNSIGNED NOT NULL,
PRIMARY KEY (`user_id`, `num`)
)
So a query like SELECT ... FROM user_cellphone_num WHERE user_id = ? will match one or more rows, but it will be an efficient lookup because it's searching the first column of the clustered index.
Reference: https://dev.mysql.com/doc/refman/8.0/en/innodb-index-types.html
i need help. As you can see in my tables i have to setup primary and forign keys and i need help on this cascade updates.
For example i have a task like this:
If the value for Category_Name is changed in CATEGORY, the change should be reflected here as well.
But this doesent work :
If an OrderID in ORDERED is changed, then the change should be reflected here as well.
If an ORDERED is deleted, then any LINE_ITEM(s)associated with that order should also be deleted.
If the Item_Number of an ITEM is changed, then the change should be reflected here as well.
I dont know how to setup this correctly and i need help to better understand this.
CREATE DATABASE TEST1;
USE TEST1;
CREATE TABLE CATEGORY (
CategoryName VARCHAR(35) NOT NULL,
ShippingPerPound CHAR(4),
OffersAlowed ENUM('y', 'n'),
CONSTRAINT CATEGORY_PK PRIMARY KEY (CategoryName)
) ENGINE=INNODB;
CREATE TABLE ITEM(
ItemNumber INT UNSIGNED AUTO_INCREMENT,
Item_Name VARCHAR(35) NOT NULL,
Description VARCHAR(255),
Model VARCHAR(50) NOT NULL,
Price CHAR(8) NOT NULL,
parent_ItemNumber INT,
CategoryName VARCHAR(35),
CONSTRAINT ITEM_PK PRIMARY KEY (ItemNumber),
CONSTRAINT ITEM_CategoryName_fk FOREIGN KEY (CategoryName) REFERENCES
CATEGORY(CategoryName) ON UPDATE CASCADE)
ENGINE=INNODB;
CREATE table LINE_ITEM(
Quantitiy INT(255),
Shipping_amounth DECIMAL(4,2),
ItemNumber INT UNSIGNED,
OrderID INT UNSIGNED,
CONSTRAINT LINE_ITEM_PK PRIMARY KEY(ItemNumber),
CONSTRAINT LINE_ITEM_PK PRIMARY KEY(OrderID),
CONSTRAINT LINE_ITEM_OrderID FOREIGN KEY (OrderID) REFERENCES ORDERED(OrderID) ON UPDATE CASCADE),
CONSTRAINT LINE_ITEM_OrderID FOREIGN KEY (OrderID) REFERENCES ORDERED(OrderID) ON UPDATE DELETE),
CONSTRAINT LINE_ITEM_ItemNumber_fk FOREIGN KEY (ItemNumber) REFERENCES ITEM(ItemNumber) ON UPDATE CASCADE)
ENGINE=INNODB;
CREATE TABLE OFFER(
OfferCode varchar(15),
Discount_Amt varchar(35) NOT NULL,
MinAmount DECIMAL(2,2) NOT NULL,
ExpirationDate DATE NOT NULL,
CONSTRAINT OFFER_OfferCode PRIMARY KEY(OfferCode)
)
ENGINE=INNODB;
CREATE TABLE ORDERED(
OrderID INT UNSIGNED AUTO_INCREMENT,
total_cost DECIMAL(8,2),
CONSTRAINT ORDERED_PK PRIMARY KEY (OrderID),
CONSTRAINT OFFER_OfferCode FOREIGN KEY (OrderID) REFERENCES OFFER(OfferCode) ON UPDATE CASCADE),
CONSTRAINT CUSTOMER_CustomerID FOREIGN KEY (CustomerID) REFERENCES CUSTOMER(CustomerID) ON UPDATE CASCADE)
)
ENGINE=INNODB;
If the value for Category_Name is changed in CATEGORY, the change should be reflected [in the tables which reference Category] as well.
You have an XY Problem. You've already chosen a solution to your problem (using cascading updates) and asked about that. It's not a good solution, it just papers over the real. Instead, you should ask about the real problem.
The real problem is you have duplicate data, CategoryName is stored in two places. The question is how one deals with that? The answer is to redesign the schema to eliminate the duplication.
Looking at the Category table reveals the real real problem, CategoryName is the primary key, so it will be referenced in other tables. But if CategoryName can change it's a poor choice for a primary key. Instead, use a simple auto incrementing integer as the primary key and the problem goes away.
create table Category (
ID integer auto_increment primary key,
Name varchar(255) not null,
ShippingPerPound CHAR(4),
OffersAlowed ENUM('y', 'n'),
);
Now categories can be referenced using CategoryID integer references category(id). Category names can change as much as they like. Any query needing to know the category name will have to do a join Category on Category.id = CategoryID; simple joins like that are cheap.
If the Item_Number of an ITEM is changed, then the change should be reflected [in the tables which reference Item] as well.
Same problem: if the primary key can change, it's not a good primary key. Since Item_Number is auto incremented it should never change, so you might be worrying about a problem that doesn't exist.
If Item_Number can change, then you need two columns. One for the immutable primary key, just call it id, and one for the mutable Item_Number. They can be the same thing for most columns, that's fine, it just adds 4 bytes to each column.
Note that I increased the name constraint to 255. It's a bad practice to put business rules, like size limits on names, into the database schema. The database should not be limiting design choices, and there's no technical reason to limit it: 30 characters in a varchar(255) takes up as much space as 30 characters in varchar(30).
I'd also question why ShippingPerPound is a char(4). It seems it should be a number, probably a numeric(9,2) for money. numeric will store exact values and does not suffer from floating point error, it's a good choice for money.
Finally, I'd caution against using an unsigned integer as a primary key. Yes, it doubles your keyspace, but I can guarantee people referencing that key will forget and use a plain, signed integer. If you hit 2 billion rows it's likely you're growing so rapidly that you'll blow through the next 2 billion much faster than the first, so it isn't worth it. If you're really concerned about keyspace, use a bigint or UUID. But this isn't something you need to worry about now, tables can be altered later if it becomes an issue. But it's unlikely to be an issue for Items as it's unlikely you'll have 2 billion items. Keyspace exhaustion is something that happens to tables that are logging things, or tracking sales, things which grow exponentially as you get more users; not manually entered warehouse data.
Old database guides sometimes encourage bad practices like trying to use data as a primary key, or putting unnecessary limits on storage sizes. That might have made sense when disk and CPU was extremely limited, or when column sizes were fixed, but it makes little sense now. An auto incremented integer primary key is a good default choice.
Would the following table considered to have duplicate indexes on TypeId, or is it perfectly fine to do it this way? Some of my queries perform faster using the KEY "covered', while others perform better just using the 'TypeId'. Any knowledge on the matter would be appreciated.
CREATE TABLE module(
Id INT unsigned not null auto_increment,
name VARCHAR(30) not null,
TypeId INT unsigned not null,
cSign tinyint not null,
orderId int not null,
PRIMARY KEY(Id),
KEY 'covered' ('cSign','TypeId','orderId'),
KEY 'TypeId' ('TypeId')
);
No, the indexes are different.
MySQL documentation does a good job of explaining indexes with composite keys. What is important is that the left-most columns in the indexes are different.
As a note: you should fix your code by removing the single quotes. They are incorrect in this context.
I am not sure how to phrase the question so I'll illustrate the tables and the explain what I want to achieve.
-- static table of the entity classes supported by the application
create table entity_type (
id integer not null auto_increment,
name varchar(30) not null,
primary key(id)
);
-- static table of statuses supported by the application
create table entity_status (
id integer not null auto_increment,
name varchar(30) not null,
primary key(id)
);
-- table of valid combinations
create table entity_type_entity_status_link (
entity_type_id integer not null,
entity_status_id integer not null,
unique key(entity_type_id, entity_status_id),
foreign key(entity_type_id) references entity_type(id),
foreign key(entity_status_id) references entity_status(id),
);
-- The tables where user types and statuses are defined
create table user_type (
id integer not null auto_increment,
name varchar(30) not null,
entity_type_id integer not null,
primary key(id),
foreign key(entity_type_id) references entity_type(id)
);
create table user_status (
id integer not null auto_increment,
name varchar(30) not null,
entity_status_id integer not null,
primary key(id),
foreign key(entity_status_id) references entity_status(id)
);
-- table of valid pairs
create table user_type_user_status_link (
user_type_id integer not null,
user_status_id integer not null,
unique key(user_type_id, user_status_id),
foreign key(user_type_id) references user_type(id),
foreign key(user_status_id) references user_status(id),
);
The basic premise behind these tables is that the system supports core types and statuses and the user is able to create their own user types and statues that derive from these.
The question I have is that I cannot see a way of creating any database constraints on the user_type_user_status_link table to ensure that the you cannot insert a file_type - file_status pair where the parent entity_type - entity_status is itself not valid. Or is this something that would have to be done with triggers.
The basic premise behind these tables is that the system supports core
types and statuses and the user is able to create their own user types
and statues that derive from these.
Although that sounds like a laudable goal on the surface, the effect is to delegate database design to your users. Database design, because the effect of your desire to set foreign key references to a subset of the rows in entity_type_entity_status_link means each of those subsets is a defacto, unnamed table.
This approach never ends well.
What you've developed is the "One True Lookup Table". Google that for a host of reasons why OTLT is an anti-pattern.
The best solution is to model real things in your tables. (Entity isn't a real thing. It's an abstraction of a real thing.) Something along the lines of either
create table file_status (
file_status varchar(30) primary key
);
or
create table file_status (
file_status_id integer primary key,
file_status varchar(30) not null unique
);
would work well for file statuses.
In the case of the second one, you can set a foreign key reference to either the id number (saves space, requires an additional join) or to the status text (takes more space, eliminates a join). Note that you need the unique constraint on the status text; your original design allows the user to enter the same text multiple times. (You could end up with 30 rows where entity_type.name is 'File'.
You should use triggers for that.
MySQL does not support constraints of the form that will prevent what you want.