I am new to databases, but I am getting a problem:
Here AAA, BBB, TABLE-1, TABLE-2 and TABLE-3 table names(tables).
TABLE-1 (A, B) COMPOUND PRIMARY KEY(A,B) AND A IS REFER FROM *AAA(A)* AND B IS REFER FROM *BBB(B)*
1 1
1 2
2 1
TABLE-2 (D, A) D IS PRIME AND A IS REFER FROM *AAA(A)*
1 1
2 2
TABLE-3 (D, B) COMPOUND PRIMARY KEY(D,B) AND B IS REFER FROM *BBB(B)*
1 1
2 2
HERE MEANING OF TABLE-2 AND TABLE-3 IS
(D, A, B)
1 1 1
2 2 2
But the problem is in second row here A = 2, B=2 is not matching with TABLE-1.
How to achieve this?
Ex:
I have Airport, Caterer, Meal, Airport_caterer_map, Airport_Meal_Map
Airport (this main configuration table)
id Name
1 aaa
2 bbb
Caterer (this main configuration table)
id Name
1 mmm
2 nnn
Airport_caterer_map (this main configuration table)
airport_id caterer_id
1 1
1 2
2 1
Meal
id Name caterer_id
1 mmm 1
2 nnn 2
Airport_Meal_Map
mail_id airport_id
1 1
1 2
2 1
2 2 -- This row should be wrong.
why is,
1. meal 2 is available in airport 2
2. meal 2 is providing by caterer 2
3. But there is no mapping between caterer 2 and airport 2 in airport_caterer_map table.
Basically, your Airport_Meal_Map should actually be an Airport_Caterer_Meal_Map - if you want the database to help with the consistency checks:
CREATE TABLE Airport
(
id INT primary key,
name VARCHAR(30)
);
INSERT INTO Airport VALUES
(1, 'aaa'),
(2, 'bbb');
CREATE TABLE Caterer
(
id INT primary key,
name VARCHAR(30)
);
INSERT INTO Caterer VALUES
(1, 'mmm'),
(2, 'nnn');
CREATE TABLE Airport_Caterer_Map
(
airport_id INT,
caterer_id INT,
PRIMARY KEY (airport_id, caterer_id),
FOREIGN KEY (airport_id) REFERENCES Airport(id),
FOREIGN KEY (caterer_id) REFERENCES Caterer(id)
);
INSERT INTO Airport_Caterer_Map (airport_id, caterer_id) VALUES
(1, 1),
(1, 2),
(2, 1);
-- INSERT INTO Airport_Caterer_Map (airport_id, caterer_id) VALUES
-- (2, 2);
CREATE TABLE Meal
(
id INT,
name VARCHAR(30),
caterer_id INT,
PRIMARY KEY (id, caterer_id),
FOREIGN KEY (caterer_id) REFERENCES Caterer(id)
);
INSERT INTO Meal (id, name, caterer_id) VALUES
(1, 'mmm', 1),
(2, 'nnn', 2);
-- INSERT INTO Meal (id, name, caterer_id) VALUES
-- (1, 'mmm', 2);
-- INSERT INTO Meal (id, name, caterer_id) VALUES
-- (2, 'nnn', 1);
CREATE TABLE Airport_Meal_Map -- actually Airport_Caterer_Meal_Map
(
meal_id INT,
airport_id INT,
caterer_id INT,
PRIMARY KEY (meal_id, airport_id, caterer_id),
FOREIGN KEY (airport_id, caterer_id) REFERENCES Airport_Caterer_Map(airport_id, caterer_id),
FOREIGN KEY (meal_id, caterer_id) REFERENCES Meal(id, caterer_id)
);
INSERT INTO Airport_Meal_Map (meal_id, airport_id, caterer_id) VALUES
(1, 1, 1),
(1, 2, 1),
(2, 1, 2);
-- Fails as meal 1 is not prepared by caterer 2
-- INSERT INTO Airport_Meal_Map (meal_id, airport_id, caterer_id) VALUES
-- (1, 1, 2);
-- Fails as meal 2 is not prepared by caterer 1
-- INSERT INTO Airport_Meal_Map (meal_id, airport_id, caterer_id) VALUES
-- (2, 1, 1);
-- Fails as airport 2 is not served by caterer 2
-- INSERT INTO Airport_Meal_Map (meal_id, airport_id, caterer_id) VALUES
-- (2, 2, 2);
SQL Fiddle
Related
I'm developing a School/University software and I got stucked in this situation:
Table Professor
id
name
1
Mr. Ward
2
Mr. Smith
Table Subject
id
name
1
Math
2
Physics
3
English
Table ProfessorsSubject
p_id
s_id
1
1
1
2
2
3
(Mr. Ward, Math), (Mr. Ward, Physics) and (Mr. Smith, English)
Table StudentClass:
id
name
Building
10
Tenth Grade
A
11
Eleventh Grade
A
Table A:
sclass_id
subj_id
prof_id
foo
bar
10
1
1
foo1
bar1
10
2
1
foo2
bar2
10
3
NULL
foo3
bar3
11
1
1
foo4
bar4
11
2
1
foo5
bar5
11
3
2
foo6
bar6
The pair(sclass_id, subj_id) must be UNIQUE.
prof_id might be NULL.
CREATE TABLE Professor (
id int PRIMARY KEY AUTO_INCREMENT,
name varchar(100) NOT NULL
);
CREATE TABLE Subject (
id int PRIMARY KEY AUTO_INCREMENT,
name varchar(100) NOT NULL
);
CREATE TABLE ProfessorsSubject (
prof_id int,
subj_id int,
PRIMARY KEY (prof_id, subj_id),
FOREIGN KEY (prof_id) REFERENCES Professor(id),
FOREIGN KEY (subj_id) REFERENCES Subject(id)
);
CREATE TABLE StudentClass (
id int PRIMARY KEY AUTO_INCREMENT,
name varchar(100) NOT NULL,
building varchar(100)
);
CREATE TABLE A (
sclass_id int,
subj_id int,
prof_id int,
foo varchar(10),
bar varchar(10),
PRIMARY KEY (sclass_id, subj_id),
FOREIGN KEY (sclass_id) REFERENCES StudentClass (id),
FOREIGN KEY (subj_id ) REFERENCES ProfessorsSubject (subj_id),
FOREIGN KEY (prof_id ) REFERENCES ProfessorsSubject (prof_id)
);
/* ==================================================================== */
INSERT INTO Professor(id, name) VALUES (1, "Mr. Ward");
INSERT INTO Professor(id, name) VALUES (2, "Mr. Smith");
INSERT INTO Subject(id, name) VALUES (1, "Math");
INSERT INTO Subject(id, name) VALUES (2, "Physics");
INSERT INTO Subject(id, name) VALUES (3, "English");
INSERT INTO ProfessorsSubject (prof_id, subj_id) VALUES (1, 1);
INSERT INTO ProfessorsSubject (prof_id, subj_id) VALUES (1, 2);
INSERT INTO ProfessorsSubject (prof_id, subj_id) VALUES (2, 3);
INSERT INTO StudentClass(id, name, building) VALUES (10, "Tenth Grade", "A");
INSERT INTO StudentClass(id, name, building) VALUES (11, "Eleventh Grade", "A");
/* ==================================================================== */
INSERT INTO A (sclass_id, subj_id, prof_id, foo, bar) VALUES (10, 1, 1, "foo1", "bar1");
INSERT INTO A (sclass_id, subj_id, prof_id, foo, bar) VALUES (10, 2, 1, "foo2", "bar2");
INSERT INTO A (sclass_id, subj_id, prof_id, foo, bar) VALUES (10, 3, 1, "foo3", "bar3");
/* ==================================================================== */
Mr. Ward shouldn't be able to teach English to Tenth Grade, because this combination is not present in table ProfessorsSubject.
To avoid inconsitences in a database level, how to make sure the pair (prof_id, subj_id) in Table A respects what is in "SubjectOfProfessor" table before insert?
1.1) Is it necessary to use Procedures? Triggers ?
1.2) Is it possible to make this just using fields proprieties and/or constraints ?
What if I wanted to do this using Django ORM in a databased level ?
Reference: migrations.RunSQL('ALTER TABLE app_event ADD CONSTRAINT chronology CHECK (start_date > end_date);
You can use a combined foreign key in the table A as you did with the primary key in the table ProfessorsSubject. A corresponding index on the referenced table is required which actually is fulfilled by its primary key already.
FOREIGN KEY (subj_id, prof_id) REFERENCES ProfessorsSubject (subj_id, prof_id)
There is a way to delete the referenced record when I delete the row with the foreign key?
This is my db's tables
and I want delete the 3 record referenced of the table "righe" when I delete the record in table "cartelle"
Just add your reference in the other direction, like this:
Fiddle
-- cartelle (folder)
CREATE TABLE folders ( folder_id int primary key );
-- righe (rows, tied to a folder)
CREATE TABLE xrows (
row_id int primary key
, folder_id int
, FOREIGN KEY (folder_id) REFERENCES folders (folder_id) ON DELETE CASCADE
);
INSERT INTO folders VALUES (1), (2), (3);
INSERT INTO xrows VALUES
(1, 1)
, (2, 1)
, (3, 1)
, (4, 2)
, (5, 3)
, (6, 2)
;
row_id
folder_id
1
1
2
1
3
1
4
2
5
3
6
2
Now when we delete a folder, the corresponding rows will be deleted.
DELETE FROM folders WHERE folder_id = 1;
SELECT * FROM xrows;
The result:
row_id
folder_id
4
2
5
3
6
2
after starting (and almost finishing) a database project for school, I found out I was supposed to use Oracle Express instead of MySQL. So when I brought in the code I had written from mysql to oracle, everything stopped working. I'm not too familiar with oracle databases but I assumed their syntax is quite simaler to MySqls.
Are there any structures in this file that are different in oracle DBs?
anything you guys can see would help. Thanks!
CREATE SCHEMA IF NOT EXISTS marys_limo_service;
use marys_limo_service;
DROP TABLE IF EXISTS Driver;
CREATE TABLE Driver(
d_id int,
d_name varchar(50),
d_contact varchar(30),
CONSTRAINT Driver_d_id PRIMARY KEY(d_id)
);
DROP TABLE IF EXISTS Limo;
CREATE TABLE Limo(
l_id int,
l_callsign varchar(12),
l_type varchar(40),
CONSTRAINT Limo_pk PRIMARY KEY(l_id)
);
DROP TABLE IF EXISTS Aclient;
CREATE TABLE Aclient (
c_id int,
c_name varchar(50),
c_contact varchar(30),
c_methpmt varchar(20),
CONSTRAINT Aclient_pk PRIMARY KEY(c_id)
);
DROP TABLE IF EXISTS Qualify;
CREATE TABLE Qualify (
q_id int,
l_id int,
d_id int,
CONSTRAINT Qualify_q_id_PK PRIMARY KEY(q_id),
CONSTRAINT Qualify_l_id_FK FOREIGN KEY(l_id) REFERENCES Limo(l_id),
CONSTRAINT Qualify_d_id_FK FOREIGN KEY(d_id) REFERENCES Driver(d_id)
);
DROP TABLE IF EXISTS Rental;
CREATE TABLE Rental (
r_id INT,
r_date DATE,
r_fee FLOAT,
c_id INT,
q_id INT,
CONSTRAINT Rental_r_id_PK PRIMARY KEY(r_id),
CONSTRAINT Rental_c_id_FK FOREIGN KEY(c_id) REFERENCES Aclient(c_id),
CONSTRAINT Rental_q_id_FK FOREIGN KEY(q_id) REFERENCES Qualify(q_id)
);
INSERT INTO Driver
VALUES
(1,"alf","9022332332"),
(2,"bob","9022322323");
INSERT INTO Limo
VALUES
(1,"Car One", "stretch limo"),
(2,"Car Two", "hummer limo"),
(3,"Car Three", "armored personnel carrier");
INSERT INTO Qualify
VALUES
(1,1,1),
(2,2,1),
(3,3,1),
(4,1,2),
(5,2,2);
INSERT INTO Aclient
VALUES
(1,"ann","9022332332", "cash"),
(2,"bub","9022322323", "CC");
INSERT INTO Rental
VALUES
(1, "2015/3/21", 550, 2, 1),
(2, "2015/3/21", 1000, 1, 5),
(3, "2015/3/20", 2050, 1, 3),
(4, "2015/3/19", 550, 1, 1),
(5, "2015/3/20", 500, 2, 4);
COMMIT;
-- Q.1
INSERT INTO marys_limo_service.driver
VALUES
(3,"Cal","9024919999"),
(4,"Dan","9024914545");
COMMIT;
-- Q.2
INSERT INTO Qualify
values(6,1,3),
(7,2,3),
(8,3,3),
(9,3,4);
select * from Qualify
-- Q.3
UPDATE Rental
SET q_id = 4
where
r_id = 1;
UPDATE Rental
SET q_id = 3
WHERE
r_id = 4;
select * from rental
-- Q.4
CREATE TEMPORARY TABLE Replace_contents
as (SELECT l_id, d_id FROM Qualify
WHERE d_id != 1);
In Oracle, privileged users (such as SYS) can create other users. That would look like this:
SQL> connect sys/pwd as sysdba
Connected.
SQL> select tablespace_name from user_tablespaces;
TABLESPACE_NAME
------------------------------
SYSTEM
SYSAUX
UNDOTBS1
TEMP
USERS
SQL> create user so_test identified by test
2 default tablespace users
3 temporary tablespace temp
4 quota unlimited on users;
User created.
SQL> grant create session, create table, create view to so_test;
Grant succeeded.
Now, connect as newly created user and run code (I fixed); later I'll post code you can reuse. There's no drop if exists in Oracle, so I'm just dropping those tables (paying attention to FK constraints!) and ignoring dropping errors.
Other errors include:
use varchar2, not varchar (that's not exactly an error, but - Oracle recommends it)
use single quotes for strings, not double quotes
either specify date format mask (such as to_date('2015/03/21', 'yyyy/mm/dd')) or use date literal (e.g. date '2015-03-21') or alter session and specify desired format
terminate all commands with semi-colon
insert into should be used for each row separately, unless you use insert all or insert into ... select ... from
OK, here we go:
SQL> connect so_test/test
Connected.
SQL> -- drop them first, because of FK constraints
SQL> drop table rental;
drop table rental
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> drop table qualify;
drop table qualify
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> -- Now, your code, fixed
SQL> DROP TABLE Driver;
DROP TABLE Driver
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> CREATE TABLE Driver(
2 d_id int,
3 d_name varchar2(50),
4 d_contact varchar2(30),
5 CONSTRAINT Driver_d_id PRIMARY KEY(d_id)
6 );
Table created.
SQL> DROP TABLE Limo;
DROP TABLE Limo
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> CREATE TABLE Limo(
2 l_id int,
3 l_callsign varchar2(12),
4 l_type varchar2(40),
5 CONSTRAINT Limo_pk PRIMARY KEY(l_id)
6 );
Table created.
SQL> DROP TABLE Aclient;
DROP TABLE Aclient
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> CREATE TABLE Aclient (
2 c_id int,
3 c_name varchar2(50),
4 c_contact varchar2(30),
5 c_methpmt varchar2(20),
6 CONSTRAINT Aclient_pk PRIMARY KEY(c_id)
7 );
Table created.
SQL> DROP TABLE Qualify;
DROP TABLE Qualify
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> CREATE TABLE Qualify (
2 q_id int,
3 l_id int,
4 d_id int,
5 CONSTRAINT Qualify_q_id_PK PRIMARY KEY(q_id),
6 CONSTRAINT Qualify_l_id_FK FOREIGN KEY(l_id) REFERENCES Limo(l_id),
7 CONSTRAINT Qualify_d_id_FK FOREIGN KEY(d_id) REFERENCES Driver(d_id)
8 );
Table created.
SQL> DROP TABLE Rental;
DROP TABLE Rental
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> CREATE TABLE Rental (
2 r_id INT,
3 r_date DATE,
4 r_fee FLOAT,
5 c_id INT,
6 q_id INT,
7 CONSTRAINT Rental_r_id_PK PRIMARY KEY(r_id),
8 CONSTRAINT Rental_c_id_FK FOREIGN KEY(c_id) REFERENCES Aclient(c_id),
9 CONSTRAINT Rental_q_id_FK FOREIGN KEY(q_id) REFERENCES Qualify(q_id)
10 );
Table created.
SQL> INSERT INTO Driver VALUES (1,'alf','9022332332');
1 row created.
SQL> INSERT INTO Driver VALUES (2,'bob','9022322323');
1 row created.
SQL>
SQL> INSERT INTO Limo VALUES
2 (1,'Car One', 'stretch limo');
1 row created.
SQL> INSERT INTO Limo VALUES
2 (2,'Car Two', 'hummer limo');
1 row created.
SQL> INSERT INTO Limo VALUES
2 (3,'Car Three', 'armored personnel carrier');
1 row created.
SQL>
SQL> INSERT INTO Qualify VALUES
2 (1,1,1);
1 row created.
SQL> INSERT INTO Qualify VALUES
2 (2,2,1);
1 row created.
SQL> INSERT INTO Qualify VALUES
2 (3,3,1);
1 row created.
SQL> INSERT INTO Qualify VALUES
2 (4,1,2);
1 row created.
SQL> INSERT INTO Qualify VALUES
2 (5,2,2);
1 row created.
SQL>
SQL> INSERT INTO Aclient VALUES
2 (1,'ann','9022332332', 'cash');
1 row created.
SQL> INSERT INTO Aclient VALUES
2 (2,'bub','9022322323', 'CC');
1 row created.
SQL> alter session set nls_date_format = 'yyyy/mm/dd';
Session altered.
SQL> INSERT INTO Rental VALUES
2 (1, '2015/3/21', 550, 2, 1);
1 row created.
SQL> INSERT INTO Rental VALUES
2 (2, '2015/3/21', 1000, 1, 5);
1 row created.
SQL> INSERT INTO Rental VALUES
2 (3, '2015/3/20', 2050, 1, 3);
1 row created.
SQL> INSERT INTO Rental VALUES
2 (4, '2015/3/19', 550, 1, 1);
1 row created.
SQL> INSERT INTO Rental VALUES
2 (5, '2015/3/20', 500, 2, 4);
1 row created.
SQL>
SQL> COMMIT;
Commit complete.
SQL>
SQL> -- Q.1
SQL> INSERT INTO driver VALUES
2 (3,'Cal','9024919999');
1 row created.
SQL> INSERT INTO driver VALUES
2 (4,'Dan','9024914545');
1 row created.
SQL> COMMIT;
Commit complete.
SQL>
SQL> -- Q.2
SQL> INSERT INTO Qualify values
2 (6,1,3);
1 row created.
SQL> INSERT INTO Qualify values
2 (7,2,3);
1 row created.
SQL> INSERT INTO Qualify values
2 (8,3,3);
1 row created.
SQL> INSERT INTO Qualify values
2 (9,3,4);
1 row created.
SQL>
SQL> select * from Qualify;
Q_ID L_ID D_ID
---------- ---------- ----------
1 1 1
2 2 1
3 3 1
4 1 2
5 2 2
6 1 3
7 2 3
8 3 3
9 3 4
9 rows selected.
SQL>
SQL>
SQL> -- Q.3
SQL>
SQL> UPDATE Rental
2 SET q_id = 4
3 where
4 r_id = 1;
1 row updated.
SQL>
SQL> UPDATE Rental
2 SET q_id = 3
3 WHERE
4 r_id = 4;
1 row updated.
SQL> select * from rental;
R_ID R_DATE R_FEE C_ID Q_ID
---------- ---------- ---------- ---------- ----------
1 2015/03/21 550 2 4
2 2015/03/21 1000 1 5
3 2015/03/20 2050 1 3
4 2015/03/19 550 1 3
5 2015/03/20 500 2 4
SQL>
SQL> -- Q.4
SQL> drop table replace_contents;
drop table replace_contents
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> CREATE global TEMPORARY TABLE Replace_contents
2 as SELECT l_id, d_id FROM Qualify
3 WHERE d_id != 1;
Table created.
SQL>
Code you can reuse:
-- drop them first, because of FK constraints
drop table rental;
drop table qualify;
-- Now, your code, fixed
DROP TABLE Driver;
CREATE TABLE Driver(
d_id int,
d_name varchar2(50),
d_contact varchar2(30),
CONSTRAINT Driver_d_id PRIMARY KEY(d_id)
);
DROP TABLE Limo;
CREATE TABLE Limo(
l_id int,
l_callsign varchar2(12),
l_type varchar2(40),
CONSTRAINT Limo_pk PRIMARY KEY(l_id)
);
DROP TABLE Aclient;
CREATE TABLE Aclient (
c_id int,
c_name varchar2(50),
c_contact varchar2(30),
c_methpmt varchar2(20),
CONSTRAINT Aclient_pk PRIMARY KEY(c_id)
);
DROP TABLE Qualify;
CREATE TABLE Qualify (
q_id int,
l_id int,
d_id int,
CONSTRAINT Qualify_q_id_PK PRIMARY KEY(q_id),
CONSTRAINT Qualify_l_id_FK FOREIGN KEY(l_id) REFERENCES Limo(l_id),
CONSTRAINT Qualify_d_id_FK FOREIGN KEY(d_id) REFERENCES Driver(d_id)
);
DROP TABLE Rental;
CREATE TABLE Rental (
r_id INT,
r_date DATE,
r_fee FLOAT,
c_id INT,
q_id INT,
CONSTRAINT Rental_r_id_PK PRIMARY KEY(r_id),
CONSTRAINT Rental_c_id_FK FOREIGN KEY(c_id) REFERENCES Aclient(c_id),
CONSTRAINT Rental_q_id_FK FOREIGN KEY(q_id) REFERENCES Qualify(q_id)
);
INSERT INTO Driver VALUES (1,'alf','9022332332');
INSERT INTO Driver VALUES (2,'bob','9022322323');
INSERT INTO Limo VALUES
(1,'Car One', 'stretch limo');
INSERT INTO Limo VALUES
(2,'Car Two', 'hummer limo');
INSERT INTO Limo VALUES
(3,'Car Three', 'armored personnel carrier');
INSERT INTO Qualify VALUES
(1,1,1);
INSERT INTO Qualify VALUES
(2,2,1);
INSERT INTO Qualify VALUES
(3,3,1);
INSERT INTO Qualify VALUES
(4,1,2);
INSERT INTO Qualify VALUES
(5,2,2);
INSERT INTO Aclient VALUES
(1,'ann','9022332332', 'cash');
INSERT INTO Aclient VALUES
(2,'bub','9022322323', 'CC');
alter session set nls_date_format = 'yyyy/mm/dd';
INSERT INTO Rental VALUES
(1, '2015/3/21', 550, 2, 1);
INSERT INTO Rental VALUES
(2, '2015/3/21', 1000, 1, 5);
INSERT INTO Rental VALUES
(3, '2015/3/20', 2050, 1, 3);
INSERT INTO Rental VALUES
(4, '2015/3/19', 550, 1, 1);
INSERT INTO Rental VALUES
(5, '2015/3/20', 500, 2, 4);
COMMIT;
-- Q.1
INSERT INTO driver VALUES
(3,'Cal','9024919999');
INSERT INTO driver VALUES
(4,'Dan','9024914545');
COMMIT;
-- Q.2
INSERT INTO Qualify values
(6,1,3);
INSERT INTO Qualify values
(7,2,3);
INSERT INTO Qualify values
(8,3,3);
INSERT INTO Qualify values
(9,3,4);
select * from Qualify;
-- Q.3
UPDATE Rental
SET q_id = 4
where
r_id = 1;
UPDATE Rental
SET q_id = 3
WHERE
r_id = 4;
select * from rental;
-- Q.4
drop table replace_contents;
CREATE global TEMPORARY TABLE Replace_contents
as SELECT l_id, d_id FROM Qualify
WHERE d_id != 1;
Is there any way to add a constraint to ensure that an entry of X in one column can then only allow an entry of Y in another column?
Say I have two tables, stripped down to minimal columns, tbl_1 has a pk. tbl_2 has 2 columns - a pk and a text string.
These tables are joined by a 3rd relationship table because they're many to many and it uses pk from tbl1 and tbl2.
t1_pk t2_pk | t2_str t1fk | t2fk
x 1 AAA x 1
y 2 BBB x 2
z 3 AAA y 3
4 BBB y 4
z 1
z 2
All entries above are allowed, but now I'm trying to figure out how I can constrict the relationship table so that the string attached to t2_pk can only tie in to the t1_pk ONCE. E.g. in the 3rd table:
t1fk | t2fk
x 3
would not be allowed because x-1 exists and both 1 and 3 have the string AAA attached. One way I can think without making 3 more tables and going round in circles, is to move the string to the relationship table and add a constraint so if the t2fk number exists in the table already it'll only allow the number again if accompanied by the same string.
is there a background process for this I can declare like adding a unique constraint, or would it simply need to be imposed by a stored procedure?
Either you add a t2_str column to your third table that contains the relations or you create a new table for this purpose. Here an example how to implement the new table tab_constr.
drop table if exists tab_constr;
drop table if exists tab_rel;
drop table if exists tab_1;
drop table if exists tab_2;
CREATE TABLE tab_1 (
t1_pk varchar(5),
PRIMARY KEY (t1_pk)
);
CREATE TABLE tab_2 (
t2_pk INT,
t2_str varchar(10) NOT NULL,
PRIMARY KEY (t2_pk),
INDEX(t2_pk, t2_str)
);
CREATE TABLE tab_rel (
t1_pk varchar(5),
t2_pk INT,
PRIMARY KEY (t1_pk,t2_pk),
INDEX (t2_pk),
FOREIGN KEY (t1_pk) REFERENCES tab_1(t1_pk),
FOREIGN KEY (t2_pk) REFERENCES tab_2(t2_pk)
);
CREATE TABLE tab_constr (
t1_pk varchar(5),
t2_str varchar(10),
t2_pk int,
PRIMARY KEY pair_already_exists(t1_pk,t2_str),
INDEX(t1_pk, t2_pk),
INDEX(t2_pk, t2_str),
FOREIGN KEY (t1_pk, t2_pk) REFERENCES tab_rel(t1_pk, t2_pk)
ON DELETE CASCADE,
FOREIGN KEY (t2_pk, t2_str) REFERENCES tab_2(t2_pk, t2_str)
ON UPDATE CASCADE
);
CREATE TRIGGER tr_ins_rel AFTER INSERT ON tab_rel
FOR EACH ROW
BEGIN
INSERT INTO tab_constr ( t1_pk, t2_str, t2_pk)
select new.t1_pk, t2_str, new.t2_pk
from tab_2
where t2_pk=new.t2_pk
;
END;
INSERT INTO tab_1 (t1_pk) VALUES ('x');
INSERT INTO tab_1 (t1_pk) VALUES ('y');
INSERT INTO tab_1 (t1_pk) VALUES ('z');
INSERT INTO tab_2 (t2_pk,t2_str) VALUES (1, 'AAA');
INSERT INTO tab_2 (t2_pk,t2_str) VALUES (2, 'BBB');
INSERT INTO tab_2 (t2_pk,t2_str) VALUES (3, 'AAA');
INSERT INTO tab_2 (t2_pk,t2_str) VALUES (4, 'BBB');
INSERT INTO tab_rel (t1_pk,t2_pk) VALUES ('x', 1);
INSERT INTO tab_rel (t1_pk,t2_pk) VALUES ('x', 2);
INSERT INTO tab_rel (t1_pk,t2_pk) VALUES ('y', 3);
INSERT INTO tab_rel (t1_pk,t2_pk) VALUES ('y', 4);
INSERT INTO tab_rel (t1_pk,t2_pk) VALUES ('z', 1);
INSERT INTO tab_rel (t1_pk,t2_pk) VALUES ('z', 2);
commit;
The following statement will raise an error:
INSERT INTO tab_rel (t1_pk,t2_pk) VALUES ('x', 3);
This also raises an error
UPDATE tab_2 set t2_str='BBB' where t2_pk=1;
But this will work
DELETE FROM tab_rel where t1_pk='x' and t2_pk=1;
INSERT INTO tab_rel (t1_pk,t2_pk) VALUES ('x', 3);
and this will work
UPDATE tab_2 set t2_str='XXX' where t2_pk=1;
Here you can try it out.
Of course this additional table violates normal form and adds redundancy to your database. But that is no problem because this table tab_constr is an auxiliary structure like an index and it will be automatically maintained by the database. So no insert/update/delete anomalies will occur.
I have this MySQL DB :
MySQL in order to create DB + set of test value :
DROP DATABASE IF EXISTS test;
CREATE DATABASE test;
CREATE TABLE table_status ( Id TINYINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, Status CHAR(27) NOT NULL) ENGINE=INNODB;
INSERT INTO table_status (Id, Status) VALUES (1, 'CREATED'), (2, 'UNSURE'), (3, 'RUNNING'), (4, 'BEGIN_ACTION_TRUE'), (5, 'STOPPED_ACTION_TRUE_OK'), (6, 'STOPPED_ACTION_TRUE_NOT_OK'), (7, 'BEGIN_ACTION_FALSE'), (8, 'STOPPED_ACTION_FALSE_OK'), (9, 'STOPPED_ACTION_FALSE_NOT_OK'), (10, 'STOPPED_NOT_OK'), (11, 'STOPPED_OK'), (12, 'CANCEL_REQUESTED'), (13, 'CANCELLED');
CREATE TABLE table_group ( Id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, Status TINYINT UNSIGNED NOT NULL DEFAULT 1, CONSTRAINT fk_group_Status FOREIGN KEY (Status) REFERENCES table_status(Id)) ENGINE=INNODB;
CREATE TABLE table_task ( Id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, IdGroup BIGINT UNSIGNED NOT NULL, Status TINYINT UNSIGNED NOT NULL DEFAULT 1, Command TEXT NOT NULL, CONSTRAINT fk_task_IdGroup FOREIGN KEY (IdGroup) REFERENCES table_group(Id) ON DELETE CASCADE, CONSTRAINT fk_task_Status FOREIGN KEY (Status) REFERENCES table_status(Id)) ENGINE=INNODB;
CREATE TABLE table_dependency ( IdBeforeTask BIGINT UNSIGNED NOT NULL, IdAfterTask BIGINT UNSIGNED NOT NULL, PRIMARY KEY (IdBeforeTask, IdAfterTask), CONSTRAINT fk_dependency_IdBeforeTask FOREIGN KEY (IdBeforeTask) REFERENCES table_task(Id) ON DELETE CASCADE, CONSTRAINT fk_dependency_IdAfterTask FOREIGN KEY (IdAfterTask) REFERENCES table_task(Id) ON DELETE CASCADE) ENGINE=INNODB;
INSERT INTO table_group (Id) VALUES (1), (2), (3), (4);
INSERT INTO table_task (IdGroup, Command) VALUES (1, "command_group_1_task_1"), (1, "command_group_1_task_2"), (1, "command_group_1_task_3"), (2, "command_group_2_task_1"), (2, "command_group_2_task_2"), (2, "command_group_2_task_3"), (3, "command_group_3_task_1"), (3, "command_group_3_task_2"), (3, "command_group_3_task_3"), (4, "command_group_4_task_1"), (4, "command_group_4_task_2"), (4, "command_group_4_task_3");
INSERT INTO table_dependency (IdBeforeTask, IdAfterTask) VALUES (1, 2), (2, 3), (4, 5), (5, 6), (7, 8), (8, 9), (10, 11), (11, 12);
The data in table_status is fixed to this :
INSERT INTO table_status (Id, Status) VALUES
(1, 'CREATED')
(2, 'UNSURE')
(3, 'RUNNING')
(4, 'BEGIN_ACTION_TRUE')
(5, 'STOPPED_ACTION_TRUE_OK')
(6, 'STOPPED_ACTION_TRUE_NOT_OK')
(7, 'BEGIN_ACTION_FALSE')
(8, 'STOPPED_ACTION_FALSE_OK')
(9, 'STOPPED_ACTION_FALSE_NOT_OK')
(10, 'STOPPED_NOT_OK')
(11, 'STOPPED_OK')
(12, 'CANCEL_REQUESTED')
(13, 'CANCELLED')
The purpose is to have a group containing task, each task can be dependant on another one.
What I want to obtain :
Group.Id, NB_TASK_TOTAL, NB_TASK_CREATED, NB_TASK_UNSURE
But there is a trap : The number of NB_TASK_CREATED is defined as : the number of task with status to CREATED and with no unresolved dependency.
An unresolved dependency is defined as a task depend on another wich have a Status != 11 (STOPPED_OK).
So if I have this :
table_dependency :
IdBeforeTask IdAfterTask
1 2
2 3
table_task :
Id IdGroup Status Command
1 1 1 command_1
2 1 1 command_2
3 1 1 command_3
I want to have
Group.Id, NB_TASK_TOTAL, NB_TASK_CREATED, NB_TASK_UNSURE
1 3 1 0
Here my unsucesful try :
SELECT
G.Id,
(SELECT COUNT(T.Id) FROM table_task as T WHERE T.IdGroup = G.Id),
(SELECT COUNT(T.Status = 1) FROM table_task as T WHERE T.IdGroup = G.Id AND T.Id NOT IN (SELECT IdAfterTask from table_dependency as D1 join table_task as T1 on T1.Id=D1.IdBeforeTask WHERE T1.Status!=11)),
(SELECT COUNT(T.Status = 2) FROM table_task as T WHERE T.IdGroup = G.Id)
FROM
table_group as G
The problem is I obtain this :
Group.Id, NB_TASK_TOTAL, NB_TASK_CREATED, NB_TASK_UNSURE
1 3 1 3
2 3 0 3
(I have 4 group, each group containing 3 task, all the task with Status = 1 (CREATED) and the dependency set in order to have just on "resolved" dependency so i should have
Group.Id, NB_TASK_TOTAL, NB_TASK_CREATED, NB_TASK_UNSURE
1 3 1 0
2 3 1 0
instead.
I'm a beginner in MySQL, and i'm lost on this one request.
This should do it for you:
SELECT T.IdGroup as Group_Id,
COUNT(T.IdGroup) as NB_TASK_TOTAL,
(SELECT COUNT(Tt.Id) FROM table_task Tt WHERE Tt.IdGroup = T.IdGroup AND Tt.Status = 1) as NB_TASK_CREATED,
(SELECT COUNT(Tt.Id) FROM table_task Tt WHERE Tt.IdGroup = T.IdGroup AND Tt.Status = 2 AND Tt.Id NOT IN (SELECT IdAfterTask from table_dependency as D1 join table_task as T1 on T1.Id=D1.IdBeforeTask WHERE T1.Status!=11)) as NB_TASK_UNSURE
FROM table_task T
GROUP BY T.IdGroup;