Using a 'not in' query inside of a check constraint in SQL - sql

I have two tables, one of student and one of staff that look as such:
create table student (
id int not null primary key
)
create table staff (
id int not null primary key
)
I want the id in each to be unique. I know this isn't how it should be in production but I'm just trying to see why my check constraint doesn't work and I'm using a simpler example to explain.
I then alter the tables to include the check as follows:
alter table student add constraint not_staff check (id not in (select id from staff))
alter table staff add constraint not_student check (id not in (select id from student))
These checks seem to be invalid.
My question is whether we're allowed to have these kinds of SQL statements inside of a check constraint. If so, why is the above constraint invalid and how would I go about fixing it.
Thanks!

You can't use queries in a check constraint in Db2. Refer to the description of the CREATE TABLE statement.
CHECK (check-condition)
Defines a check constraint. The search-condition must be true or unknown for every row of the table.
search-condition
The search-condition has the following restrictions:
...
The search-condition cannot contain any of the following (SQLSTATE 42621):
Subqueries
The easiest way to achieve your goal is not to create constraints, but create a sequence and use it in before triggers on both tables.

Related

Create a table with a foreign key referencing to a temporary table generated by a query

I need to create a table having a field, which is a foreign key referencing to another query rather than existing table. E.g. the following statement is correct:
CREATE TABLE T1 (ID1 varchar(255) references Types)
but this one throws a syntax error:
CREATE TABLE T2 (ID2 varchar(255) references SELECT ID FROM BaseTypes UNION SELECT ID FROM Types)
I cannot figure out how I can achieve my goal. In the case it’s needed to introduce a temporary table, how can I force this table being updated each time when tables BaseTypes and Types are changed?
I am using Firebird DB and IBExpert management tool.
A foreign key constraint (references) can only reference a table (or more specifically columns in the primary or unique key of a table). You can't use it to reference a select.
If you want to do that, you need to use a CHECK constraint, but that constraint would only be checked on insert and updates: it wouldn't prevent other changes (eg to the tables in your select) from making the constraint invalid while the data is at rest. This means that at insert time the value could meet the constraint, but the constraint could - unnoticed! - become invalid. You would only notice this when updating the row.
An example of the CHECK-constraint could be:
CREATE TABLE T2 (
ID2 varchar(255) check (exists(
SELECT ID FROM BaseTypes WHERE BaseTypes.ID = ID2
UNION
SELECT ID FROM Types WHERE Types.ID = ID2))
)
For a working example, see this fiddle.
Alternatively, if your goal is to 'unite' two tables, define a 'super'-table that contains the primary keys of both tables, and reference that table from the foreign key constraint. You could populate and update (eg insert and delete) this table using triggers. Or you could use a single table, and replace the existing views with an updatable view (if this is possible depends on the exact data, eg IDs shouldn't overlap).
This is more complex, but would give you the benefit that the foreign key is also enforced 'at rest'.

SQL How to not insert duplicated values

I'm trying to create a procedure that inserts data into a table of registers but i don't want to repeat the second parameter, this is the table
CREATE TABLE Inscription
(
idClass INT references tb_class,
idStudent INT references tb_student,
)
The idea is that a student (idStudent) can register in various classes but not in the same class (idClass), I tried to add a unique constraint in the idStudent column but that only allows a student to register in one single class.
I always suggest that all tables have a numeric primary key. In addition, your foreign key references are not correct. And what you want to do is add a unique constraint.
The exact syntax depends on the database. The following is for SQL Server:
CREATE TABLE Inscriptions (
idInscription int identity(1, 1) primary key
idClass int references tb_classes(idClass),
idStudent int references tb_students(idStudnt)
unique (idClass, idStudent)
);
Notice that I name the tables as the plural of the entity, but the id using the singular.
The Inscriptions table probably wants other columns as well, such as the date/time of the inscription, the method, and other related information.
You are looking to create a constraint on your table that includes both columns idClass and idStudent.
Once that constraint is created, an attempt to insert duplicate class/student will result in an error being raised.
As your table does not seem to include a primary key, you would better make that constraint your primary key.
NB : you did not tell which RDBMS you are using hence cannot give you the exact syntax to use...
Your unique key needs to encompass both idClass and idStudent, so any particular combination cannot repeat itself.

Postgres create table error

I am trying to create my very first table in postgres, but when I execute this SQL:
create table public.automated_group_msg (
automated_group_msg_idx integer NOT NULL DEFAULT nextval ('automated_group_msg_idx'::regclass),
group_idx integer NOT NULL,
template_idx integer NOT NULL,
CONSTRAINT automated_group_msg_pkey PRIMARY KEY (automated_group_msg_idx),
CONSTRAINT automated_group_msg_group_idx_fkey FOREIGN KEY (group_idx)
REFERENCES public.groups (group_idx) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT automated_msg_template_idx_fkey FOREIGN KEY (template_idx)
REFERENCES public.template (template_idx) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE
)
WITH (
OIDS = FALSE
);
I get the following error:
ERROR: relation "automated_group_msg_idx" does not exist
Your error is (likely) because the sequence you're trying to use doesn't exist yet.
But you can create a sequence on the fly using this syntax:
create table public.automated_group_msg (
id serial primary key,
... -- other columns
)
Not directly related to your question, but naming columns with the table name in the name of the column is generally speaking an anti-pattern, especially for primary keys for which id is the industry standard. It also allows for app code refactoring using abstract classes whose id column is always id. It's crystal clear what automated_group_msg.id means and also crystal clear that automated_group_msg.automated_group_msg_id is a train wreck and contains redundant information. Attribute column names like customer.birth_date should also not be over-decorated as customer.customer_birth_date for the same reasons.
You just need to create the sequence before creating the table
CREATE SEQUENCE automated_group_msg_idx;

What does DF__role_sett__custo__4589517F in SQL Server database mean?

I have just inherited a database from another developer, and I have looked through the sys.objects table, filtering by constraints.
What does DF__role_sett__custo__4589517F mean - mainly the ID at the end of the string?
I know that DF_role_sett_custo means default constraint of role_setting_customer, but am not sure of the last ID 4589517f.
If you don't name a constraint when it is created, SQL Server will assign it a random name based on the table and column. It appends a random number so that it doesn't clash with existing constraint names.
In almost all cases, it is best to name a constraint when it is created. It's then easier to refer to the constraint by name in other T-SQL statements.
For instance, in the following create statement
CREATE TABLE dbo.some_table(
some_field INT NOT NULL DEFAULT(5)
);
The default constraint will be assigned a random name. In this statement:
CREATE TABLE dbo.some_table(
some_field INT NOT NULL CONSTRAINT DF_some_table_some_field DEFAULT(5)
);
The default constraint will have the name you assigned to it (i.e. DF_some_table_some_field).

MySQL: Can I constraint column values in one table to values in a column in another table, by DB design only?

Example:
Table "persons", Column "surname" may only contain values predefined in
Table "names", Column "surnames", which would contain a collection of surnames acceptable for the purpose.
Can I achieve this by design (i.e. without involving any validation code)? On a MyISAM table? No? On InnoDB?
Thank you.
What you're asking for is a foreign key constraint. You'd need to use InnoDB - quote:
For storage engines other than InnoDB, MySQL Server parses the FOREIGN KEY syntax in CREATE TABLE statements, but does not use or store it.
To add a foreign key constraint within the CREATE TABLE statement for PERSONS:
FOREIGN KEY (surname) REFERENCES names(surnames)
Using an ALTER TABLE statement if the tables already exist:
ALTER TABLE persons
ADD CONSTRAINT FOREIGN KEY (surname) REFERENCES names(surname)
Be aware that if you use the ALTER TABLE statement, the data in the PERSONS table can only contain surname values that exist in the NAMES.surname table - it can not be applied until after the data has been fixed.
For MyISAM tables you can achieve desired functionality by using triggers.
For instance (validate insert),
DELIMITER //
CREATE DEFINER=`root`#`localhost` TRIGGER BEFORE INSERT ON persons
FOR EACH ROW
BEGIN
DECLARE tmp_surname varchar(100);
SELECT surname into tmp_surname FROM names WHERE surname = NEW.surname;
IF (tmp_surname IS NULL) THEN
INSERT INTO t1(id,value) VALUES('aaa'); #raise an 'exception'
END IF;
END;//
delimiter;
Mysql doesn't have exceptions, but you can terminate execution(and, consequently, 'rollback' changes) by creating an invalid statement