Build correct logical db - sql

I use 4 table in database.
Example:
Create table applicant(
Id int not null primary key,
IdName integer
idSkill integer,
idContact integer
Constraint initial foreign key (idName) References Initiale(id)
CONSTRAINT contacT foreign key (idContact) References contact(id)
CONSTRAINT Skills foreign key (idSkill) references skill(id))
Create table Initiale(
Id int not null primary key,
firstname text,
middlename text)
Create table contact(
Id int not null primary key,
phone text,
email text)
Create tabke Skills(
Id int not null primary key,,
Nane text)
I want insert data promptly in 4 table,but i not understand, what get id and insert in applicant.

Create tabke Skills ..... will fail. You should use Create table Skills.
Nor should you have Id int not null primary key,, (two commas), this would fail.
You should very likely be using Id INTEGER PRIMARY KEY not Id int not null primary key.
That is because generally an Id column should be a unique identifier of the row. With SQLite INTEGER PRIMARY KEY has a special meaining whilst INT PRIMARY KEY does not.
That is, if INTEGER PRIMARY KEY is used then the column will be an alias of the rowid column which has to be a unique signed 64 bit integer and importantly if no value is provided when inserting a row then SQLite will assign a unique integer. i.e. the all important Id.
This Id will initially be 1, then likely 2, then likely 3 and so on, although there is no guarantee that the Id will be monotonically increasing.
There are additional errors, mainly comma's omitted. The following should work :-
CREATE TABLE IF NOT EXISTS applicant(
Id INTEGER PRIMARY KEY,
IdName integer,
idSkill integer,
idContact integer,
Constraint initial foreign key (idName) References Initiale(id),
CONSTRAINT contacT foreign key (idContact) References contact(id),
CONSTRAINT Skills foreign key (idSkill) references Skills(id));
Create table IF NOT EXISTS Initiale(
Id INTEGER PRIMARY KEY,
firstname text,
middlename text);
Create table IF NOT EXISTS contact(
Id INTEGER PRIMARY KEY,
phone text,
email text);
Create table IF NOT EXISTS Skills(
Id INTEGER PRIMARY KEY,
Nane text);
You could then insert data along the lines of :-
INSERT INTO Initiale (firstname,middlename) -- Note absence of Id so SQLite will generate
VALUES
('Fred','James'), -- very likely id 1
('Alan','Roy'), -- very likely id 2
('Simon','Gerorge')-- very likely id 3
;
INSERT INTO contact -- alternative way of getting Id generated (specify null for Id)
VALUES
(null,'0123456789','email01#email.com'), -- very likely id 1
(null,'0987654321','email02#email.com'), -- very likely id 2
(null,'3333333333','email03.#email.com') -- very likely id 3
;
INSERT INTO Skills (Nane)
VALUES
('Skill01'),('Skill02'),('Skill03') -- very likely id's 1,2 and 3
;
INSERT INTO applicant (IdName,idSkill,idContact)
VALUES
-- First applicant
(2, -- Alan Roy
3, -- Skill 3
1), -- Contact 0123456789 )
-- Second Applicant
(3, -- Simon George
3, -- Skill 3
2), -- Contact 0987654321 )
-- Third Applicant
(2, -- Alan Roy again????
1, -- Skill 1
3), -- contact 3333333333)
(1,1,1) -- Fred James/ Skill 1/ Contact 0123456789
--- etc
;
Noting that Rows on the Initiale, Contact and Skills table MUST exists before insertions can be made into the Applicant table.
You could then run a query such as :-
SELECT * FROM applicant
JOIN Initiale ON Initiale.Id = idName
JOIN contact ON contact.Id = idContact
JOIN Skills ON Skills.Id = idSkill
This would result in (using the data as inserted above) :-

Related

Directionless relationship failing in PostgreSQL

I am trying to create a 2-way relationship table in PostgreSQL for my 3 objects. This idea has stemmed from the following question https://dba.stackexchange.com/questions/48568/how-to-relate-two-rows-in-the-same-table where I also want to store the relationship and its reverse between rows.
For context on my database: Object 1 which contains (aka relates to many) object2s. In turn, these object2s also relate to many object3s. A 1-to-many relationship (object 1 to object 2) and many-to-many relationship (object 2 to object 3)
Each of the objects have been assigned a UUID in other tables which contain info regarding them. Based on their UUID's I want to be able to query them and get the associated objects UUID as well. This in turn will show me the associations and direct me as to which object I should be looking at for location, info, etc just by knowing the UUID.
PLEASE NOTE - THAT ONE BOX MAY HAVE A RELTIONSHIP OF 10 SLOTS. THEREFORE THAT ONE UUID ASSIGNED FOR THE BOX WILL APPEAR IN MY UUID1 COLUMN 10 TIMES!! THIS IS A MUST!
My next step was to try and create a directionless relationship using this query:
CREATE TABLE bridge_x
(uuid1 UUID NOT NULL REFERENCES temp (uuid1), uuid2 UUID NOT NULL REFERENCES temp (uuid2),
PRIMARY KEY(uuid1, uuid2),
CONSTRAINT temp_temp_directionless
FOREIGN KEY (uuid2, uuid1)
REFERENCES bridge_x (uuid1, uuid2)
);
Is there any other way I can store ALL the information mentioned and be able to query the UUID in order to see the relationship between the objects?
You'll need a composite primary key in the bridge table. An example, using polygameous marriages:
CREATE TABLE person
(person_id INTEGER NOT NULL PRIMARY KEY
, name varchar NOT NULL
);
CREATE TABLE marriage
( person1 INTEGER NOT NULL
, person2 INTEGER NOT NULL
, comment varchar
, CONSTRAINT marriage_1 FOREIGN KEY (person1) REFERENCES person(person_id)
, CONSTRAINT marriage_2 FOREIGN KEY (person2) REFERENCES person(person_id)
, CONSTRAINT order_in_court CHECK (person1 < person2)
, CONSTRAINT polygamy_allowed UNIQUE (person1,person2)
);
INSERT INTO person(person_id,name) values (1,'Bob'),(2,'Alice'),(3,'Charles');
INSERT INTO marriage(person1,person2, comment) VALUES(1,2, 'Crypto marriage!') ; -- Ok
INSERT INTO marriage(person1,person2, comment) VALUES(2,1, 'Not twice!' ) ; -- Should fail
INSERT INTO marriage(person1,person2, comment) VALUES(3,3, 'No you dont...' ) ; -- Should fail
INSERT INTO marriage(person1,person2, comment) VALUES(2,3, 'OMG she did it again.' ) ; -- Should fail (does not)
INSERT INTO marriage(person1,person2, comment) VALUES(3,4, 'Non existant persons are not allowed to marry !' ) ; -- Should fail
SELECT p1.name, p2.name, m.comment
FROM marriage m
JOIN person p1 ON m.person1 = p1.person_id
JOIN person p2 ON m.person2 = p2.person_id
;
Result:
CREATE TABLE
CREATE TABLE
INSERT 0 3
INSERT 0 1
ERROR: new row for relation "marriage" violates check constraint "order_in_court"
DETAIL: Failing row contains (2, 1, Not twice!).
ERROR: new row for relation "marriage" violates check constraint "order_in_court"
DETAIL: Failing row contains (3, 3, No you dont...).
INSERT 0 1
ERROR: insert or update on table "marriage" violates foreign key constraint "marriage_2"
DETAIL: Key (person2)=(4) is not present in table "person".
name | name | comment
-------+---------+-----------------------
Bob | Alice | Crypto marriage!
Alice | Charles | OMG she did it again.
(2 rows)

What's wrong with my "on delete set default"?

I'm on Postgresql 13.
I want a table(rooms) that assume the default value of "1" if I delete from building which is the "parent table"
This is my sql code
DROP TABLE rooms;
DROP TABLE buildings;
CREATE TABLE buildings (
building_no INT default 1 primary key,
building_name VARCHAR(255),
address VARCHAR(255));
CREATE TABLE rooms (
room_no INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
room_name VARCHAR(255),
building_no INT default 1,
FOREIGN KEY (building_no) REFERENCES buildings (building_no) ON DELETE SET default );
I insert the values into the tables
insert into buildings values (1,'Building1','Street 33');
insert into buildings values (2,'Build-B','Street 34');
insert into rooms values (1,'Room 1',1);
insert into rooms values (2,'Room 2',2);
Then I delete from buildings
delete from buildings;
When I delete from buildings instead of make the default value of 1 as I ask it set the value NULL.
test=> select * from rooms;
room_no | room_name | building_no
---------+-----------+-------------
1 | Room 1 |
2 | Room 2 |
What's wrong in my sql code?
By deleting all of the records in buildings, the default value of 1 in the rooms table violates the FK constraint. Therefore, it's going to set it to NULL. If you were to delete all buildings EXCEPT building 1, you will not encounter the behavior you are describing.

Add row to table while incrementing primary key

Say I have a table that looks like:
ID Name Age Co
1 Adls 15 US
2 sldkl 14 FR
3 sldke 16 UK
4 sldee 17 IN
I want to add values to the table and have the ID incremented. ID is the primary key, and I set is Identity under column properties to 'Yes' and identity increment to 1.
So basically, I am doing:
Insert Into TableName(Name, Age, Co)
Values(slkdje, 19, CH)
(sldjklse, 20, AU)
(slfjke, 12, PK)
But, I am getting errors that the primary key is null, and therefore this operation in invalid. How would I add the values, but get the primary key values to increment?
here is a great example for what you want here
here is also a sql query that is copy and paste that will show my example.
create table #temp(
ID int IDENTITY(1,1) PRIMARY KEY,
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Age int
)
insert into #temp(LastName) values('billy'),('bob')
select * from #temp
drop table #temp;
hope this helps dude.

ORA-00904: "NO_OF_PROJ_PER_CON_PY": invalid identifier

I am trying to create a fact table which will display the number of projects per consultant per year. It has 2 dimension tables 1 for time (report_time_dim) and the other for consultants(consultant_dim) then the main fact table (fact_table).
CREATE TABLE fact_table(
fact_key INTEGER NOT NULL,
consultant_key INTEGER NOT NULL,
time_key INTEGER NOT NULL,
no_of_projects_py INTEGER,
no_of_consultants_py INTEGER,
no_of_accounts_py INTEGER,
no_of_proj_per_con_py INTEGER,
fk1_time_key INTEGER NOT NULL,
fk2_consultant_key INTEGER NOT NULL,
-- Specify the PRIMARY KEY constraint for table "fact_table".
-- This indicates which attribute(s) uniquely identify each row of data.
CONSTRAINT pk_fact_table PRIMARY KEY (consultant_key,time_key)
);
CREATE TABLE report_time_dim(
time_key INTEGER NOT NULL,
year INTEGER,
-- Specify the PRIMARY KEY constraint for table "time_dim".
-- This indicates which attribute(s) uniquely identify each row of data.
CONSTRAINT pk_report_time_dim PRIMARY KEY (time_key)
);
CREATE TABLE consultant_dim(
consultant_key INTEGER NOT NULL,
project_id INTEGER,
consultant_id INTEGER,
-- Specify the PRIMARY KEY constraint for table "consultant_dim".
-- This indicates which attribute(s) uniquely identify each row of data.
CONSTRAINT pk_consultant_dim PRIMARY KEY (consultant_key)
);
Each table has it's own surrogate key and I have managed to populate the time and consultant tables successfully, however the issue I'm having is with the fact table. When I try to populate it I get the error ORA-00904: "NO_OF_PROJ_PER_CON_PY": invalid identifier. I am unsure how I can go about fixing this and populating the fact table so it will display the information I want. Any help would be appreciated.
--populate fact_table
--table that lists consultant ids, project ids and years
DROP TABLE temp_fact1;
CREATE TABLE temp_fact1 AS
SELECT project_id, fk2_consultant_id, to_number(to_char(lds_project.pj_actual_start_date, 'YYYY')) as which_year FROM lds_project;
--display table
SELECT * FROM temp_fact1;
--list that counts the number of projects for each consultant and specify the year
DROP TABLE temp_fact2;
CREATE TABLE temp_fact2 AS
SELECT which_year, fk2_consultant_id, COUNT(*) project_id FROM temp_fact1 GROUP by fk2_consultant_id, which_year;
--display table
SELECT * FROM temp_fact2;
--fact table surrogate key
DROP SEQUENCE fact_seq;
CREATE SEQUENCE fact_seq
START WITH 1
INCREMENT BY 1
MAXVALUE 1000000
MINVALUE 1
NOCACHE
NOCYCLE;
--load data
INSERT INTO fact_table (fact_key, consultant_key, time_key, no_of_proj_per_con_py)
SELECT fact_seq.nextval, consultant_key, report_time_dim.time_key, no_of_proj_per_con_py FROM temp_fact2, report_time_dim WHERE temp_fact2.which_year = report_time_dim.year;
Try just running this select by itself - it's the last line in your script.
SELECT fact_seq.nextval,
consultant_key,
report_time_dim.time_key,
no_of_proj_per_con_py
FROM temp_fact2, report_time_dim
WHERE temp_fact2.which_year = report_time_dim.year;
It doesn't look like either TEMP_FACT2 or REPORT_TIME_DIM has a column named no_of_proj_per_con_py. I'm not sure where you want to pull that data from, actually.

How do I check the value of a foreign key on insert?

I'm teaching myself SQL using Sqlite3, well suited for my forever-game project (Don't we all have one?) and have the following tables:
CREATE TABLE equipment_types (
row_id INTEGER PRIMARY KEY,
type TEXT NOT NULL UNIQUE);
INSERT INTO equipment_types (type) VALUES ('gear'), ('weapon');
CREATE TABLE equipment_names (
row_id INTEGER PRIMARY KEY,
name TEXT NOT NULL UNIQUE);
INSERT INTO equipment_names (name) VALUES ('club'), ('band aids');
CREATE TABLE equipment (
row_id INTEGER PRIMARY KEY,
name INTEGER NOT NULL UNIQUE REFERENCES equipment_names,
type INTEGER NOT NULL REFERENCES equipment_types);
INSERT INTO equipment (name, type) VALUES (1, 2), (2, 1);
So now we have a 'club' that is a 'weapon', and 'band aids' that are 'gear'. I now want to make a weapons table; it will have an equipment_id that references the equipment table and weapon properties like damage and range, etc. I want to constrain it to equipment that is a 'weapon' type.
But for the life of me I can't figure it out. CHECK, apparently, only allows expressions, not subqueries, and I've been trying to craft a TRIGGER that might do the job, but in short, I can't quite figure out the query and syntax, or how to check the result that as I understand it will be in the form of a table, or null.
Also, are there good online resources for learning SQL more advanced than W3School? Add them as a comment, please.
Just write a query that looks up the type belonging to the new record:
CREATE TRIGGER only_weapons
BEFORE INSERT ON weapons
FOR EACH ROW
WHEN (SELECT et.type
FROM euqipment_types AS et
JOIN equipment AS e ON e.type = et.equipment_type_id
WHERE e.row_id = NEW.equipment_id
) != 'weapon'
BEGIN
SELECT RAISE(FAIL, "not a weapon");
END;
The foreign key references should be to the primary key and to the same time. I would phrase this as:
CREATE TABLE equipment_types (
equipment_type_id INTEGER PRIMARY KEY,
type TEXT NOT NULL UNIQUE
);
INSERT INTO equipment_types (type) VALUES ('gear'), ('weapon');
CREATE TABLE equipment_names (
equipment_name_id INTEGER PRIMARY KEY,
name TEXT NOT NULL UNIQUE
);
INSERT INTO equipment_names (name) VALUES ('club'), ('band aids');
CREATE TABLE equipment (
equipment_id INTEGER PRIMARY KEY,
equipment_name_id INTEGER NOT NULL UNIQUE REFERENCES equipment_names(equipment_name_id),
equipement_type_id INTEGER NOT NULL REFERENCES equipment_types(equipement_type_id)
);
I would not use the name row_id for the primary key. That is the built-inn default, so the name is not very good. In SQLite, an integer primary key is automatically auto-incremented (see here).