Skip to content

Conversation

@andreyaksenov
Copy link
Contributor

@andreyaksenov andreyaksenov commented Aug 29, 2023

Updated the section about foreign key constraints: https://docs.d.tarantool.io/en/doc/sql-table-constraint/reference/reference_sql/sql_statements_and_clauses/#sql-foreign-key

Changes:

  • Updated the syntax used for foreign key constraints - removed deprecated referencing options.
  • Added a syntax when a constraint is created in a column definition.
  • Added a note with deprecated referencing options.
  • Added a testable code sample with constraint error examples.
  • Tried to make the entire section a bit clearer.

@andreyaksenov andreyaksenov linked an issue Aug 29, 2023 that may be closed by this pull request
@andreyaksenov andreyaksenov force-pushed the sql-table-constraint branch 9 times, most recently from a8f4b43 to 05d5935 Compare August 30, 2023 10:38
@andreyaksenov andreyaksenov requested a review from ImeevMA August 30, 2023 11:09
Copy link

@ImeevMA ImeevMA left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the patch! I have a few comments, please look at them.

-- create_parent_start
CREATE TABLE author (
id INTEGER PRIMARY KEY,
name VARCHAR(100) NOT NULL
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest using STRING instead of VARCHAR(...) here and below, since our SQL does not support fixed length string values and will automatically replace them with STRING.

Constraint Conflict Clauses
The referenced column names must be defined in the referenced table and have similar data types.
The values in the referencing columns must equal values in the referenced columns of the referenced table,
or at least one of the referencing columns must contain ``NULL``.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is currently not the case. This describes MATCH SIMPLE, which is usually the default. However, we only support MATCH FULL, which requests a full match.


If behavior is ROLLBACK: the statement is rolled back, and the first statement is rolled back,
and there is an error message. The table now contains nothing.
On an attempt to delete an author that already has books in the ``book`` table, the following error is raised:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error shown is actually not what I expected from the description. This is a new limitation for FKs: referencing fields must now have an index in order to remove anything from the referenced space. Otherwise, we will not be able to remove from the referenced space, even if the row is not referenced. For example, if we add (3, 'Alexander Pushkin') to the author space and do not add anything to the book space, we won't be able to remove the added row. To remove it, we need to create an index on book.author_id.

To receive expected error I suggest to replace

        box.execute([[
            -- create_child_start
            CREATE TABLE book (
                id INTEGER PRIMARY KEY,
                title VARCHAR(200) NOT NULL,
                author_id INTEGER NOT NULL,
                FOREIGN KEY (author_id)
                    REFERENCES author (id)
            );
            -- create_child_end
        ]])

by

        box.execute([[
            -- create_child_start
            CREATE TABLE book (
                id INTEGER PRIMARY KEY,
                title VARCHAR(200) NOT NULL,
                author_id INTEGER NOT NULL UNIQUE,
                FOREIGN KEY (author_id)
                    REFERENCES author (id)
            );
            -- create_child_end
        ]])

and mention why we add UNIQUE constraint here.

Then the error will be:
'Foreign key ''fk_unnamed_BOOK_1'' integrity check failed: tuple is referenced'

A foreign key constraint is defined on the child table that references the parent table's column values.

There is a shorthand: specifying REFERENCES in a :ref:`column definition <sql_column_def_constraint>`.
Foreign key constraints look like this:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that the described FK constraint is known as the FK tuple constraint. What about the FK field constraint? I'm not sure if the FK description should be duplicated due to different types of constraints, but they have different error descriptions and are described differently in '_space', so at least add a quick overview of that and links to 'tuple constraint' and ' field constraint ' looks like a good idea.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this requires some investigation, created a separate ticket: #3703

Copy link
Contributor

@p7nov p7nov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

FOREIGN KEY constraints look like this: |br|
:samp:`FOREIGN KEY ({referencing-column-name} [, {referencing-column-name}...]) REFERENCES {referenced-table-name} [({referenced-column-name} [, {referenced-column-name}...]]) [MATCH FULL] [update-or-delete-rules]`
A foreign key is a constraint that can be used to enforce data integrity across related tables.
A foreign key constraint is defined on the child table that references the parent table's column values.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.. COMMENT
Constraint Conflict Clauses are temporarily disabled.
However, the description is here, as a big comment.
With :doc:`2.11.0 </release/2.11.0>`, the following referencing options aren't supported anymore:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since 2.11.0?

This example shows how to create a relation between the parent and child tables through a single-column foreign key:

FAIL -- return an error but do not do statement rollback.
1. First, create a parent ``author`` table:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: "first", "then", and similar words are usually redundant in procedures with numbered steps.
Let's keep it shorter

.. _sql_foreign_key:

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Table Constraint Definition for foreign keys
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe fix capitalization in this and previous heading while we are here?
image

@andreyaksenov andreyaksenov merged commit 19b21e2 into latest Sep 12, 2023
@andreyaksenov andreyaksenov deleted the sql-table-constraint branch September 12, 2023 07:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SQL: document changes in parsing rules

4 participants