Reorder composition of composite primary key - sql

I have a table
documents
(
year int not null,
number int not null,
document_types_id int not null,
...
)
The primary key is year + number + document_types_id.
I think that a better primary key would be year + document_types_id + number. Is there a way to reorder this composition (not columns in table, PK and FK combination) without deleting and recreation of PK, because this PK is used as a FK in many other tables.
Thanks.

Your foreign keys are referencing your primary key, so your foreign keys are 3-dimensional (year + number + document_types_id). If you are going to get rid of a dimension then even if you try to modify your primary key your constraints will tell you that you can't get rid of the given column, so you should handle your foreign keys first and then you can modify your primary key. Steps:
Write all your foreign keys into a list to enable you to know which were the foreign keys before.
Get rid of all the foreign keys referencing your primary key
Modify/recreate your primary key
Recreate your foreign keys according to the new version of your primary key.

You have to drop the primary key first to alter it later. Otherwise you get a message, that there can't be two primary keys on one table.
But that's no problem, just do
Alter Table myTable NOCHECK Constraint All
then alter your tables as you like, then do
Alter Table myTable CHECK Constraint ALL
and you're fine.
The equivalent in MySQL would be:
SET FOREIGN_KEY_CHECKS = 0;
and
SET FOREIGN_KEY_CHECKS = 1;

If dropping the FK on other tables is a problem, then you can create a non-clustered index with those columns in that order and provide hints (WITH INDEX(ALTER TABLE syntax leaves no scope for an ALTER CONSTRAINT statement.

No. In the relational model, there is no meaningful ordering to the attributes in a key. But in SQL, there is. The correspondence of columns of a foreign key, to the columns of the primary or unique key the FK references, is by ordinal position, not by name.
So the ordering of the columns in the key declaration is meaningful, and if that meaning/ordering is currently used effectively, then you cannot change it without breaking the current use.
Besides. That the theory attaches no meaning to the ordering of the key attributes/columns, is not without reason. What exactly do you think is "better" with your "re-ordered" key, compared to the existing one ?

Related

Is it possible to create one index for both primary and foreign key?

Let's suppose we have two tables A and B and between them one-to-one relation.
CREATE TABLE IF NOT EXISTS A
(
ID INT UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (ID)
);
CREATE TABLE IF NOT EXISTS B
(
ID INT UNSIGNED NOT NULL,
PRIMARY KEY (ID),
FOREIGN KEY (ID) REFERENCES A(ID)
ON UPDATE CASCADE ON DELETE CASCADE
);
B.ID key will be used as foreign key in tables about which A doesn't know. When row is deleted from A there also will be deletion from other tables that are linked to B. As we see in B one column is at the same time primary and foreign key. As I know keys use indexes. So, is it possible to make these two keys use the same index? Does it depend on RDBMS? Or there is something wrong in my understanding?
As I know [foreign] keys use indexes
This is false. I am guessing that your experience with databases is limited to MySQL/MariaDB. These are two databases where a foreign key definition does created an index on the referencing table.
In most databases, a foreign key definition does NOT create an index on the referencing table. Another difference is that most databases (and I'm pretty sure the standard as well) requires that the referenced key be either a primary key or unique key. That doesn't affect you in this case, but it is another deviation from the standard in MySQL in this area.

How to manage postgresql foreign keys?

I need some advice on SQL structure on Postgresql.
I have those two tables :
DROP TABLE IF EXISTS "public"."attribute_value";
CREATE TABLE "public"."attribute_value"
(
"id" INTEGER NOT NULL,
"attribute_id" INTEGER NOT NULL,
"value" CHARACTER VARYING(100) NULL
);
--*****************************************************
DROP TABLE IF EXISTS "public"."product_attribute";
CREATE TABLE "public"."product_attribute"
(
"product_id" INTEGER NOT NULL,
"attribute_value_id" INTEGER NOT NULL,
"attribute_id" INTEGER NOT NULL
);
I added no constraints on purpose.
I need a foreign key on the child table product_attribute.attribute_value_id referencing the parent table attribute_value.id. The best practice is to create a primary key on the field attribute_value.id (maybe with a sequence), or to CREATE UNIQUE INDEX on attribute_value.id ?
I first thought indexes were only special lookup tables that the database search engine can use to speed up data retrieval. But when I played with foreign keys, I found that creating an unique index allowed me to avoid error "there is no unique constraint matching given keys for referenced table blablabla" because a foreign key is not supposed to point to a non unique value. Should indexes be used to create foreign keys then ?
I also need a foreign key on the child table product_attribute.attribute_id referencing parent table attribute_value.attribute_id. The problem is that attribute_value.attribute_id is not unique. But all the rows in product_attribute.attribute_id must not take any value out of attribute_value.attribute_id's possible values. How should I do ?
Every table should have a primary key. Don't join the legion of people who complain about duplicate rows in their tables.
So make id the primary key of attribute_value, then you can create a foreign key constraint.
Constraints are implemented by unique indexes, so technically they are almost the same. Still you need a constraint and not just a unique index as the target of a foreign key constraint.
About attribute_id: that should not be a foreign key constraint between the two tables from your question, but both tables should have a foreign key referencing yet another table (attribute?).

Can FOREIGN KEY be omitted in PostgreSQL when using REFERENCES?

I'm wondering if there's any (maybe subtle) difference between these two SQL statements:
CREATE TABLE profiles (
profile_id SERIAL PRIMARY KEY NOT NULL,
bio TEXT,
user_id INTEGER NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(user_id)
);
and
CREATE TABLE profiles (
profile_id SERIAL PRIMARY KEY NOT NULL,
bio TEXT,
user_id INTEGER NOT NULL REFERENCES users(user_id)
);
I've noticed that when I create a table in Postico with the first notation, but look at the DDL of the created profiles table later, the FOREIGN KEY is removed and I end up with the shorter second notation.
Create table with FOREIGN KEY:
DDL view doesn't show FOREIGN KEY:
So, I'm wondering (and seeking confirmation) that the two statements are in fact 100% equivalent or if there are some subtle differences in what they do to the DB.
Any pointer to official resources (and maybe also how that differs from MySQL) would be appreciated.
The two samples you show do the same thing, just with a different syntax.
The first method is called table constraint, the second column constraint, but the latter name is somewhat misleading because the constraint is on the table as well.
The main difference is that the column constraint syntax is shorter, but cannot be used for all constraints: if you have for example a primary key that contains two columns, you have to write it in the table constraint syntax.
DDL view doesn't show FOREIGN KEY
DDL view created by unknown third-party tool in not an argument.
See fiddle. Foreign key exists in both cases. Moreover, I do not see the result difference for both DDL queries.
PS. As a recommendation - always specify the constraint name explicitly. What if you need to delete it? It is problematic without the constraint name...
In PostgreSQL, you define a foreign key through a foreign key constraint. A foreign key constraint indicates that values in a column or a group of columns in the child table match with the values in a column or a group of columns of the parent table. We say that a foreign key constraint maintains referential integrity between child and parent tables.
This may explain to you better or you can read about Foreign Keys documentation .

What is difference between foreign key and reference key?

I am very confused about those two terms. Are they the same or different?
Some books and people say they are the same and others say they are different.
I tried but couldn't find a conclusive answer.
I am supposing that you are talking about using the REFERENCES where the FOREIGN KEY keyword is not used when constraining a column inline, which is called a column-level foreign key constraint, eg.
author_id INTEGER REFERENCES author(id)
... instead of the table-level foreign key constraint, which is placed after the column declarations ...
author_id INTEGER,
FOREIGN KEY(author_id) REFERENCES author(id)
The answer is, that it is simply shorthand syntax for the same thing. The main concern when altering between the two should be readability.
For more advanced use, it might be relevant that only table-level foreign key constraints can describe constraints on multiple keys at once, where all must be present in the referenced table.
Do note that MySQL 'parses but ignores “inline REFERENCES specifications” (as defined in the SQL standard) where the references are defined as part of the column specification', meaning that only the table-level foreign key constraint will work.
Both Postgres and Microsoft's SQL Server respect both column- and table-level foreign key constraints.
A foreign key must refer to a primary key.
When using REFERENCES constraint simply, then it isn't necessary that the referenced key be a primary key.
"Reference key" isn't a normal technical term in relational modeling or in SQL implementation in US English.
A foreign key "references" a key in some other table; could that be where the confusion comes from?
You don't really call something a reference key... They are the same thing... you might see the word references used for example in sqlite: you might use syntax like this to start a db of authors and books. This lets you show that one author can have many books. This tells the db that the books.author_id (defined a couple of lines up) references author.id
CREATE TABLE 'author' (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
firstname varchar(255)
lastname varchar(255)
);
CREATE TABLE 'books' (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
author_id INTEGER,
title varchar(255),
published date,
FOREIGN KEY(author_id) REFERENCES author(id)
);
In terms of standard SQL, both result in a foreign key constraint.
One form is a table constraint, meaning it can apply to one or more columns. You would need this to reference a table that has a multi-column primary key:
CREATE TABLE child (
id int PRIMARY KEY,
parent_id int,
date date,
FOREIGN KEY (parent_id, date) REFERENCES parent(id, date)
);
The other form is a column constraint, meaning it can only apply to the single column it is defined with. It cannot be used to reference a table with a multi-column primary key.
CREATE TABLE child (
id int PRIMARY KEY,
parent_id int REFERENCES parent(id)
);
The above syntax works exactly the same as if you declared a table constraint for a single column (supposing the RDBMS supports this type of column constraint), as follows:
CREATE TABLE child (
id int PRIMARY KEY,
parent_id int,
FOREIGN KEY (parent_id) REFERENCES parent(id)
);
It frequently causes confusion for users of MySQL and its InnoDB storage engine, that the latter column-constraint style is not supported. You must define a table-level constraint for a foreign key, even if it is a single-column constraint. This has been a strange behavior of MySQL since its earliest days, that some constraint syntax is valid, but results in no constraint. See discussion here: https://bugs.mysql.com/bug.php?id=17943
The only and most important difference between the two keywords 'FOREIGN KEY" and "REFERENCES" keywords is though both of them make the data to be child data of the parent table, the "FOREIGN KEY" is used to create a table level constraint whereas REFERENCES keyword can be used to create column level constraint only. Column level constraints can be created only while creating the table only. But table level constraints can be added using ALTER TABLE command.
Perhaps you are using the term "reference key" somewhat loosely?
A foreign key value in one row is said to "reference" the row that contains the corresponding key value. Note the word "reference" in the prior sentence is a verb, so we may say we have a referencing foreign key value and a referenced key value.
Although it is the key values, rather than the table key constraint, that is being referenced, I suppose loosely speaking we could say "referenced key" to mean the rows that comprise the values that may potentially be referenced. I then see how "referenced key" could become "referenced key" but not belie its origin.
There are 2 ways to declare a foreign key(s):
if the foreign key is a SINGLE attribute:
REFERENCES ()
if foreign keys are a LIST of attributes
FOREIGN KEY () REFERENCES
A foreign key "references" a key in some other table. That key in some other table is called Referenced key. You'll probably hear a lot about this if you're using Graphic feature on phpmyadmin.
The Reference Key is the primary key that is referenced in the other table.
On the other hand, Foreign Key is how you link the second table to the primary tables Primary Key (or Reference Key).

Trouble understanding SQL (Oracle) create table code

I am aware of Oracle's create table syntax
CREATE TABLE MyTable(
id int primary key,
...
);
This will create a table called MyTable with an int primary key. So, nothing new here.
but I am having difficulties understanding the following query:
CREATE TABLE departament (
cod_dept INTEGER CONSTRAINT dept_key PRIMARY KEY,
dept_name CHAR(15) NOT NULL,
admission DATE NOT NULL,
localization CHAR(20))
When I look up on Oracle's SQL Developer software on departement's table, I can see 4 columns: cod_dept, dept_name, admission and localization. On the constraints tab, I can also see dept_key, but I am confused as to what this might mean. What is dept_key purpose here?
Edit
Ok, seems it is a way to define the name of the constraint you're adding to the table. My next question is why don't you just call it the same name as the primary key column? From what I've seen it seems Oracle by default just creates a random name for the constraint!
Thanks
When you write id int primary key, Oracle will create a primary key constraint to ensure uniqueness of primary key values. All constraints have names, so in this case Oracle assigns an autogenerated name to this constraint. But you can set a name of this constraint explicitly using the CONSTRAINT syntax:
cod_dept INTEGER CONSTRAINT dept_key PRIMARY KEY
This name may be used later to refer to the constraint, for example, to delete or modify it:
ALTER TABLE department DROP CONSTRAINT dept_key;
EDIT:
Constraint names are unique across the schema, so Oracle can't just use the name of primary key column as a constraint name.
Primary keys can be explicitly be named. dept_key is just a name.
dept_key is the name of the primary key constraint. That means cod_dept is the unique identifier for your table, the mechanism for identifying a row, and so it can only have one occurrence of any given value.
That is the constraint you created representing the primary key.
A table is made up of:
Columns (where the data lives)
Indexes (indexed copies of the data used for faster searching)
Constraints (rules about what data can be in the table, including PK, FK, and check constraints).
dept_key is the name of the constraint. You specified the name here : "INTEGER CONSTRAINT dept_key PRIMARY KEY," so it will create a constraint with the name dept_key.
Another syntax for the same would be to write the following after your CREATE TABLE instruction.
ALTER TABLE department
ADD CONSTRAINT dept_key PRIMARY KEY (cod_dept)
dept_key is then the name of the constraint you created to be the primary key for this table. In order for a database engine to know the primary key, and to index it for fastest results and so forth, it needs to create a known constraint that is indexed. Here, it is you who has given the name which is dept_key.
For you kind information, it is often seen to write PK_[table name] for primary keys constraints and FK_[current_table_name]_[foreign_table_name] for foreign keys constraints.
Hope this helps! =)
I think whenever we create a Primary Key value then by default Oracle will crate constraint for it with the same name but it looks like that u are creating constraint with some other name.
Thank You