PostgreSQL force X amount of foreign key rows after insert - sql

If I have the following tables:
CREATE TABLE projects
(
id SERIAL PRIMARY KEY,
name VARCHAR(25) NOT NULL,
);
INSERT INTO projects (name) VALUES ('Portfolio Website'), ('Client Website');
CREATE TABLE developers
(
id SERIAL PRIMARY KEY,
name VARCHAR(25) NOT NULL,
);
INSERT INTO developers (name) VALUES ('Kevin'), ('Mark'), ('Simon');
CREATE TABLE languages
(
id SERIAL PRIMARY KEY,
name VARCHAR(25) NOT NULL,
);
INSERT INTO languages (name) VALUES ('HTML'), ('PHP'), ('ASP.NET'), ('Java');
CREATE TABLE developer_languages
(
id SERIAL PRIMARY KEY,
developer INTEGER REFERENCES developers(id),
language INTEGER REFERENCES languages(id)
);
INSERT INTO developer_languages (developer, language) VALUES (1,1), (1,2), (2,1), (2,3), (3,4);
CREATE TABLE project_developers
(
id SERIAL PRIMARY KEY,
project INTEGER REFERENCES projects(id),
developer INTEGER REFERENCES developers(id)
);
The requirement is that every project has a HTML developer and a Java developer. Is there any way to create a rule that enforces this?
I know I could just have a 'html_dev' and 'java_dev' column in the projects table but this then is an extra data source if you wanted to get every developer on the project stored in these two columns and the project_developers table.
I hope my question makes sense? I'm not even sure where to start looking so I though someone might be able to point me in the right direction, thanks!

What you are trying to do is not easily solved and a constraint trigger is not the solution because you cannot create a constraint to match your problem. One solution is the following, although it is a bit artificial:
Remove the INSERT privilege from the projects table.
Create a function insert_new_project(nm text, html_dev integer, java_dev integer) which inserts the new project and two inserts in project_developers. Check that the developers indeed have the required language skills.
Remove the UPDATE privilege on project_developers. Create a BEFORE DELETE trigger on project_developers to check that if you delete a Java or HTML developer from a project there is at least one such developer remaining. (So if you want to remove a developer, first insert a replacement.)
This procedure ensures that a new project has one developer of both flavours and that when developers get removed from a project at least one of each flavour remains. Insert a new project with SELECT insert_new_project('New project', 1, 3);.

Related

Update Postgres SQL table with SERIAL from previous insert [duplicate]

This question already has answers here:
Insert a value from a table in another table as foreign key
(3 answers)
Closed 4 months ago.
Very new to SQL in general, working on creating 2 Tables, 1 for example representing appliances with a primary key, second representing a microwave for example with its FK referencing the primary tables PK.
I'm using SERIAL as the id for the primary table, but don't know how to update or insert into the second table using that specific generated value from the first.
I've created my tables using PSQL (Postgres15) like so:
CREATE TABLE Appliances (
id SERIAL NOT NULL,
field1 integer NOT NULL DEFAULT (0),
--
PRIMARY KEY (id),
UNIQUE(id)
);
CREATE TABLE Microwaves (
id integer NOT NULL,
field1 integer,
--
PRIMARY KEY (id),
FOREIGN KEY (id) REFERENCES Appliances(id)
);
Inserting my first row into the Appliance table:
INSERT INTO Appliances(field1) VALUES(1);
SELECT * FROM Appliances;
Yields:
And a query I found somewhere pulls the current increment of the SERIAL:
SELECT currval(pg_get_serial_sequence('Appliances', 'id'));
Yields:
I'm struggling to determine how to format the INSERT statement, have tried several variations around the below input:
INSERT INTO Microwaves VALUES(SELECT currval(pg_get_serial_sequence('Appliances', 'id'), 1));
Yields:
Appreciate feedback on solving the problem as represented, or a better way to tackle this in general.
Okay looks like I stumbled on at least one solution that works in my case as taken from https://stackoverflow.com/a/50004699/3564760
DO $$
DECLARE appliance_id integer;
BEGIN
INSERT INTO Appliances(field1) VALUES('appliance2') RETURNING id INTO appliance_id;
INSERT INTO Microwaves(id, field2) VALUES(appliance_id, 100);
END $$;
Still open to other answers if this isn't ideal.

Securing values for other tables from enumerable table in SQL Server database

English is not my native language, so I might have misused words Enumerator and Enumerable in this context. Please get a feel for what I'm trying to say and correct me if I'm wrong.
I'm looking into not having tables for each enumerator I need in my database.
I "don't want" to add tables for (examples:) service duration type, user type, currency type, etc. and add relations for each of them.
Instead of a table for each of them which values will probably not change a lot, and for which I'd have to create relationships with other tables, I'm looking into having just 2 tables called Enumerator (eg: user type, currency...) and Enumerable (eg: for user type -> manager, ceo, delivery guy... and for currency -> euro, dollar, pound...).
Though here's the kicker. If I implement it like that, I'm loosing the rigidity of the foreign key relationships -> I can't accidentally insert a row in users table that will have a user type of some currency or service duration type, or something else.
Is there another way to resolve the issue of having so many enumerators and enumerables with the benefit of having that rigidity of the foreign key and with the benefit of having all of them in just those 2 tables?
Best I can think of is to create a trigger for BEFORE UPDATE and BEFORE INSERT to check if (for example) the column type of user table is using the id of the enumerable table that belongs to the correct enumerator.
This is a short example in SQL
CREATE TABLE [dbo].[Enumerator]
(
[Id] INT NOT NULL PRIMARY KEY,
[Name] VARCHAR(50)
)
CREATE TABLE [dbo].[Enumerable]
(
[Id] INT NOT NULL PRIMARY KEY,
[EnumeratorId] INT NOT NULL FOREIGN KEY REFERENCES Enumerator(Id),
[Name] VARCHAR(50)
)
INSERT INTO Enumerator (Id, Name)
VALUES (1, 'UserType'),
(2, 'ServiceType');
INSERT INTO Enumerable (Id, EnumeratorId, Name) -- UserType
VALUES (1, 1, 'CEO'),
(2, 1, 'Manager'),
(3, 1, 'DeliveryGuy');
INSERT INTO Enumerable (Id, EnumeratorId, Name) -- ServiceDurationType
VALUES (4, 2, 'Daily'),
(5, 2, 'Weekly'),
(6, 2, 'Monthly');
CREATE TABLE [dbo].[User]
(
[Id] INT NOT NULL PRIMARY KEY IDENTITY (1,1),
[Type] INT NOT NULL FOREIGN KEY REFERENCES Enumerable(Id)
)
CREATE TABLE [dbo].[Service]
(
[Id] INT NOT NULL PRIMARY KEY IDENTITY (1,1),
[Type] INT NOT NULL FOREIGN KEY REFERENCES Enumerable(Id)
)
The questions are:
Is it viable to resolve enumerators and enumerables with 2 tables and with before update and before insert triggers, or is it more trouble than it's worth?
Is there a better way to resolve this other than using before update and before insert triggers?
Is there a better way to resolve enumerators and enumerables that is not using 2 tables and triggers, nor creating a table with relations for each of them?
I ask for your wisdom as I don't have one or more big projects behind me and I didn't get a chance to create a DB like this until now.

Cannot create Access tables through SQL view

I'm trying to create 3 access tables in SQL view on Microsoft Access but whenever I try to execute it, I receive the following error. 'Syntax Error in CREATE TABLE statement'.
Please find my code below.
CREATE TABLE Book (
Book_ID int,
Book_Title varchar (30),
PRIMARY KEY (Book_ID)
);
CREATE TABLE Users (
User_ID int,
User_Name varchar (30),
PRIMARY KEY (User_ID)
);
CREATE TABLE Borrows (
User_ID int,
Book_ID int,
B_ID int,
PRIMARY KEY(B_ID),
FOREIGN KEY(User_ID) REFERENCES Users(User_ID),
FOREIGN KEY(Book_ID) REFERENCES Book(Book_ID)
);
INSERT INTO Book VALUES (101, 'The Hobbit'), (102, 'To Kill a Mockingbird');
INSERT INTO Users VALUES (1, 'Stephen'), (2, 'Tom'), (3,' Eric');
INSERT INTO Borrows VALUES (3, 102, 1), (1, 101, 2);
Appreciate any feedback I can get, have a good day.
Your first CREATE TABLE executed flawlessly from the query designer in Access 2010. However my preference is to include the PRIMARY KEY constraint as part of the field definition:
CREATE TABLE Book (
Book_ID int PRIMARY KEY,
Book_Title varchar (30)
);
That variation also executed successfully.
I suspect you have at least 2 issues to resolve:
Access does not allow you to execute more than one SQL statement at a time (as Heinzi and Albert mentioned). You must execute them one at a time.
In Access, INSERT ... VALUES can only be used to add one row at a time. Revise your inserts accordingly.
IOW, split the first one into 2 statements which you then execute individually:
-- INSERT INTO Book VALUES (101, 'The Hobbit'), (102, 'To Kill a Mockingbird');
INSERT INTO Book VALUES (101, 'The Hobbit');
INSERT INTO Book VALUES (102, 'To Kill a Mockingbird');
Then split and execute the remaining inserts similarly.
Your code example use SQL Server (T-SQL) syntax, not MS Access syntax.
The syntax for Access' CREATE TABLE statement is documented here:
https://learn.microsoft.com/en-us/office/client-developer/access/desktop-database-reference/create-table-statement-microsoft-access-sql
The most obvious differences seem to be there is no varchar type and that PRIMARY KEY needs a constraint name if specified in an extra line. There might be more, see the article and its examples for details. I also suggest that you submit your statements one-by-one, instead of submitting a complete ;-separated batch; I'm not sure Access queries even support the latter.

Creating a table in SQL using Oracle 11G

I am new to learning SQL and have been struggling to create a table for an assignment. These are the requirements:
Create a new table to track the Library location.
LIBRARY (lib_id, lib_name, lib_address, lib_city, lib_state, lib_zip)
LIB_ID is the library id – it is an auto generated number. (you should create a sequence number called lib_id_seq, start with 1001 and increment by 1.)
LIB_ID is the primary key.
LIB_NAME, LIB_ADDRESS, and LIB_CITY is between 1 and 35 characters.
LIB_STATE is 2 characters – default to TX.
LIB_ZIP is 5 numbers. Check for one of the following zip codes – 75081, 75080, 75082, 75079, 75078
And this is what I have written out so far:
CREATE TABLE LIBRARY
(
LIB_ID INT(4),
LIB_ADDRESS VARCHAR(35),
LIB_CITY VARCHAR(35),
LIB_STATE VARCHAR(2) DEFAULT ‘TX’,
LIB_ZIP INT(5) CHECK (Frequency IN ('75078', ‘75079', '75080', '75081', ‘75082’))
PRIMARY KEY(LIB_ID)
);
CREATE SEQUENCE LIB_ID_SEQ
START WITH 1001
INCREMENT BY 1;
I keep getting errors, but am not sure what I need to fix.
For oracle (Kid Tested unsure if SO approved)...
use varchar2 instead of varchar
use Number instead of int
added constraint syntax (named them)
adjusted apostrophe's (Removed) instead of whatever the heck you had in some of them :P (It's a numeric field shouldn't be using text apostrophes!)
personally I wouldn't name a table library as that's a reserved word
I woudln't use a numeric Zip code as we will never do math on a zipcode.
.
.
CREATE TABLE LIBRARY (
LIB_ID Number(4),
LIB_ADDRESS VARCHAR2(35),
LIB_CITY VARCHAR2(35),
LIB_STATE VARCHAR2(2) DEFAULT 'TX',
LIB_ZIP NUMBER(5),
CONSTRAINT Lib_ZIP_CON CHECK (LIB_ZIP IN (75078, 75079, 75080, 75081, 75082)),
CONSTRAINT LIB_ID_PK PRIMARY KEY(LIB_ID)
);
CREATE SEQUENCE LIB_ID_SEQ
START WITH 1001
INCREMENT BY 1;
This works for SQL Server. You need to modify the syntax accordingly for the concerned db.
CREATE TABLE LIBRARY
(
LIB_ID INTEGER PRIMARY KEY,
LIB_ADDRESS VARCHAR(35),
LIB_CITY VARCHAR(35),
LIB_STATE VARCHAR(2) DEFAULT 'TX',
LIB_ZIP INTEGER,
CHECK( LIB_ZIP IN ('75078', '75079', '75080', '75081', '75082') )
);
CREATE SEQUENCE LIB_ID_SEQ
START WITH 1001
INCREMENT BY 1;
For learning how to create tables and constraints check this link on w3schools as you seem to be a beginner.
http://www.w3schools.com/sql/sql_primarykey.asp

On duplicate key update feature in H2

I have developed java desktop application with the use of H2(Embedded). I just have basic knowledge about database, so i simply installed H2 and create a schema name RecordAutomation and then add tables to that schema. Now i am trying to use the ON DUPLICATE KEY UPDATE feature for a specific table which is not working giving sql syntax error, i check my query i found it right, given below
INSERT INTO RECORDAUTOMATION.MREPORT
(PRODUCTID ,DESCRIPTION ,QUANTITY ,SUBTOTAL ,PROFIT )
VALUES (22,olper,5,100,260)
ON DUPLICATE KEY UPDATE SET QUANTITY = QUANTITY+5;
i search and try to solve this problem some where it is discussed like this feature does not work for non-default tables. i have no idea about default and non-default. please make help me
You need to use the MySQL mode. To do that, append ;mode=MySQL to the database URL. (This feature is not properly documented yet).
The table needs to have a primary key or at least a unique index. Complete example:
drop table MREPORT;
set mode MySQL;
create table MREPORT(PRODUCTID int primary key,
DESCRIPTION varchar, QUANTITY int, SUBTOTAL int, PROFIT int);
INSERT INTO MREPORT
(PRODUCTID ,DESCRIPTION ,QUANTITY ,SUBTOTAL ,PROFIT )
VALUES (22,'olper',5,100,260)
ON DUPLICATE KEY UPDATE QUANTITY = QUANTITY+5;