Swap two values in an indexed field - sql

Is there a simple way (using a SQL query or VBA with a DAO recordset) to swap two values in an indexed field? In my case said field is the primary key of a small table (not expected to exceed 30 records). Expected input and output below.
Before:
StageNumber | Description
------------+--------------------------
01 | First Thing
02 | Second Thing
After:
StageNumber | Description
------------+--------------------------
02 | First Thing
01 | Second Thing
I'm aware this looks like I could simply switch the descriptions rather than the StageNumber but the StageNumber is used as a foreign key into another table with cascading updates specified in the relationship so simply switching the description would cause 'child' records to be associated with the wrong 'parent'.
Ideally this would be achieved with a single UPDATE..SET query but for the life of me I can't figure out what the syntax for such an operation would be without causing a primary key violation error.

This highlights one of the perils of using a Natural Keys as a primary key, when there is a risk of change of identity.
Assuming there might be similar changes in future, an alternative is to add a new Surrogate PK to the Stage table (e.g. ID as an integer AUTONUMBER), and then:
Add a new StageId foreign key column to all tables referencing Stage.
Then update the StageId column to assign the correct StageId via a lookup join via the existing foreign key (StageNo)
Then drop the FOREIGN KEY constraint on the existing StageNumber foreign key columns in the referencing tables.
Drop the PRIMARY KEY on Stage.StageNumber and change the PK to Stage.Id
Then re-add the FOREIGN KEY constraint on the new StageId foreign key columns in the referencing tables.
You are now free to change the value of the StageNumber column as it is no longer part of a foreign key.

Update StageNumber of the first record to an arbitrary number not in use.
Update StageNumber of the second record to that the first record had.
Update StageNumber of the first record to that the second records had.
Or, in two steps:
Update both StageNumbers to arbitrary numbers not in use.
Update both StageNumbers to that the other record had.

Related

SQL: in CHECK, check varchar value in another table using entered foreign key

One of the values to be inserted into a table is a foreign key. I need to figure out how to, inside the CHECK clause, check if a value in another table is equal to a specific value using the foreign key (which is unique in the other table).
Example Diagram
As an example, the MonkeySpecies table has a unique primary key. I need to make it so that the Monkey table can only be added to if the SpeciesID in the MonkeySpecies table is not 'extinct'.

Which column for foreign key: id or any other column and why?

TL;DR
Should a foreign key always refer to the id column of another table? Why or why not? Is there a standard rule for this?
Is there a cost associated with using any other unique column other than id column for foreign key? Performance / storage? How significant? Is it frowned in the industry?
Example: this is the schema for my sample problem:
In my schema sometimes I use id column as the foreign key and sometimes use some other data column.
In vehicle_detail table I use a unique size column as a foreign key from vehicle_size table and unique color column as the foreign key from vehicle_color table.
But in vehicle_user I used the user_identifier_id as a foreign key which refers to id primary key column in user_identifier table.
Which is the correct way?
On a side note, I don't have id columns for the garage_level, garage_spaceid, vehicle_garage_status and vehicle_parking_status tables because they only have one column which is the primary key and the data they store is just at most 15 rows in each table and it is probably never going to change. Should I still have an id column in those ?
A foreign key has to target a primary key or unique constraint. It is normal to reference the primary key, because you typically want to reference an individual row in another table, and the primary key is the identifier of a table row.
From a technical point of view, it does not matter whether a foreign key references the primary key or another unique constraint, because in PostgreSQL both are implemented in the same way, using a unique index.
As to your concrete examples, there is nothing wrong with having the unique size column of vehicle_size be the target of a foreign key, although it begs the question why you didn't make size the primary key and omit the id column altogether. There is no need for each table to have an id column that is the automatically generated numeric primary key, except that there may be ORMs and other software that expect that.
A foreign key is basically a column of a different table(it is always of a different table, since that is the role it serves). It is used to join/ get data from a different table. Think of it like say school is a database and there are many different table for different aspects of student.
say by using Admission number 1234, from accounts table you can get the fees and sports table you can get the sports he play.
Now there is no rule that foreign key should be id column, you can keep it whatever you want. But,to use foreign key you should have a matching column in both tables therefore usually id column is only used. As I stated in the above example the only common thing in say sports table and accounts table would be admission number.
admn_no | sports |
+---------+------------+
| 1234 | basketball
+---------+---------+
| admn_no | fees |
+---------+---------+
| 1234 | 1000000 |
+---------+---------+
Now say using the query\
select * from accounts join sports using (admn_no);
you will get:
+---------+---------+------------+
| admn_no | fees | sports |
+---------+---------+------------+
| 1234 | 1000000 | basketball |
+---------+---------+------------+
PS: sorry for bad formatting
A foreign key is a field or a column that is used to establish a link between two tables. A FOREIGN KEY is a column (or collection of columns) in one table, that refers to the PRIMARY KEY in another table.
There is no rule that it should refer to a id column but the column it refers to should be the primary key. In real scenarios, it usually refers to Id column as in most cases it is the primary key in the tables.
OP question is about "correct way".
I will try to provide some kind of summary from existing comments and answers, general DO and general DONT for FKs.
What was already said
A. "A foreign key has to target a primary key or unique constraint"
Literally from Laurenz Albe answer and it was noted in comments
B. "stick with whatever you think will change the least"
It was noted by Adrian Klavier in comments.
Notes
There is no such general rule that PK or unique constraint must be defined on a single column.
So the question title itself must be corrected: "Which column(s) for foreign key: id or any other column(s) and why?"
Let's talk about "why".
Why: General DO, general DONT and an advice
Is there a cost associated with using any other unique column other than id column for foreign key? Performance / storage? How significant? Is it frowned in the industry?
General DO: Analyze requirements, use logic, use math (arithmetics is enough usually). There is no a single database design that's always good for all cases. Always ask yourself: "Can it be improved?". Never be content with design of existing FKs, if requirements changed or DBMS changed or storage options changed - revise design.
General DONT: Don't think that there is a single correct rule for all cases. Don't think: "if that worked in that database/table than it will work for this case too".
Let me illustrate this points with a common example.
Example: PK on id uuid field
We look into database and see a table has a unique constraint on two fields of types integer (4 bytes) + date (4 bytes)
Additionally: this table has a field id of uuid type (16 bytes)
PK is defined on id
All FKs from other tables are targeting id field
It this a correct design or not?
Case A. Common case - not OK
Let's use math:
unique constraint on int+date: it's 4+4=8 bytes
data is never changed
so it's a good candidate for primary key in this table
and nothing prevents to use it for foreign keys in related tables
So it looks like additional 16 bytes per each row + indexes costs is a mistake.
And that's a very common mistake especially in combination of MSSQL + CLUSTERED indexes on random uuids
Is it always a mistake?
No.
Consider latter cases.
Case B. Distributed system - OK
Suppose that you have a distributed system:
ServerA, ServerB, ServerC are sources of data
HeadServer - is data aggregator
data on serverA-ServerC could be duplicated: the same record could exists on several instances
aggregated data must not have duplicates
data for related tables can come from different instances: data for table with PK from serverA and data for tables with FKs from serverB-serverC
you need to log from where each record is originated
In such case existence of PK on id uuid is justified:
unique constraint allows to deduplicate records
surrogate key allows related data come from different sources
Case C. 'id' is used to expose data through API - OK
Suppose that you have an API to access data for external consumers.
There is a good unique constraint on:
client_id: incrementing integer in range 1..100000
invoice_date: dates '20100101'..'20210901'
And a surrogate key on id with random uuids.
You can create external API in forms:
/server/invoice/{client_id}/{invoice_date}
/server/invoice/{id}
From security POV /{id} is superior by reasons:
it's impossible to deduce from one uuid value existence of other
it's easier to implement authorization system for entities of different types. E.g. entityA has natural key on int, entityB on bigint' and entityC on int+ byte+date`
In such case surrogate key not only justified but becames essential.
Afterword
I hope that I was clear in explanation of main correct principle: "There is no such thing as a universal correct principle".
An additional advice: avoid CASCADE UPDATE/DELETEs:
Although it depends on DBMS you use.
But in general :
"explicit is better than implicit"
CASCADEs rarely works as intended
when CASCADES works - usually they have performance problems
Thank you for your attention.
I hope this helps somebody.

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

Database table id-key Null value and referential integrity

I'm learning databases, using SQLce. Got some problems, with this error:
A foreign key value cannot be inserted because a corresponding primary key value does not exist.
How does the integrity and acceptance of data work when attempting to save a data row that does not have specified one foreign key. Isn't it possible to set it to NULL in some way, meaning it will not reference the other table? In case, how would I do that? (For an integer key field)
Also, what if you save a row with a valid foreign key that corresponds to an existing primary key in other table. But then decide to delete that entry in this other table. So the foreign key will no longer be valid. Will I be allowed to delete? How does it work? I would think it should then be simply reset to a null value.. But maybe it's not that simple?
What you need to do is insert your data starting from the parent down.
So if you have an orders table and an items table that refers to orders, you have to create the new order first before adding all the children to the list.
Many of the data access libraries that you can get (in C# there is Linq to SQL) which will try and abstract this problem.
If you need to delete data you actually have to go the other way, delete the items before you delete the parent order record.
Of course, this assumes you are enforcing the foreign key, it is possible to not enforce the key, which might be useful during a bulk delete.
This is because of "bad data" you have in the tables. Check if you have all corresponding values in the primary table.
DBMS checks the referential integrity for ensuring the "correctness" of data within database.
For example, if you have a column called some_id in TableA with values 1 through 10 and a column called some_id in TableB with values 1 through 11 then TableA has no corresponding value (11) for that which you have already in TableB.
You can make a foreign key nullable but I don't recommend it. There are too many problems and inconsistencies that can arise. Redesign your tables so that you don't need to populate the foreign key for values that don't exist. Usually you can do that by moving the column to a new table for example.

Understanding Update and Delete Rules for Relationships in SSMS 2008

I am confused about what means the update and delete rule in SQL Server 2008 Management Studio when we define foreign key constraints. I also did not find related help documents (e.g. F1 help).
Here is the screen snapshot. Appreciate if anyone could describe what do they mean and recommend some related documents to read. :-)
The foreign key defines a parent - child relationship between two tables. The primary key in the parent table is the foreign key in the up to n child table rows.
Now if that primary key in the parent table gets UPDATE, the UPDATE RULE kicks in. Either all the child rows are also updated, set to NULL or whatever. Best practice however is to have a primary key that NEVER changes (a fixed ID or something), so that's the less important rule.
The more important one is the DELETE rule - what if the parent row is deleted (e.g. the Order is deleted)? You can either also delete all child rows (all the Order line items) with CASCADE DELETE, or you can set their foreign key to NULL (they don't have a parent anymore) - that's totally up to your concrete scenario.
In the Order/order lines scenario, it might be totally useful to delete the order lines when the complete order gets deleted, but you probably don't want to delete a product, just because an order that references it has been deleted - there's no one single CORRECT answer - it depends on your scenario and your app.
Marc
It looks like the documentation is at Foreign Key Relationships Dialog Box.
BTW, F1 help worked fine for me in SSMS 2008. It took me right to the above page (after I searched for 1/2 hour online, of course).
A foreign key field can only store null or a value defined by the primary key field.
If you try to change the foreign key value to something not defined by a primary key you will get an error. Likewise if you try to change a primary key which has foreign key dependencies you will get an error... as an example
Models table
modelID (primary key) model
1 Jeep
2 Ford
Customer table
id customer modelID (foreign key of Models.modelID)
1 1234 1
2 2345 2
If you try to delete the Jeep record from Models you will get an error because customer 1234 has a modelID set to 1, and this if the foreign key. Likewise if I try to update customer 1234 to have a modelID of 3 it will throw an error because there is no primary key in the Models table having a value of 3
Check this out