General many-to-many relationship problem ( Postgresql ) - sql

i have two tables:
CREATE TABLE "public"."auctions" (
"id" VARCHAR(255) NOT NULL,
"auction_value_key" VARCHAR(255) NOT NULL,
"ctime" TIMESTAMP WITHOUT TIME ZONE NOT NULL,
"mtime" TIMESTAMP WITHOUT TIME ZONE NOT NULL,
CONSTRAINT "pk_XXXX2" PRIMARY KEY("id"),
);
and
CREATE TABLE "public"."auction_values" (
"id" NUMERIC DEFAULT nextval('default_seq'::regclass) NOT NULL,
"fk_auction_value_key" VARCHAR(255) NOT NULL,
"key" VARCHAR(255) NOT NULL,
"value" TEXT,
"ctime" TIMESTAMP WITHOUT TIME ZONE NOT NULL,
"mtime" TIMESTAMP WITHOUT TIME ZONE NOT NULL,
CONSTRAINT "pk_XXXX1" PRIMARY KEY("id"),
);
if i want to create a many-to-many relationship on the auction_value_key like this:
ALTER TABLE "public"."auction_values"
ADD CONSTRAINT "auction_values_fk" FOREIGN KEY ("fk_auction_value_key")
REFERENCES "public"."auctions"("auction_value_key")
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE;
i get this SQL error:
ERROR: there is no unique constraint matching given keys for referenced table "auctions"
Question:
As you might see, i want "auction_values" to be be "reused" by different auctions without duplicating them for every auction... So i don't want a key relation on the "id" field in the auctions table...
Am i thinking wrong here or what is the deal? ;)
Thanks

You need an extra table to model a many-to-many relationship. It will contain the mappings between auctions and auction_values. It needs two columns: auction_id and auction_value_id.

If you want the auction_values to be reused by different auctions, you should declare a constraint the other way round:
ALTER TABLE auctions
ADD CONSTRAINT fk_auction_values
FOREIGN KEY (auction_value_key)
REFERENCES auction_values (id)

Quoting the wikipedia
In the context of relational
databases, a foreign key is a
referential constraint between two
tables.1 The foreign key identifies
a column or a set of columns in one
(referencing) table that refers to set
of columns in another (referenced)
table. The columns in the referencing
table must be the primary key or other
candidate key in the referenced table.
The values in one row of the
referencing columns must occur in a
single row in the referenced table.
Thus, a row in the referencing table
cannot contain values that don't exist
in the referenced table (except
potentially NULL). This way references
can be made to link information
together and it is an essential part
of database normalization. Multiple
rows in the referencing table may
refer to the same row in the
referenced table. Most of the time, it
reflects the one (master table, or
referenced table) to many (child
table, or referencing table)
relationship.
As Quassnoi points out, it sounds as if you want to have multiple rows in auctions reference single rows in auction_values.
For that the master or referenced table is auction_values and child or referencing table is auction_values.
If on the other hand Alex is right and you want to reference multiple rows in the auction_values you will need another table.
This table will help you convert the many-to-many relationship (which can not be directly realized on the physical database level) to two one-to-many relationships.
Generally you could have this table store ids from the two starting tables and in this way you can associate any combination of the records from auction_values and auctions.
However, this might be too general and you might actually be after a table auction_value_keys (auction_value_key)

Related

Bypass database constraints during record deletion

I have around 20 mapping tables which refer to a single table.
The single table being referenced is,
field (
id integer,
value char
)
The mapping tables are as,
employee_field_map (
employee_id integer references employee(id),
field_id references field(id)
)
dept_field_map (
dept_id integer references dept(id),
field_id references field(id)
)
and similar additional 18 mapping tables.
Now if I want to delete number of records from the field table where field.id = employee_field_map.field_id it takes very long amount of time because there are 20 mapping tables which refer to the field table; And for each of that mapping table a constraint violation check is performed before deleting a record from the field table.
A field table rcord will always be referenced by only one of the mapping table at a time.
In above scenario before deleting a record from field table of course the corresponding record in employee_field_map table is deleted first. So I know for sure that none of the mapping table contains a reference to the field table record being deleted. So is there a way to tell the database engine not to perform those constraint checks when the delete on field table is being performed?
Disabling the constraints is not an option unfortunately. Please advise.
Assuming each of the mapping tables has an index on field_id, then the lookups should not be expensive.
I am wondering why you are not declaring them using cascading delete foreign key references:
employee_field_map (
employee_id integer references employee(id),
field_id references field(id) on delete cascade
);
Nothing in your data model is saying that the field is in only one mapping table. In fact, I don't see why things are broken out the way they are. Presumably there is a reason for breaking the fields apart like this instead of just having a "type" column in the fields table.

Adding multiple foreign keys in column

Is there a way to store multiple values in a column that has a foreign key constraint?
Let's say I have a states table and a project table. Project table has a foreign key constraint with states table. Now we are implementing the same project in three different states. How can I select multiple states?
Sample
Create table states (
Stateid int identity primary key,
State varchar(100)
);
Projects Table
Create table projects (
ProjId int primary key identity,
ProjTitle varchar (100),
Budget decimal,
);
How can I insert multiple values in projects states table?
Based on TPHE answer lets me create another table called projectstates
Create table projectstates(
projStatid int identity primary key,
stateid int,
ProjId int
constraint fk_ProjId foreign key (ProjId) references Projects(ProjId),
constraint fk_stateid foreign key (stateid) references states(StateId)
);
Now how can i insert data in ProjectStates while adding project to the project table?
The best way I've found to do this is to create the second table with no foreign key constraint at first. Then you can populate both tables with the data, then introduce the constraint afterwards - assuming the data in the tables complies with the constraint.
Also, if a many to many relationship exists, add in a mapping table to allow this.
It would break some basic rules of database design to add multiple values. You should create a new table that has a one to many relationship with the states table (each state can have multiple values in the new table) and contains a column for the associated project IDs (also with a one-to-many relationship). Then you would join from the states table to the new table and then to the projects table or vice versa. More info on how and why to design databases in this way.

Can a foreign key be NULL and/or duplicate?

Please clarify two things for me:
Can a Foreign key be NULL?
Can a Foreign key be duplicate?
As fair as I know, NULL shouldn't be used in foreign keys, but in some application of mine I'm able to input NULL in both Oracle and SQL Server, and I don't know why.
Short answer: Yes, it can be NULL or duplicate.
I want to explain why a foreign key might need to be null or might need to be unique or not unique. First remember a Foreign key simply requires that the value in that field must exist first in a different table (the parent table). That is all an FK is by definition. Null by definition is not a value. Null means that we do not yet know what the value is.
Let me give you a real life example. Suppose you have a database that stores sales proposals. Suppose further that each proposal only has one sales person assigned and one client. So your proposal table would have two foreign keys, one with the client ID and one with the sales rep ID. However, at the time the record is created, a sales rep is not always assigned (because no one is free to work on it yet), so the client ID is filled in but the sales rep ID might be null. In other words, usually you need the ability to have a null FK when you may not know its value at the time the data is entered, but you do know other values in the table that need to be entered. To allow nulls in an FK generally all you have to do is allow nulls on the field that has the FK. The null value is separate from the idea of it being an FK.
Whether it is unique or not unique relates to whether the table has a one-one or a one-many relationship to the parent table. Now if you have a one-one relationship, it is possible that you could have the data all in one table, but if the table is getting too wide or if the data is on a different topic (the employee - insurance example #tbone gave for instance), then you want separate tables with a FK. You would then want to make this FK either also the PK (which guarantees uniqueness) or put a unique constraint on it.
Most FKs are for a one to many relationship and that is what you get from a FK without adding a further constraint on the field. So you have an order table and the order details table for instance. If the customer orders ten items at one time, he has one order and ten order detail records that contain the same orderID as the FK.
1 - Yes, since at least SQL Server 2000.
2 - Yes, as long as it's not a UNIQUE constraint or linked to a unique index.
Yes foreign key can be null as told above by senior programmers... I would add another scenario where Foreign key will required to be null....
suppose we have tables comments, Pictures and Videos in an application which allows comments on pictures and videos. In comments table we can have two Foreign Keys PicturesId, and VideosId along with the primary Key CommentId. So when you comment on a video only VideosId would be required and pictureId would be null... and if you comment on a picture only PictureId would be required and VideosId would be null...
it depends on what role this foreign key plays in your relation.
if this foreign key is also a key attribute in your relation, then it can't be NULL
if this foreign key is a normal attribute in your relation, then it can be NULL.
Here's an example using Oracle syntax:
First let's create a table COUNTRY
CREATE TABLE TBL_COUNTRY ( COUNTRY_ID VARCHAR2 (50) NOT NULL ) ;
ALTER TABLE TBL_COUNTRY ADD CONSTRAINT COUNTRY_PK PRIMARY KEY ( COUNTRY_ID ) ;
Create the table PROVINCE
CREATE TABLE TBL_PROVINCE(
PROVINCE_ID VARCHAR2 (50) NOT NULL ,
COUNTRY_ID VARCHAR2 (50)
);
ALTER TABLE TBL_PROVINCE ADD CONSTRAINT PROVINCE_PK PRIMARY KEY ( PROVINCE_ID ) ;
ALTER TABLE TBL_PROVINCE ADD CONSTRAINT PROVINCE_COUNTRY_FK FOREIGN KEY ( COUNTRY_ID ) REFERENCES TBL_COUNTRY ( COUNTRY_ID ) ;
This runs perfectly fine in Oracle. Notice the COUNTRY_ID foreign key in the second table doesn't have "NOT NULL".
Now to insert a row into the PROVINCE table, it's sufficient to only specify the PROVINCE_ID. However, if you chose to specify a COUNTRY_ID as well, it must exist already in the COUNTRY table.
By default there are no constraints on the foreign key, foreign key can be null and duplicate.
while creating a table / altering the table, if you add any constrain of uniqueness or not null then only it will not allow the null/ duplicate values.
Simply put, "Non-identifying" relationships between Entities is part of ER-Model and is available in Microsoft Visio when designing ER-Diagram. This is required to enforce cardinality between Entities of type " zero or more than zero", or "zero or one". Note this "zero" in cardinality instead of "one" in "one to many".
Now, example of non-identifying relationship where cardinality may be "zero" (non-identifying) is when we say a record / object in one entity-A "may" or "may not" have a value as a reference to the record/s in another Entity-B.
As, there is a possibility for one record of entity-A to identify itself to the records of other Entity-B, therefore there should be a column in Entity-B to have the identity-value of the record of Entity-B. This column may be "Null" if no record in Entity-A identifies the record/s (or, object/s) in Entity-B.
In Object Oriented (real-world) Paradigm, there are situations when an object of Class-B does not necessarily depends (strongly coupled) on object of class-A for its existence, which means Class-B is loosely-coupled with Class-A such that Class-A may "Contain" (Containment) an object of Class-A, as opposed to the concept of object of Class-B must have (Composition) an object of Class-A, for its (object of class-B) creation.
From SQL Query point of view, you can query all records in entity-B which are "not null" for foreign-key reserved for Entity-B. This will bring all records having certain corresponding value for rows in Entity-A alternatively all records with Null value will be the records which do not have any record in Entity-A in Entity-B.
Can a Foreign key be NULL?
Existing answers focused on single column scenario. If we consider multi column foreign key we have more options using MATCH [SIMPLE | PARTIAL | FULL] clause defined in SQL Standard:
PostgreSQL-CREATE TABLE
A value inserted into the referencing column(s) is matched against the values of the referenced table and referenced columns using the given match type. There are three match types: MATCH FULL, MATCH PARTIAL, and MATCH SIMPLE (which is the default). MATCH FULL will not allow one column of a multicolumn foreign key to be null unless all foreign key columns are null; if they are all null, the row is not required to have a match in the referenced table. MATCH SIMPLE allows any of the foreign key columns to be null; if any of them are null, the row is not required to have a match in the referenced table. MATCH PARTIAL is not yet implemented.
(Of course, NOT NULL constraints can be applied to the referencing column(s) to prevent these cases from arising.)
Example:
CREATE TABLE A(a VARCHAR(10), b VARCHAR(10), d DATE , UNIQUE(a,b));
INSERT INTO A(a, b, d)
VALUES (NULL, NULL, NOW()),('a', NULL, NOW()),(NULL, 'b', NOW()),('c', 'b', NOW());
CREATE TABLE B(id INT PRIMARY KEY, ref_a VARCHAR(10), ref_b VARCHAR(10));
-- MATCH SIMPLE - default behaviour nulls are allowed
ALTER TABLE B ADD CONSTRAINT B_Fk FOREIGN KEY (ref_a, ref_b)
REFERENCES A(a,b) MATCH SIMPLE;
INSERT INTO B(id, ref_a, ref_b) VALUES (1, NULL, 'b');
-- (NULL/'x') 'x' value does not exists in A table, but insert is valid
INSERT INTO B(id, ref_a, ref_b) VALUES (2, NULL, 'x');
ALTER TABLE B DROP CONSTRAINT IF EXISTS B_Fk; -- cleanup
-- MATCH PARTIAL - not implemented
ALTER TABLE B ADD CONSTRAINT B_Fk FOREIGN KEY (ref_a, ref_b)
REFERENCES A(a,b) MATCH PARTIAL;
-- ERROR: MATCH PARTIAL not yet implemented
DELETE FROM B; ALTER TABLE B DROP CONSTRAINT IF EXISTS B_Fk; -- cleanup
-- MATCH FULL nulls are not allowed
ALTER TABLE B ADD CONSTRAINT B_Fk FOREIGN KEY (ref_a, ref_b)
REFERENCES A(a,b) MATCH FULL;
-- FK is defined, inserting NULL as part of FK
INSERT INTO B(id, ref_a, ref_b) VALUES (1, NULL, 'b');
-- ERROR: MATCH FULL does not allow mixing of null and nonnull key values.
-- FK is defined, inserting all NULLs - valid
INSERT INTO B(id, ref_a, ref_b) VALUES (1, NULL, NULL);
db<>fiddle demo
I think it is better to consider the possible cardinality we have in the tables.
We can have possible minimum cardinality zero. When it is optional, the minimum participation of tuples from the related table could be zero, Now you face the necessity of foreign key values to be allowed null.
But the answer is it all depends on the Business.
The idea of a foreign key is based on the concept of referencing a value that already exists in the main table. That is why it is called a foreign key in the other table. This concept is called referential integrity. If a foreign key is declared as a null field it will violate the the very logic of referential integrity. What will it refer to? It can only refer to something that is present in the main table. Hence, I think it would be wrong to declare a foreign key field as null.
I think foreign key of one table also primary key to some other table.So it won't allows nulls.So there is no question of having null value in foreign key.

How can I share the same primary key across two tables?

I'm reading a book on EF4 and I came across this problem situation:
So I was wondering how to create this database so I can follow along with the example in the book.
How would I create these tables, using simple TSQL commands? Forget about creating the database, imagine it already exists.
You've been given the code. I want to share some information on why you might want to have two tables in a relationship like that.
First when two tables have the same Primary Key and have a foreign key relationship, that means they have a one-to-one relationship. So why not just put them in the same table? There are several reasons why you might split some information out to a separate table.
First the information is conceptually separate. If the information contained in the second table relates to a separate specific concern, it makes it easier to work with it the data is in a separate table. For instance in your example they have separated out images even though they only intend to have one record per SKU. This gives you the flexibility to easily change the table later to a one-many relationship if you decide you need multiple images. It also means that when you query just for images you don't have to actually hit the other (perhaps significantly larger) table.
Which bring us to reason two to do this. You currently have a one-one relationship but you know that a future release is already scheduled to turn that to a one-many relationship. In this case it's easier to design into a separate table, so that you won't break all your code when you move to that structure. If I were planning to do this I would go ahead and create a surrogate key as the PK and create a unique index on the FK. This way when you go to the one-many relationship, all you have to do is drop the unique index and replace it with a regular index.
Another reason to separate out a one-one relationship is if the table is getting too wide. Sometimes you just have too much information about an entity to easily fit it in the maximum size a record can have. In this case, you tend to take the least used fields (or those that conceptually fit together) and move them to a separate table.
Another reason to separate them out is that although you have a one-one relationship, you may not need a record of what is in the child table for most records in the parent table. So rather than having a lot of null values in the parent table, you split it out.
The code shown by the others assumes a character-based PK. If you want a relationship of this sort when you have an auto-generating Int or GUID, you need to do the autogeneration only on the parent table. Then you store that value in the child table rather than generating a new one on that table.
When it says the tables share the same primary key, it just means that there is a field with the same name in each table, both set as Primary Keys.
Create Tables
CREATE TABLE [Product (Chapter 2)](
SKU varchar(50) NOT NULL,
Description varchar(50) NULL,
Price numeric(18, 2) NULL,
CONSTRAINT [PK_Product (Chapter 2)] PRIMARY KEY CLUSTERED
(
SKU ASC
)
)
CREATE TABLE [ProductWebInfo (Chapter 2)](
SKU varchar(50) NOT NULL,
ImageURL varchar(50) NULL,
CONSTRAINT [PK_ProductWebInfo (Chapter 2)] PRIMARY KEY CLUSTERED
(
SKU ASC
)
)
Create Relationships
ALTER TABLE [ProductWebInfo (Chapter 2)]
ADD CONSTRAINT fk_SKU
FOREIGN KEY(SKU)
REFERENCES [Product (Chapter 2)] (SKU)
It may look a bit simpler if the table names are just single words (and not key words, either), for example, if the table names were just Product and ProductWebInfo, without the (Chapter 2) appended:
ALTER TABLE ProductWebInfo
ADD CONSTRAINT fk_SKU
FOREIGN KEY(SKU)
REFERENCES Product(SKU)
This simply an example that I threw together using the table designer in SSMS, but should give you an idea (note the foreign key constraint at the end):
CREATE TABLE dbo.Product
(
SKU int NOT NULL IDENTITY (1, 1),
Description varchar(50) NOT NULL,
Price numeric(18, 2) NOT NULL
) ON [PRIMARY]
ALTER TABLE dbo.Product ADD CONSTRAINT
PK_Product PRIMARY KEY CLUSTERED
(
SKU
)
CREATE TABLE dbo.ProductWebInfo
(
SKU int NOT NULL,
ImageUrl varchar(50) NULL
) ON [PRIMARY]
ALTER TABLE dbo.ProductWebInfo ADD CONSTRAINT
FK_ProductWebInfo_Product FOREIGN KEY
(
SKU
) REFERENCES dbo.Product
(
SKU
) ON UPDATE NO ACTION
ON DELETE NO ACTION
See how to create a foreign key constraint. http://msdn.microsoft.com/en-us/library/ms175464.aspx This also has links to creating tables. You'll need to create the database as well.
To answer your question:
ALTER TABLE ProductWebInfo
ADD CONSTRAINT fk_SKU
FOREIGN KEY (SKU)
REFERENCES Product(SKU)

Foreign key reference to a two-column primary key

I'm building a database that must work on MySQL, PostgreSQL, and SQLite. One of my tables has a two-column primary key:
CREATE TABLE tournament (
state CHAR(2) NOT NULL,
year INT NOT NULL,
etc...,
PRIMARY KEY(state, year)
);
I want a reference to the tournament table from another table, but I want this reference to be nullable. Here's how I might do it, imagining that a winner doesn't necessarily have a tournament:
CREATE TABLE winner (
name VARCHAR NOT NULL,
state CHAR(2) NULL,
year INT NULL
);
If state is null but year is not, or vice-versa, the table would be inconsistent. I believe the following FOREIGN KEY constraint fixes it:
ALTER TABLE winner ADD CONSTRAINT FOREIGN KEY fk (name, state) REFERENCES tournament (name, state);
Is this the proper way of enforcing consistency? Is this schema properly normalized?
Rule #1: ALWAYS SAY THE DATABASE YOU'RE USING
Ok, I'm going to suggest you look at the ON DELETE clause, and the MATCH clause. Because, Pg is fairly SQL compliant I'll point you to the current docs on CREATE TABLE.
Excerpt:
These clauses specify a foreign key
constraint, which requires that a
group of one or more columns of the
new table must only contain values
that match values in the referenced
column(s) of some row of the
referenced table. If refcolumn is
omitted, the primary key of the
reftable is used. The referenced
columns must be the columns of a
unique or primary key constraint in
the referenced table. Note that
foreign key constraints cannot be
defined between temporary tables and
permanent tables.
A value inserted into the referencing
column(s) is matched against the
values of the referenced table and
referenced columns using the given
match type. There are three match
types: MATCH FULL, MATCH PARTIAL, and
MATCH SIMPLE, which is also the
default. MATCH FULL will not allow one
column of a multicolumn foreign key to
be null unless all foreign key columns
are null. MATCH SIMPLE allows some
foreign key columns to be null while
other parts of the foreign key are not
null. MATCH PARTIAL is not yet
implemented.
In addition, when the data in the
referenced columns is changed, certain
actions are performed on the data in
this table's columns. The ON DELETE
clause specifies the action to perform
when a referenced row in the
referenced table is being deleted.
Likewise, the ON UPDATE clause
specifies the action to perform when a
referenced column in the referenced
table is being updated to a new value.
If the row is updated, but the
referenced column is not actually
changed, no action is done.
Referential actions other than the NO
ACTION check cannot be deferred, even
if the constraint is declared
deferrable. There are the following
possible actions for each clause:
Also, there is a major exception here with MS SQL -- which doesn't permit partial matches (MATCH SIMPLE and MATCH PARTIAL) behaviors in foreign keys (defaults and enforces MATCH FULL). There are workarounds where you create a MATCH FULL index on the part of the table that IS NOT NULL for any of the composite key's constituents.