Referential Constraint from one table to multiple tables - sql-server-2008-r2

If I have the following tables, is it possible to create a constraint in #TableNotes that will check if InstanceId exists in #Users if TableId == 1 and checks if InstanceId exists in #Companies if TableId == 2?
create table Users(
UserId int not null,
TableId int not null default 1
)
create table Companies(
CompanyId int not null,
TableId int not null default 2
)
create table TableNotes(
InstanceId int not null,
TableId int not null
)
Is there a way to accomplish this without using triggers?

I would recommend not designing your table, and instead using two columns to keep the referential integrity correct. I also assume that you mean TableId rather than ModelId
Something along the following lines would probably would work best for you if you can still change the design of your table.
CREATE TABLE TableNotes(
TableId int not null,
UserId int constraint fk_Users_Table_id foreign key references Users(TableId),
CompanyId int constraint fk_Companies_Table_id foreign key references Companies(TableId)
)
If this is not an option, as you have stated your only option would be to use triggers to keep this in check.

Related

Reference a Column From Another Table in PostgreSQL

I want to create the following tables (simplified to the keys for example):
CREATE TABLE a (
TestVer VARCHAR(50) PRIMARY KEY,
TestID INT NOT NULL
);
CREATE TABLE b (
RunID SERIAL PRIMARY KEY,
TestID INT NOT NULL
);
Where TestID is not unique, but I want table b's TestID to only contain values from table a's `TestID'.
I'm fairly certain I can't make it a foreign key, as the target of a foreign key has to be either a key or unique, and found that supported by this post.
It appears possible with Triggers according to this post where mine on insert would look something like:
CREATE TRIGGER id_constraint FOR b
BEFORE INSERT
POSITION 0
AS BEGIN
IF (NOT EXISTS(
SELECT TestID
FROM a
WHERE TestID = NEW.TestID)) THEN
EXCEPTION my_exception 'There is no Test with id=' ||
NEW.TestID;
END
But I would rather not use a trigger. What are other ways to do this if any?
A trigger is the only way to continuously maintain such a constraint, however you can delete all unwanted rows as part of a query that uses table b:
with clean_b as (
delete from b
where not exists (select from a where a.TestID = b.TestID)
)
select *
from b
where ...

PostgreSQL - Common autoincrement with inherited tables

I'm currently trying the inheritance system with PostgreSQL but I have a problem with the auto-increment index in my child tables.
I have three tables: "Currency", "Crypto" and "Stable"
CREATE TABLE IF NOT EXISTS public.currency
(
id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name VARCHAR(30) UNIQUE NOT NULL,
symbol VARCHAR(10) UNIQUE NOT NULL,
);
CREATE TABLE IF NOT EXISTS public.stable (id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY) INHERITS (public.currency);
CREATE TABLE IF NOT EXISTS public.crypto (id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY) INHERITS (public.currency);
I insered my data like this:
INSERT INTO public.stable (name, symbol) VALUES ('Euro', '€'), ('Dollar', '$'), ('Tether', 'USDT');
INSERT INTO public.crypto (name, symbol) VALUES ('Bitcoin', 'BTC'), ('Ethereum', 'ETH'), ('Litcoin', 'LTC');
But this is my problem: I would like to have a unique identifier that increments itself through my parent table "Currency".
When I select, I have (take a look in my id: 1,2,3,1,2,3):
But, Is it possible to have something like this instead (1,2,3,4,5,6):
Is it a problem in my primary key?
Thank you
We can try to use create sequence to set row numbers for sharing between multiple tables.
define a new sequence generator
create sequence n_id;
Then we can use this sequence as below, sharing this sequence for those three tables.
create sequence n_id;
CREATE TABLE IF NOT EXISTS currency
(
id INT default nextval('n_id') PRIMARY KEY,
name VARCHAR(30) UNIQUE NOT NULL,
symbol VARCHAR(10) UNIQUE NOT NULL
);
CREATE TABLE IF NOT EXISTS stable (id INT default nextval('n_id') PRIMARY KEY) INHERITS (currency);
CREATE TABLE IF NOT EXISTS crypto (id INT default nextval('n_id') PRIMARY KEY) INHERITS (currency);
sqlfiddle

How to design a database structure for a table with user set columns

TLDR
Is there some database mechanism or design pattern that allows the representation and use of custom columns in a table?
Longer version
This question has probably been asked before but the word "table" trips search engines up.
I need alternatives for a database design where a user sees a table with mostly custom columns.
Currently Postgresql is used, if there's an alternative engine that performs well with this task, that information would be appreciated.
It would look something like this:
predefined column | user column1 | user column2 | user column3 | user column4
--------------------|---------------|---------------|---------------|--------------
0 | 1 | 2 | 3 | 4
1 | 5 | 6 | 7 | 8
And here's the current database structure:
If the picture doesn't load/ you want to play around here's the SQL for it
CREATE SEQUENCE user_table_id_seq INCREMENT BY 1 MINVALUE 1 START 1;
CREATE SEQUENCE available_column_id_seq INCREMENT BY 1 MINVALUE 1 START 1;
CREATE SEQUENCE table_column_id_seq INCREMENT BY 1 MINVALUE 1 START 1;
CREATE SEQUENCE table_row_id_seq INCREMENT BY 1 MINVALUE 1 START 1;
CREATE TABLE user_table (id INT NOT NULL, user_id INT NOT NULL, name VARCHAR(50) NOT NULL, PRIMARY KEY(id));
CREATE TABLE available_column (id INT NOT NULL, name VARCHAR(50) NOT NULL, PRIMARY KEY(id));
CREATE TABLE table_column (id INT NOT NULL, user_table_id INT NOT NULL, column_id INT NOT NULL, name VARCHAR(50) NOT NULL, PRIMARY KEY(id));
CREATE TABLE table_row (id INT NOT NULL, table_column_id INT NOT NULL, user_column INT NOT NULL, predefined_column INT NOT NULL, PRIMARY KEY(id));
CREATE INDEX IDX_35DE8775E3087FAA ON user_table (user_id);
CREATE INDEX IDX_35DE8775E3087FAB ON table_column (user_table_id);
CREATE INDEX IDX_35DE8775E3087FAC ON table_column (column_id);
CREATE INDEX IDX_35DE8775E3087FAD ON table_row (table_column_id);
ALTER TABLE table_column ADD CONSTRAINT IDX_35DE8775E3087FAE FOREIGN KEY (user_table_id) REFERENCES "user_table" (id) NOT DEFERRABLE INITIALLY IMMEDIATE;
ALTER TABLE table_column ADD CONSTRAINT IDX_35DE8775E3087FAF FOREIGN KEY (column_id) REFERENCES "available_column" (id) NOT DEFERRABLE INITIALLY IMMEDIATE;
ALTER TABLE table_row ADD CONSTRAINT IDX_35DE8775E3087FBA FOREIGN KEY (table_column_id) REFERENCES "table_column" (id) NOT DEFERRABLE INITIALLY IMMEDIATE;
There are 2 main problems with this structure:
Data integrity is not properly enforced. One column can have 50 table_rows attached, while another has only 1. This is solvable in application layer, however.
Working with data seems pretty difficult: things like row count or pagination are hard to obtain. Group by clauses quickly cause headaches with indexes and performance.
I'm hoping that there's some mechanism or design pattern that i don't know, that allows for performant use of a table with custom colums. Extra points if it solves the problem of data integrity too.
One simple thing that could be done is flipping the relation, where table_row references user_table and table_column references table_row. That way row count is easier, but getting all the columns of a specific table is made hard.

Primary key for multiple columns in PostgreSQL?

How to provide primary key for multiple column in a single table using PostgreSQL?
Example:
Create table "Test"
(
"SlNo" int not null primary key,
"EmpID" int not null, /* Want to become primary key */
"Empname" varchar(50) null,
"EmpAddress" varchar(50) null
);
Note: I want to make "EmpID" also a primary key.
There can only be one primary key per table - as indicated by the word "primary".
You can have additional UNIQUE columns like:
CREATE TABLE test(
sl_no int PRIMARY KEY, -- NOT NULL due to PK
emp_id int UNIQUE NOT NULL,
emp_name text,
emp_addr text
);
Columns that are (part of) the PRIMARY KEY are marked NOT NULL automatically.
Or use a table constraint instead of a column constraint to create a single multicolumn primary key. This is semantically different from the above: Now, only the combination of both columns must be unique, each column can hold duplicates on its own.
CREATE TABLE test(
sl_no int, -- NOT NULL due to PK below
emp_id int , -- NOT NULL due to PK below
emp_name text,
emp_addr text,
PRIMARY KEY (sl_no, emp_id)
);
Multicolumn UNIQUE constraints are possible, too.
Aside: Don't use CaMeL-case identifiers in Postgres. Use legal, lower-case identifiers so you never have to use double-quotes. Makes your life easier. See:
Are PostgreSQL column names case-sensitive?
In case you want to specify the name of the primary key constraint:
CREATE TABLE test(
sl_no int not null,
emp_id int not null,
emp_name text,
emp_addr text,
constraint pk_test primary key (sl_no, emp_id)
);
Source: https://www.postgresqltutorial.com/postgresql-primary-key/

Creating a Check Constraint that Relies on the Information in another Table it References

To explain:
In one table, lets call it GroupMember, there is a column called JoinDate. GroupMembers are allocated to Groups which has a DateFounded.
Group
--------
GroupID identity int (PK)
DateFounded datetime
GroupMember
--------
GroupMemberID identity int (PK)
GroupID int (FK)
JoinDate datetime
I want to have a constraint on the GroupMember column JoinDate, that will prevent it from being entered as before the DateFounded for it's Group. How should I approach it? Can I use a check constraint? Or do I need a function/trigger?
Thanks
It can be done but it's a little messy (and does use a trigger, but only to support insertion, not to enforce the actual constraint):
create table dbo.Group (
GroupID int identity not null primary key,
DateFounded datetime not null,
constraint UQ_Group_Founded UNIQUE (GroupID,DateFounded)
)
go
create table dbo._GroupMember (
GroupMemberID int identity not null primary key,
GroupID int not null references Group (GroupID)
JoinDate datetime not null,
_Founded datetime not null,
constraint FK_GroupMember_Founding FOREIGN KEY (GroupID,_Founded) references Group (GroupID,DateFounded),
constraint CK_GroupMember_NoTimeTravel CHECK (JoinDate >= _Founded)
)
go
create view dbo.GroupMember
with schemabinding
as
select GroupMemberID,GroupID,JoinDate
from dbo.GroupMember
go
create trigger T_GroupMember_I
on dbo.GroupMember
instead of insert
as
insert into dbo._GroupMember (GroupID,JoinDate,_Founded)
select i.GroupID,i.JoinDate,g.DateFounded
from inserted i inner join Group g on i.GroupID = g.GroupID
And now you treat the view GroupMember as if it was your original GroupMember table and ignore the _GroupMember table.
It's up to you whether you continue to have the plain foreign key constraint to Group as well as the one that includes the DateFounded column. And if you want to allow that date to be adjusted in Group, you should mark the foreign key as ON UPDATE CASCADE and it should automatically adjust the stored value in _GroupMember and fail the update if the check constraint is then broken.