SQL Server - Create FK Using a literal as one of the keys - sql

I have a code list table with a group name and key id. Instead of using discreet tables for every look-up (key/description pair), they are all in a single code_list table. I would like to generate a FK using a literal and column name as the relational key.
Example:
Order table -> "State" & order.state_id -> code_list.group_name & code_list.key_id.
The statement below, obviously does not work, but is an example of what I am trying to accomplish.
ALTER TABLE [dbo].[Order] WITH CHECK
ADD CONSTRAINT [FK_State_Code_List]
FOREIGN KEY('State', [State_Id])
REFERENCES [dbo].[Code_List] ([Group_Name], [Key_Id])
I am using SQL Server 2014

You can't use a literal value.
You could add a persisted computed column with the desired value and reference that in the FK definition, used in some super type / sub type models as this questioner demonstrates.
But you appear to be implementing the "one true lookup table" anti pattern here.
You should just have a separate table for State and a regular foreign key.

Related

How to make a general reference to the primary key column in oracle SQL?

I have multiple tables with a unique column name for each of their primary key such as: DeviceName, DeviceNumber, SwitchNumber, Etc.
There is another table which serves as an audit trail containing the changes from all tables, it lists the table name and the primary key value for each respective table as a reference i.e.
Table#2
TableName, InstanceNumber
I would like to use the information in table #2 to pull the respective records from each table in 'TableName' by referencing the 'InstanceNumber' attribute as the PK for each respective table without having to manually create a reference for each table's column name.
Is there a way I can do this? That is, create a query that references a 'general' column name to a table that points to the primary key column?
Select * from (TableName) where (PrimaryKeyColumn) = (InstanceNumber);
You can only do this using dynamic SQL -- in PL/SQL, that would be execute immediate.
Why not? Here is one reason. All the columns returned by a query need to be known when the query is compiled. That is, before any data is read. You are requesting a set of columns that depends on the table that is in the data. So, the columns are NOT known and the query cannot be compiled.

Sql change Data Type

There is one column named Line_no (smallint) now. I want to change this column data type is bigint ,but this column is primary key, and have so many tables has foreign key reference on it, so how to change it?, i need to change both Sql server and oracle database
First of all there's no easy way to do that currently. especially in Oracle, in order to change the data type, all the values of the field should be null. anyway the following process works for both Oracle and SQL Server:
make your database off line so that no operation can disturb our
process.
Add a new field, say line_num having your new data type.
update the the new field with the line_no values for all records.
write a Stored Procedure to drop all the FKs referencing current
PK, using meta data and this SP should write the add FK command to
dbms output, while it is looping, so that later you can execute them
to add these FKs again in step 9.
drop the primary key off the line_no field.
drop the field line_no.
rename the field
line_num to line_no.
add the primary key on the new field.
run the commands generated in step 4 to add all the FKs again.
make your db online :)
It depends on your DBMS. You may have to drop the foreign key constraints, alter the columns and re-create the constraints.

Setting referential tables in SQL Server 2008

I have two tables (A and B) that need to be related. The A has a int column that will be the foreign key column related to B table's primary key of tinyint. When I setup the relationship using SMS, I got the following error. How do I set this relationship up without changing the data type? Is it possible to cast A.FKey to int?
The following data type properties of column 'dbo.A.FKey' do not match
those of 'dbo.B.PKey'.
- Data type
- Length
- Precision
The datatypes must be the same on a relationship. I advise altering the datatype to match.
You can try creating a computed column in master table which cast pk column so it matches detailed column definition. Then add a unique constraint on this computes column. Finally, add fk in details table that refers computed column. However, it's much easier to alter table and make columns involved in relationship one type

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'))

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)