How do I store custom values in place of data types for the column.
I have a Table named as 'Orders' in which a column named as 'OrderStatus' and it's purpose will be to store the Status of the Order. For example R=Rejected, S=Sent, T=Returned.
I am very new to databases and design...
The 'correct' answer is to use Standard SQL-92's CREATE DOMAIN. Sadly, SQL Server doesn't support it yet. If you would like to see support you can vote for it here.
SQL Server has its own CREATE TYPE syntax but when I last looked I declared them not fit for purpose. If anyone disagrees, please post an answer to my question :)
This leaves two viable choices: a table with a foreign keys or CHECK constraints. The rule of thumb is that if the set of domain values is small and stable (e.g. the ISO 5218 sex codes) then use CHECK constraints, otherwise prefer a table with foreign keys.
In this case you don't really need a custom data type, you just need a foreign key to a table with all of your statuses in it.
Your OrderStatus table would look like:
id int PK NOT NULL, IDENTITY
code char(1) NOT NULL
description varchar(100) NOT NULL
(edit: note, as Martin pointed out in a comment on another answer, the surrogate id key isn't entirely necessary, but it allows flexibility for easily changing the code without having to update the data that refers to it)
Your Order table would then have a foreign key to this table:
order_status_id int FK NOT NULL
You can do that.
OrderStatus OrderStatusCode
----------- ---------------
Rejected R
Sent S
Returned T
Later, when you've got more 'design' under your belt, you go with a lookup table.
Best practice is to normalize, which means creating a table called ORDER_STATUS with the approved values in there, minimally with a schema like:
ORDER_STATUS(id number auto increment, code character, meaning varchar)
and then relate ORDERS to that table in a column called order_status_id, which would be a foreign key that would not be null.
Related
I have a table which represents users connected to a game room. It looks like this:
id | gameRoomId | userId
------------------------
0 abc bob
1 xyz joe
2 xyz frank
...
Is there a way I can remove the auto-increment primary-key id column? I'm not using it for any queries, and don't plan to.
The gameRoomId and userId have a generic index on them individually.
I'm using mysql now, might switch to postgres eventually, if it matters.
It is not obligatory for a table to have a primary key constraint. Where a table does have a primary key, it is not obligatory for that key to be automatically generated. In some cases, there is no meaningful sense in which a given primary key even could be automatically generated.
You should be able to remove your existing primary key column from the database like so:
alter table my_table drop column id;
or perhaps you can avoid creating it in the first place.
Whether this is a wise thing to do depends on your circumstances.
Your table looks like a relationship table. It represents the many-to-many relationship between gamerooms and users. Assuming that a given combination of the two can occur only once (which seems reasonable), you could declare a composite primary key of those two columns, and do without the id field.
Some design tools require a simple primary key, but that's not part of relational modeling as such.
At the physical level, declaring a primary key would have a variety of consequences. The index created for you would be a compound one. It would be slightly more efificient if you used integers for userids and gemeroomids, instead of the character strings you have shown.
As far as not declaring any primary key goes, I don't recommend that. Sooner or later, you'll have a bug in your application that lets duplicate rows in there, and you'll start to get unexpected results from your queries. It's far better to let the DBMS help you manage your data.
No.
A primary key must be unique and that has to be 100% guaranteed, and NON NULL
A primary key should be stable if ever possible and not change.
So you don't have to, but it's a good choice since there is no other naturally unique data and you don't want to have enormous primary keys.
To answer your sub-question, you wouldn't really want to, it's not taking that much data and it's unique.
If I create two tables and I want to set one column as foreign key to another table column why the hell am I allowed to set foreign key column datatype?
It just doesn't make any sense or am I missing something? Is there any scenario where column with foreign keys has different datatype on purpose?
Little more deeper about my concerns, I tried to use pgadmin to build some simple Postgres DB. I made first table with primary key serial datatype. Then I tried to make foreign key but what datatype? I have seen somewhere serial is bigint unsigned. But this option doesn't even exists in pgadmin. Of course I could use sql but then why am I using gui? So I tried Navicat instead, same problem. I feel like with every choice I do another mistake in my DB design...
EDIT:
Perhaps I asked the question wrong way.
I was allowed to do build structure:
CREATE TABLE user
(
id bigint NOT NULL,
CONSTRAINT user_pkey PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
CREATE TABLE book
(
user integer,
CONSTRAINT dependent_user_fkey FOREIGN KEY (user)
REFERENCES user (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
WITH (
OIDS=FALSE
);
I insert some data to table user:
INSERT INTO user(id)
VALUES (5000000000);
But I can't cast following insert:
INSERT INTO book(user)
VALUES (5000000000);
with ERROR: integer out of range which is understandable, but obvious design error.
And my question is: Why when we set CONSTRAINT, data types are not being validated. If I'm wrong, answer should contain scenario where it is useful to have different data types.
Actually it does make sense here is why:
In a table, you can in fact set any column as its primary key. So it could be integer, double, string, etc. Even though nowadays, we mostly use either integers or, more recently, strings as primary key in a table.
Since the foreign key is pointing to another table's primary key, this is why you need to specify the foreign key's datatype. And it obviously needs to be the same datatype.
EDIT:
SQL implementations are lax on this case as we can see: they do allow compatible types (INT and BIG INT, Float or DECIMAL and DOUBLE) but at your own risk. Just as we can see in your example, below.
However, SQL norms do specify that both datatypes must be the same.
If datatype is character, they must have the same length, otherwise, if it is integer, they must have the same size and must both be signed or both unsigned.
You can see by yourself over here, a chapter from a MySQL book published in 2003.
Hope this answers your question.
To answer your question of why you'd ever want different type for a foreign vs. primary key...here is one scenario:
I'm in a situation where an extremely large postgres table is running out of integer values for its id sequence. Lots of other, equally large tables have a foreign key to that parent table.
We are upsizing the ID from integer to bigint, both in the parent table and all the child tables. This requires a full table rewrite. Due to the size of the tables and our uptime commitments and maintenance window size, we cannot rewrite all these tables in one window. We have about three months before it blows up.
So between maintenance windows, we will have primary keys and foreign keys with the same numeric value, but different size columns. This works just fine in our experience.
Even outside an active migration strategy like this, I could see creating a new child table with a bigint foreign key, with the anticipation that "someday" the parent table will get its primary key upsized from integer to bigint.
I don't know if there is any performance penalty with mismatched column sizes. That question is actually what brought me to this page, as I've been unable to find guidance on it online.
(Tangent: Never create any table with an integer id. Go with bigint, no matter what you think your data will look like in ten years. You're welcome.)
I'm defining a database for a customer/ order system where there are two highly distinct types of customers. Because they are so different having a single customer table would be very ugly (it'd be full of null columns as they are pointless for one type).
Their orders though are in the same format. Is it possible to have a CustomerId column in my Order table which has a foreign key to both the Customer Types? I have set it up in SQL server and it's given me no problems creating the relationships, but I'm yet to try inserting any data.
Also, I'm planning on using nHibernate as the ORM, could there be any problems introduced by doing the relationships like this?
No, you can't have a single field as a foreign key to two different tables. How would you tell where to look for the key?
You would at least need a field that tells what kind of user it is, or two separate foreign keys.
You could also put the information that is common for all users in one table and have separate tables for the information that is specific for the user types, so that you have a single table with user id as primary key.
A foreign key can only reference a single primary key, so no. However, you could use a bridge table:
CustomerA <---- CustomerA_Orders ----> Order
CustomerB <---- CustomerB_Orders ----> Order
So Order doesn't even have a foreign key; whether this is desirable, though...
I inherited a SQL Server database where this was done (a single column used in four foreign key relationships with four unrelated tables), so yes, it's possible. My predecessor is gone, though, so I can't ask why he thought it was a good idea.
He used a GUID column ("uniqueidentifier" type) to avoid the ambiguity problem, and he turned off constraint checking on the foreign keys, since it's guaranteed that only one will match. But I can think of lots of reasons that you shouldn't, and I haven't thought of any reasons you should.
Yours does sound like the classical "specialization" problem, typically solved by creating a parent table with the shared customer data, then two child tables that contain the data unique to each class of customer. Your foreign key would then be against the parent customer table, and your determination of which type of customer would be based on which child table had a matching entry.
You can create a foreign key referencing multiple tables. This feature is to allow vertical partioining of your table and still maintain referential integrity. In your case however, this is not applicable.
Your best bet would be to have a CustomerType table with possible columns - CustomerTypeID, CustomerID, where CustomerID is the PK and then refernce your OrderID table to CustomerID.
Raj
I know this is a very old question; however if other people are finding this question through the googles, and you don't mind adding some columns to your table, a technique I've used (using the original question as a hypothetical problem to solve) is:
Add a [CustomerType] column. The purpose of storing a value here is to indicate which table holds the PK for your (assumed) [CustomerId] FK column. Optional - addition of a check constraint (to ensure CustomerType is in CustomerA or CustomerB) will help you sleep better at night.
Add a computed column for each [CustomerType], eg:
[CustomerTypeAId] as case when [CustomerType] = 'CustomerA' then [CustomerId] end persisted
[CustomerTypeBId] as case when [CustomerType] = 'CustomerB' then [CustomerId] end persisted
Add your foreign keys to the calculated (and persisted) columns.
Caveat: I'm primarily in a MSSQL environment; so I don't know how well this translates to other DBMS (ie: Postgres, ORACLE, etc).
As noted, if the key is, say, 12345, how would you know which table to look it up in? You could, I suppose, do something to insure that the key values for the two tables never overlapped, but this is too ugly and painful to contemplate. You could have a second field that says which customer type it is. But if you're going to have two fields, why not have one field for customer type 1 id and another for customer type 2 id.
Without knowing more about your app, my first thought is that you really should have a general customer table with the data that is common to both, and then have two additional tables with the data specific to each customer type. I would think that there must be a lot of data common to the two -- basic stuff like name and address and customer number at the least -- and repeating columns across tables sucks big time. The additional tables could then refer back to the base table. As there is then a single key for the base table, the issue of foreign keys having to know which table to refer to evaporates.
Two distinct types of customer is a classic case of types and subtypes or, if you prefer, classes and subclasses. Here is an answer from another question.
Essentially, the class-table-inheritance technique is like Arnand's answer. The use of the shared-primary-key technique is what allows you to get around the problems created by two types of foreign key in one column. The foreign key will be customer-id. That will identify one row in the customer table, and also one row in the appropriate kind of customer type table, as the case may be.
Create a "customer" table include all the columns that have same data for both types of customer.
Than create table "customer_a" and "customer_b"
Use "customer_id" from "consumer" table as foreign key in "customer_a" and "customer_b"
customer
|
---------------------------------
| |
cusomter_a customer_b
I have table named 'Dictionary' with columns as follow:
ID bigint
TYPE varchar (200)
ITEM varchar (200)
Table is used by various tables as simple dictionary / lookup.
Eg it stores countries, titles, business type lists.
TYPE column keeps info about type of dictionary , ITEM is dictionary string value.
All works well but I have problem to set up relationship between dictionary and foreigin tables.
When I'm using 'Foreign Key Relationship' I can not make it depended of 'TYPE" column.
(Please note same item with same type - eg 'countries' can be linked to several tables, when item with another type can be linked to different)
Currently I'm using USPs to manage that but I'd like to switch to standard relationship mechanism.
Any advice how to get that?
It looks to me that you could consider an alternative design
Dictionary table
ID (pk)
DICTIONARY_TYPE_ID (fk to dictionaryType)
ITEM
DictionaryType table
ID (pk)
DESCRIPTION
and then make links to the ID of DictionaryType table in places where you currently want to reference Type field from your original design
From the context of the question, I'm guessing you'll need to do one of two things:
Make your Type column the primary key
or have the foreign keys depend on the ID field here.
Foreign keys need to refer to a primary key, and it looks like your Type column isn't a PK.
what you have here is an EAV db design which is bad for number of reasons one being your problem. there is no solution for this in the real sense. you might try using sql_variant as a column type for the item and try to to a PK-FK relationship on that.
there's another way you could try to do this with the xml datatype and schemas like i describe here. however you'll have to test this to see if it applies to your problem.
An associate has created a schema that uses an ENUM() column for the primary key on a lookup table. The table turns a product code "FB" into it's name "Foo Bar".
This primary key is then used as a foreign key elsewhere. And at the moment, the FK is also an ENUM().
I think this is not a good idea. This means that to join these two tables, we end up with four lookups. The two tables, plus the two ENUM(). Am I correct?
I'd prefer to have the FKs be CHAR(2) to reduce the lookups. I'd also prefer that the PKs were also CHAR(2) to reduce it completely.
The benefit of the ENUM()s is to get constraints on the values. I wish there was something like: CHAR(2) ALLOW('FB', 'AB', 'CD') that we could use for both the PK and FK columns.
What is: Best PracticeYour preference
This concept is used elsewhere too. What if the ENUM()'s values are longer? ENUM('Ding, dong, dell', 'Baa baa black sheep'). Now the ENUM() is useful from a space point-of-view. Should I only care about this if there are several million rows using the values? In which case, the ENUM() saves storage space.
ENUM should be used to define a possible range of values for a given field. This also implies that you may have multiple rows which have the same value for this perticular field.
I would not recommend using an ENUM for a primary key type of foreign key type.
Using an ENUM for a primary key means that adding a new key would involve modifying the table since the ENUM has to be modified before you can insert a new key.
I am guessing that your associate is trying to limit who can insert a new row and that number of rows is limited. I think that this should be achieved through proper permission settings either at the database level or at the application and not through using an ENUM for the primary key.
IMHO, using an ENUM for the primary key type violates the KISS principle.
but when you only trapped with differently 10 or less rows that wont be a problem
e.g's
CREATE TABLE `grade`(
`grade` ENUM('A','B','C','D','E','F') PRIMARY KEY,
`description` VARCHAR(50) NOT NULL
)
This table it is more than diffecult to get a DML
We've had more discussion about it and here's what we've come up with:
Use CHAR(2) everywhere. For both the PK and FK. Then use mysql's foreign key constraints to disallow creating an FK to a row that doesn't exist in the lookup table.
That way, given the lookup table is L, and two referring tables X and Y, we can join X to Y without any looking up of ENUM()s or table L and can know with certainty that there's a row in L if (when) we need it.
I'm still interested in comments and other thoughts.
Having a lookup table and a enum means you are changing values in two places all the time. Funny... We spent to many years using enums causing issues where we need to recompile to add values. In recent years, we have moved away from enums in many situations an using the values in our lookup tables. The biggest value I like about lookup tables is that you add or change values without needing to compile. Even with millions of rows I would stick to the lookup tables and just be intelligent in your database design