Using references in MYSQL - sql

I got an answer to another question here:
DB Schema For Chats?
It's a great answer, but I am not understanding the bit about references. I can do SQL statements but I have never used references.
What are they used for?
How are they used?
Give an example please

The REFERENCES keyword is part of a foreign key constraint and it causes MySQL to require that the value(s) in the specified column(s) of the referencing table are also present in the specified column(s) of the referenced table.
This prevents foreign keys from referencing ids that do not exist or were deleted, and it can optionally prevent you from deleting rows whilst they are still referenced.
A specific example is if every employee must belong to a department then you can add a foreign key constraint from employee.departmentid referencing department.id.
Run the following code to create two test tables tablea and tableb where the column a_id in tableb references the primary key of tablea. tablea is populated with a few rows.
CREATE TABLE tablea (
id INT PRIMARY KEY,
foo VARCHAR(100) NOT NULL
) Engine = InnoDB;
INSERT INTO tablea (id, foo) VALUES
(1, 'foo1'),
(2, 'foo2'),
(3, 'foo3');
CREATE TABLE tableb (
id INT PRIMARY KEY,
a_id INT NOT NULL,
bar VARCHAR(100) NOT NULL,
FOREIGN KEY fk_b_a_id (a_id) REFERENCES tablea (id)
) Engine = InnoDB;
Now try these commands:
INSERT INTO tableb (id, a_id, bar) VALUES (1, 2, 'bar1');
-- succeeds because there is a row in tablea with id 2
INSERT INTO tableb (id, a_id, bar) VALUES (2, 4, 'bar2');
-- fails because there is not a row in tablea with id 4
DELETE FROM tablea WHERE id = 1;
-- succeeds because there is no row in tableb which references this row
DELETE FROM tablea WHERE id = 2;
-- fails because there is a row in tableb which references this row
Important note: Both tables must be InnoDB tables or the constraint is ignored.

The REFERENCES keyword shows a foreign key constraint, which means that:
FOREIGN KEY (`chat_id` ) REFERENCES `chats`.`chat` (`id` )
...the chat_id column in the current table can only contain values that already exist in the chat table, id column.
For example, if the CHAT.id column contains:
id
----
a
b
c
..you can not add any values other than a/b/c into the chat_id column.

Related

How to insert multiple rows into table B, and update table A's null foreign keys with the new IDs?

I've found a million things sounding kind of similar on StackOverflow, but not my case exactly. I'll simplify as much as possible:
I have two tables as follows:
CREATE TABLE B (id uuid PRIMARY KEY);
CREATE TABLE A (id uuid PRIMARY KEY, b_id uuid REFERENCES b);
There are some NULL values in A.b_id. I am trying to create a migration that does the following:
For every row in A with no b_id, create a new row in B, and assign its id to A.b_id.
How can I accomplish this in one query?
Assuming you want a distinct entry in b for every row with a missing UUID in a:
WITH upd AS (
UPDATE a
SET b_id = gen_random_uuid()
WHERE b_id IS NULL
RETURNING b_id
)
INSERT INTO b (id)
SELECT b_id FROM upd;
db<>fiddle here
This works because it's a single command, and the FK reference is only enforced at the end of the command.
See:
SET CONSTRAINTS ALL DEFERRED not working as expected
Constraint defined DEFERRABLE INITIALLY IMMEDIATE is still DEFERRED?

Can I make a unique constraint in Oracle on a combination of 2 columns from 2 different tables?

Column A is the PK of table A. Column B is a column in table B. Column C is a FK is table B that references column A in table A.
Can I define a constraint that says that that a column B AND column C have to be unique? As in, I don't want any repeats of the same combination of values from A and B.
Here's one possibility i'm thinking about:
Create a unique ID column.
unique_id varchar2 GENERATED ALWAYS AS (B || '-' || FK that references column A) VIRTUAL
set it as unique
CONSTRAINT unique_id UNIQUE
If i go with this solution i'm confused about one thing. The docs say: "Virtual columns are not supported for index-organized, external, object, cluster, or temporary tables." Obviously, because they don't get stored like other columns. Would this be a problem if I wanted to make my tables clustered?
Yes, you can create a UNIQUE constraint on two columns. For example:
create table table_a (
a number(6) primary key not null
);
create table table_b (
b number(6) not null,
c number(6) not null,
constraint uq1 unique (b, c),
constraint fk1 foreign key (c) references table_a (a)
);
Then, if you try to insert it will fail for duplicates. For example:
insert into table_a (a) values (1);
insert into table_a (a) values (2);
insert into table_b (b, c) values (10, 1);
insert into table_b (b, c) values (10, 1); -- fails!
insert into table_b (b, c) values (10, 2);
See running example at db<>fiddle.

Create constraint for control insert in table

There are two tables - orders and a list of services. In the first there is a bool field that the order is approved, if it is true then you can’t insert / delete values in the second table. With the UPDATE of the first table and the DELETE of the second, it is clear.
INSERT make as
INSERT INTO b (a_id, b_value)
SELECT *
FROM (VALUES (1, 'AA1-BB1'),(1, 'AA1-BB2'),(1, 'AA1-BB3')) va
WHERE (SELECT NOT confirm FROM a WHERE a_id = 2);
https://dbfiddle.uk/?rdbms=postgres_12&fiddle=7b0086967c1c38b0c80ca5624ebe92e9
How to forbid to insert without triggers and stored procedures? Is it possible to compose somehow complex constraint or a foreign key for checking conditions at the DBMS level?
The most recent version of Postgres supports generated columns. So, you can do:
alter table b add confirm boolean generated always as (false) stored;
Then create a unique key in a:
alter table a add constraint unq_a_confirm_id unique (confirm, id);
And finally the foreign key relationship:
alter table b add constraint fk_b_a_id_confirm
foreign key (confirm, a_id) references a(confirm, id);
Now, only confirmed = false ids can be used. Note that this will prevent updates to a that would invalidate the foreign key constraint.

No auto increment in my foreign key

I'm working in my school project and I want to make the id subject of any student incremented automatically as foreign key. I am showing you the example below as prototype, there are two tables, when I'm trying to insert data into the second table, I get an error (necessary to insert another field id of the table)
CREATE DATABASE database1;
USE database1;
CREATE TABLE table1
(
IdTable1 INT NOT NULL IDENTITY,
NOM VARCHAR(30),
PRIMARY KEY(IDMEDO)
);
--auto increment is working here
INSERT INTO table1
VALUES ('data1Table1'), ('data2Table1'), ('data3Table1');
--auto increment is working here just with the primary key
CREATE TABLE table2
(
IdTable2 INT not null IDENTITY,
IdTable1 INT,
dataTable2 varchar(30),
primary key(IdTable2),
constraint fk_tbl1 foreign key(IdTable1) references Table1
);
--necessary to add id field
INSERT INTO table2
VALUES ('data1Table2'), ('data2Table2'), ('data3Table2');
You should always (as a "best practice") define the columns you want to insert data into - that way, you can specify those that you have to provide values for, and let SQL Server handle the others. And for the foreign key, you have to explicitly provide a value - there's no "auto-magic" (or "auto-incrementing") way of associating a child row with its parent table - you have to provide the value in your INSERT statement.
So change your code to:
-- explicitly *specify* the NOM column here!
INSERT INTO table1 (NOM)
VALUES ('data1Table1'), ('data2Table1'), ('data3Table1');
-- again: explicitly *specify* the columns you want to insert into!
INSERT INTO table2 (IdTable1, dataTable2)
VALUES (1, 'data1Table2'), (2, 'data2Table2'), (3, 'data3Table2');
You need to insert the value of the foreign key wrt to table 1 now if you enter a value that's not in table 1 column which is acting as a foreign key then also it will not accept
Simply
Primary key and foreign key should match
Foreign key can't be null if table 1 doesn't contain a primary key with value null

PostgreSQL delete fails with ON DELETE rule on inherited table

In my PostgreSQL 9.1 database I've defined RULEs that delete rows from child tables whenever a parent table row is deleted. This all worked OK, until I introduced inheritance. If the parent (referencing) table INHERITS from another table and I delete from the base table then the DELETE succeeds, but the RULE doesn't appear to fire at all - the referenced row is not deleted. If I try to delete from the derived table I get an error:
update or delete on table "referenced" violates foreign key constraint "fk_derived_referenced" on table "derived"
There is no other row in the parent table that would violate the foreign key: it's being referenced by the row that's being deleted! How do I fix this?
The following script reproduces the problem:
-- Schema
CREATE TABLE base
(
id serial NOT NULL,
name character varying(100),
CONSTRAINT pk_base PRIMARY KEY (id)
);
CREATE TABLE referenced
(
id serial NOT NULL,
value character varying(100),
CONSTRAINT pk_referenced PRIMARY KEY (id)
);
CREATE TABLE derived
(
referenced_id integer,
CONSTRAINT pk_derived PRIMARY KEY (id),
CONSTRAINT fk_derived_referenced FOREIGN KEY (referenced_id) REFERENCES referenced (id)
)
INHERITS (base);
-- The rule
CREATE OR REPLACE RULE rl_derived_delete_referenced
AS ON DELETE TO derived DO ALSO
DELETE FROM referenced r WHERE r.id = old.referenced_id;
-- Some test data
INSERT INTO referenced (id, value)
VALUES (1, 'referenced 1');
INSERT INTO derived (id, name, referenced_id)
VALUES (2, 'derived 2', 1);
-- Delete from base - deletes the "base" and "derived" rows, but not "referenced"
--DELETE FROM base
--WHERE id = 2;
-- Delete from derived - fails with:
-- update or delete on table "referenced" violates foreign key constraint "fk_derived_referenced" on table "derived"
DELETE FROM derived
WHERE id = 2
As I said in my comment, this seems an unusual way to do things. But you can make it work with a deferred constraint.
CREATE TABLE derived
(
referenced_id integer,
CONSTRAINT pk_derived PRIMARY KEY (id),
CONSTRAINT fk_derived_referenced FOREIGN KEY (referenced_id)
REFERENCES referenced (id) DEFERRABLE INITIALLY DEFERRED
)
INHERITS (base);
The PostgreSQL docs, Rules vs. Triggers, say
Many things that can be done using triggers can also be implemented
using the PostgreSQL rule system. One of the things that cannot be
implemented by rules are some kinds of constraints, especially foreign
keys.
But it's not clear to me that this specific limitation is what you're running into.
Also, you need to check if other records are still referencing the to-be-deleted rows. I added a test derived record#3, which points to the same #1 reference record.
-- The rule
CREATE OR REPLACE RULE rl_derived_delete_referenced
AS ON DELETE TO tmp.derived DO ALSO (
DELETE FROM tmp.referenced re_del
WHERE re_del.id = OLD.referenced_id
AND NOT EXISTS ( SELECT * FROM tmp.derived other
WHERE other.referenced_id = re_del.id
AND other.id <> OLD.id )
;
);
-- Some test data
INSERT INTO tmp.referenced (id, value)
VALUES (1, 'referenced 1');
-- EXPLAIN ANALYZE
INSERT INTO tmp.derived (id, name, referenced_id)
VALUES (2, 'derived 2', 1);
INSERT INTO tmp.derived (id, name, referenced_id)
VALUES (3, 'derived 3', 1);
-- Delete from base - deletes the "base" and "derived" rows, but not "referenced"
--DELETE FROM base
--WHERE id = 2;
-- Delete from derived - fails with:
-- update or delete on table "referenced" violates foreign key constraint "fk_derived_referenced" on table "derived"
EXPLAIN ANALYZE
DELETE FROM tmp.derived
WHERE id = 2
;
SELECT * FROM tmp.base;
SELECT * FROM tmp.derived;
SELECT * FROM tmp.referenced;