Foreign keys in SQL while using arrays - sql

I have a table 'person' having a attribute ID (primary key). I want to store an array of person IDs in another table. How to define the foreign key in that table referring to table 'person'?

In the creation or alteration of your table include: Foreign_key_name int FOREIGN KEY REFERENCES Person(ID), assuming that Person.ID is of type int.
The exact command syntax might differ depending on your database type.
A good guide giving examples for MySQL / SQL Server / Oracle / MS Access can be found here

Related

SQL Foreign Key based on column that specifies table

Suppose I have a table that contains a list of ids pointing to table names, with the following schema:
RemoteTables
============
id (Primary Key)
tableName (string)
Suppose I also have the following schema in another table:
AnotherTable
============
id (Primary Key)
remoteTableId (foreign key referencing RemoteTables)
remoteId ("special" foreign key)
where remoteId points to a row in the table specified by remoteTableId.
I have seen a few situations where I wanted to do this, but is there any built-in SQL support to manage the relationship in any way?
What you have is a special type of constraint here, because you are building a custom meta-database (data dictionary of sorts). So nothing "built in", per se.
Your best bet would be to enforce this through a trigger, although triggers on MySQL unfortunately are not always as easy as they ought to be.

SQL Server 2008: The columns in table do not match an existing primary key or unique constraint

I need to make some changes to a SQL Server 2008 database.
This requires the creation of a new table, and inserting a foreign key in the new table that references the Primary key of an already existing table. So I want to set up a relationship between my new tblTwo, which references the primary key of tblOne.
However when I tried to do this (through SQL Server Management Studio) I got the following error:
The columns in table 'tblOne' do not
match an existing primary key or
UNIQUE constraint
I'm not really sure what this means, and I was wondering if there was any way around it?
It means that the primary key in tblOne hasn't been properly declared - you need to go to tblOne and add the PRIMARY KEY constraint back onto it.
If you're sure that tblOne does have a PRIMARY KEY constraint, then maybe there are multiple tblOne tables in your DB, belonging to different schemas, and your references clause in your FK constraint is picking the wrong one.
If there's a composite key (which your comment would indicate), then you have to include both columns in your foreign key reference also. Note that a table can't have multiple primary keys - but if it has a composite key, you'll see a key symbol next to each column that is part of the primary key.
If you have a composite key the order is important when creating a FK, and sometimes the order is not how it is displayed.
What I do is go to the Keys section of the table1 and select script primary key as create to clipboard and then create FK using the order as shown in script
I've had this situation that led me to this topic. Same error but another cause. Maybe it will help someone.
Table1
ColA (PK)
ColB (PK)
ColC
Table2
ID (PK)
ColA
COLB
When trying to create foreign key in Table2 I've choose values from combobox in reverse order
Table1.ColB = Table2.ColB
Table1.ColA = Table2.ColA
This was throwing me an error like in topic name. Creating FK keeping order of columns in Primary key table as they are, made error disappear.
Stupid, but.. :)
If you still get that error after you have followed all advice from the above answers and everything looks right.
One way to fix it is by Removing your Primary keys for both tables, Save, Refresh, and add them again.
Then try to add your relationship again.
This Error happened with me When I tried to add foreign key constraint starting from PrimaryKey Table
Simpy go to other table and and create this foreign key constraint from there (foreign key Table)
This issue caught me out, I was adding the relationship on the wrong table. So if you're trying to add a relationship in table A to table B, try adding the relationship in table B to table A.
That looks like you are trying to create a foreign key in tblTwo that does not match (or participate) with any primary key or unique index in tblOne.
Check this link on MSDN regarding it. Here you have another link with a practical case.
EDIT:
Answwering to your comment, I understand you mean there are 2 fields in the primary key (which makes it a composite). In SQL it is not possible to have 2 primary keys on the same table.
IMHO, a foreign key field should always refer to a single register in the referenced table (i.e. the whole primary key in your case). That means you need to put both fields of the tblOne primary key in tblTwo before creating the foreign key.
Anyway, I have investigated a bit over the Internet and it seems SQL Server 2008 (as some prior versions and other RDBMS) gives you the possibility to reference only part of the primary key as long as this part is a candidate key (Not Null and Unique) and you create an unique constraint on it.
I am not sure you can use that in your case, but check this link for more information on it.
I have found that the column names must match.
Example:
So if tblOne has id called categoryId a reference in tblTwo must also be called categoryId.
_tblname, primary key name, foreign key_
tblOne, "categoryId", none
tblTwo, "exampleId", "categoryId"
I noticed this when trying to create foreign key between 2 tables that both had the column name "id" as primary key.
If nothing helps, then this could be the reason:
Considering this case:
Table A:
Column 1 (Primary Key)
Column 2 (Primary Key)
Column 3
Column 4
Table B:
Column a (Primary Key)
Column b
Column c
when you are defining a dependency B to A, then you are forced to respect the order in which the primaries are defined.
That's mean your dependency should look like this:
Table A Table B
Column 1 Column b
Column 2 Column c
AND NOT:
Table A Table B
Column 2 Column c
Column 1 Column b
then this will lead to the error you are encountering.
I've found another way to get this error. This can also happen if you are trying to make a recursive foreign key (a foreign key to the primary key in the same table) in design view in SQL Management Studio. If you haven't yet saved the table with the primary key it will return this message. Simply save the table then it will allow you to create the foreign key.
If you have data in your tables this could be the issue.
In my case I had some data in the Account table that I loaded at 3 pm, and some data in Contact table that I loaded at 3:10 pm, so Contact table had some values that weren't in my Account table yet.
I ended up deleting these values from the contact table and then managed to add a key without any problems.
Kindly also see that there are no existing data inside the table where the primary key is defined while setting the foreign key with another table column.
this was the cause of the error in my case.
I had to take backup empty the table set the relationship and then upload the data back.
sharing my experience
Was using ms sql smss

Can I put constraint on column without referring to another table?

I have a text column that should only have 1 of 3 possible strings. To put a constraint on it, I would have to reference another table. Can I instead put the values of the constraint directly on the column without referring to another table?
If this is SQL Server, Oracle, or PostgreSQL, yes, you can use a check constraint.
If it's MySQL, check constraints are recognized but not enforced. You can use an enum, though. If you need a comma-separated list, you can use a set.
However, this is generally frowned upon, since it's definitely not easy to maintain. Just best to create a lookup table and ensure referential integrity through that.
In addition to the CHECK constraint and ENUM data type that other mention, you could also write a trigger to enforce your desired restriction.
I don't necessarily recommend a trigger as a good solution, I'm just pointing out another option that meets your criteria of not referencing a lookup table.
My habit is to define lookup tables instead of using constraints or triggers, when the rule is simply to restrict a column to a finite set of values. The performance impact of checking against a lookup table is no worse than using CHECK constraints or triggers, and it's a lot easier to manage when the set of values might change from time to time.
Also a common task is to query the set of permitted value, for instance to populate a form field in the user interface. When the permitted values are in a lookup table, this is a lot easier than when they're defined in a list of literal values in a CHECK constraint or ENUM definition.
Re comment "how exactly to do lookup without id"
CREATE TABLE LookupStrings (
string VARCHAR(20) PRIMARY KEY
);
CREATE TABLE MainTable (
main_id INT PRIMARY KEY,
string VARCHAR(20) NOT NULL,
FOREIGN KEY (string) REFERENCES LookupStrings (string)
);
Now you can be assured that no value in MainTable.string is invalid, since the referential integrity prevents that. But you don't have to join to the LookupStrings table to get the string, when you query MainTable:
SELECT main_id, string FROM MainTable;
See? No join! But you get the string value.
Re comment about multiple foreign key columns:
You can have two individual foreign keys, each potentially pointing to different rows in the lookup table. The foreign key column doesn't have to be named the same as the column in the referenced table.
My common example is a bug-tracking database, where a bug was reported by one user, but assigned to be fixed by a different user. Both reported_by and assigned_to are foreign keys referencing the Accounts table.
CREATE TABLE Bugs (
bug_id INT PRIMARY KEY,
reported_by INT NOT NULL,
assigned_to INT,
FOREIGN KEY (reported_by) REFERENCES Accounts (account_id),
FOREIGN KEY (assigned_to) REFERENCES Accounts (account_id)
);
In Oracle, SQL Server and PostgreSQL, use CHECK constraint.
CREATE TABLE mytable (myfield INT VARCHAR(50) CHECK (myfield IN ('first', 'second', 'third'))
In MySQL, use ENUM datatype:
CREATE TABLE mytable (myfield ENUM ('first', 'second', 'third'))

Can there be constraints with the same name in a DB?

This is a follow-on question from the one I asked here.
Can constraints in a DB have the same name?
Say I have:
CREATE TABLE Employer
(
EmployerCode VARCHAR(20) PRIMARY KEY,
Address VARCHAR(100) NULL
)
CREATE TABLE Employee
(
EmployeeID INT PRIMARY KEY,
EmployerCode VARCHAR(20) NOT NULL,
CONSTRAINT employer_code_fk FOREIGN KEY (EmployerCode) REFERENCES Employer
)
CREATE TABLE BankAccount
(
BankAccountID INT PRIMARY KEY,
EmployerCode VARCHAR(20) NOT NULL,
Amount MONEY NOT NULL,
CONSTRAINT employer_code_fk FOREIGN KEY (EmployerCode) REFERENCES Employer
)
Is this allowable? Does it depend on the DBMS (I'm on SQL Server 2005)? If it is not allowable, does anyone have any suggestions on how to work around it?
No - a constraint is a database object as well, and thus its name needs to be unique.
Try adding e.g. the table name to your constraint, that way it'll be unique.
CREATE TABLE BankAccount
(
BankAccountID INT PRIMARY KEY,
EmployerCode VARCHAR(20) NOT NULL,
Amount MONEY NOT NULL,
CONSTRAINT FK_BankAccount_Employer
FOREIGN KEY (EmployerCode) REFERENCES Employer
)
We basically use "FK_"(child table)_(parent table)" to name the constraints and are quite happy with this naming convention.
Information from MSDN
That constraint names have to be unique to the schema (ie. two different schemas in the same database can both contain a constraint with the same name) is not explicitly documented. Rather you need to assume the identifiers of database objects must be unique within the containing schema unless specified otherwise. So the constraint name is defined as:
Is the name of the constraint. Constraint names must follow the rules for identifiers, except that the name cannot start with a number sign (#). If constraint_name is not supplied, a system-generated name is assigned to the constraint.
Compare this to the name of an index:
Is the name of the index. Index names must be unique within a table or view but do not have to be unique within a database. Index names must follow the rules of identifiers.
which explicitly narrows the scope of the identifier.
The other answers are all good but I thought I'd add an answer to the question in the title, i.e., "can there be constraints with the same name in a DB?"
The answer for MS SQL Server is yes – but only so long as the constraints are in different schemas. Constraint names must be unique within a schema.
I was always puzzled why constraint names must be unique in the database, since they seem like they're associated with tables.
Then I read about SQL-99's ASSERTION constraint, which is like a check constraint, but exists apart from any single table. The conditions declared in an assertion must be satisfied consistently like any other constraint, but the assertion can reference multiple tables.
AFAIK no SQL vendor implements ASSERTION constraints. But this helps explain why constraint names are database-wide in scope.
It depends on the DBMS.
For example on PostgreSQL, the answer is yes :
Because PostgreSQL does not require constraint names to be unique
within a schema (but only per-table), it is possible that there is
more than one match for a specified constraint name.
Source : https://www.postgresql.org/docs/current/static/sql-set-constraints.html
I've seen Foreign Keys constraint names equals on 2 different tables within the same schema.
Does it depend on the DBMS (I'm on SQL Server 2005)?
Yes, apparently it does depend on the DBMS.
Other answers say it's not permitted, but I have a MS SQL CE ("Compact Edition") database in which I accidentally successfully created two FK contraints, in two tables, with the same contraint name.
Good practice is to create index and constraint names specifying table name at the beginning.
There's 2 approaches, with index/constraint type at the beginning or at the end) eg.
UQ_TableName_FieldName
or
TableName_FieldName_UQ
Foreign keys names should also contain names of referenced Table/Field(s).
One of good naming conventions is to give table names in form of FullName_3LetterUniqueAlias eg.
Employers_EMR
Employees_EMP
BankAccounts_BNA
Banks_BNK
This give you opportunity to use "predefined" aliases in queries which improves readability and also makes Naming of foreign keys easier, like:
EMPEMR_EmployerCode_FK
BNKEMR_EmployerCode_FK

Is it possible to change SQL user-defined data type?

I have a bunch of tables using user-defined data type for PK column. Is it possible to change this type Using SQL Server 2005?
I would suggest that it is always possible to refactor poor or outmoded database designs, it simply depends on how much work you are willing to go to in order to do so.
If you are looking to replace the user-defined data with a surrogate key then you should be able to simply alter the existing table to contain a non-nullable identity column and this should cause all of the existing records to be assigned a new key automatically.
Once the new field is populated with unique id's, if you need to move out and replace foreign key references to this table, then I would simply alter those tables to contain the new field and use something like the following:
UPDATE child_table
SET new_fk_val =
SELECT new_pk_val
FROM parent_table
WHERE parent_table.old_pk_val = child_table.old_fk_val
Once that step is complete, then you could drop the old foreign key constraint, drop the old foreign key column, drop the old primary key column, establish the new primary key constraint, and then establish the new foreign key constraint.
Of course, if the old version of the parent and child tables relationship was such that you have invalid records in the child table you may have to do something like the following:
DELETE FROM child_table
WHERE old_fk_val NOT IN
( SELECT old_pk_val FROM parent_table)