How to avoid bad data entries in table through proper Key relationship? - sql

I have 3 tables. widgets, widget types, widget type ID. I have created direct relationship between them. How can I avoid bad data going into Widget tables based on Widget_type and Widget_sub_Type. Please see my code. There is just one small thing missing.
Create table widgets (
Widget_ID int not null primary key,
Widget_type_ID int not null,
Widget_Sub_type_ID int,
Widget_Name varchar (50)
)
Create table Widget_Type (
Widget_Type_ID int not null primary key,
)
Create table Widget_Sub_type (
Widget_Sub_Type_ID int not null primary key,
Widget_Type_ID int not null
)
---adding foregin key constraints
Alter table widgets
ADD constraint FK_Widget_Type
FOREIGN KEY (Widget_type_ID)
References Widget_Type (Widget_type_ID)
Alter table widgets
ADD constraint FK_Widget_Sub_Type
FOREIGN KEY (Widget_Sub_type_ID)
References Widget_SUB_Type (Widget_SUB_type_ID)
Alter table widget_Sub_Type
ADD Constraint FK_Widget_Type_Alter
Foreign key (widget_Type_ID)
References Widget_Type (Widget_Type_ID)
---- insert values
insert Widget_Type values (1)
insert Widget_Type values (5)
insert Widget_Sub_type values (3,1)
insert Widget_Sub_type values (4,1)
insert Widget_Sub_type values (7,5)
insert Widget_Sub_type values (9,5)
-- This will error out which is correct
insert Widget_Sub_type values (5,6)
select * from Widget_Sub_type
select * from Widget_type
--Good
insert widgets (Widget_ID,Widget_Name, Widget_type_ID, Widget_Sub_type_ID)
values (1, 'TOY', 1, 3)
select * from widgets
--Good
insert widgets (Widget_ID,Widget_Name, Widget_type_ID, Widget_Sub_type_ID)
values (2, 'BatMan', 5, 7)
-- How to prevenet this, 3 is not sub_type_id of type_ID 5. This is bad data, It should not be inserted.
insert widgets (Widget_ID,Widget_Name, Widget_type_ID, Widget_Sub_type_ID)
values (3, 'Should Not', 5, 3)

Related

SQL table with primary key over two columns and unique values in both columns

How to create a table in SQL with the following attributes?
The table has two columns A and B.
The primary key of the table is (A, B).
All values in A are unique. Pseudo code: (Count(A) == COUNT(SELECT DISTINCT A)).
All values in B are also unique.
CREATE TABLE IF NOT EXISTS myTable(
A VARCHAR(32) PRIMARY KEY NOT NULL, -- A HAS DISTINCT VALUES
B VARCHAR(32) NOT NULL -- B HAS DISTINCT VALUES
);
INSERT INTO myTable VALUES ('A1', 'B1') --> Add value
INSERT INTO myTable VALUES ('A1', 'B2') --> Do not add value
INSERT INTO myTable VALUES ('A2', 'B2') --> Add value
INSERT INTO myTable VALUES ('A3', 'B3') --> Add value
INSERT INTO myTable VALUES ('A4', 'B3') --> Do not add value
INSERT INTO myTable VALUES ('A4', 'B4') --> Add value
INSERT INTO myTable VALUES ('A5', 'B6') --> Add value
To define a compound PRIMARY KEY:
CREATE TABLE myTable
(
A VARCHAR(32) NOT NULL,
B VARCHAR(32) NOT NULL,
CONSTRAINT PK_AB primary key (A,B),
CONSTRAINT UQ_A UNIQUE(A),
CONSTRAINT UQ_B UNIQUE(B)
);
Please note: a table with just 2 columns with both columns in the primary key smells funny.

UNIQUE constraint failed SQL

I want to create two Tables, but it does not work because of "UNIQUE constraint failed".
Can someone explain to me what is wrong with my querees?
CREATE TABLE A (
ka INT PRIMARY KEY,
a2 VARCHAR(1)
);
INSERT INTO A VALUES (1,'s');
INSERT INTO A VALUES (2,'s');
INSERT INTO A VALUES (3,'s');
INSERT INTO A VALUES (4,'m');
INSERT INTO A VALUES (5,'m');
INSERT INTO A VALUES (6,'b');
INSERT INTO A VALUES (7,'b');
INSERT INTO A VALUES (8,'b');
INSERT INTO A VALUES (9,'b');
CREATE TABLE B (
a2 VARCHAR(1),
b2 INT,
PRIMARY KEY (a2),
FOREIGN KEY (a2) REFERENCES A(a2)
);
INSERT INTO B VALUES ('s',12);
INSERT INTO B VALUES ('s',23);
INSERT INTO B VALUES ('s',34);
INSERT INTO B VALUES ('m',45);
INSERT INTO B VALUES ('m',56);
INSERT INTO B VALUES ('b',67);
INSERT INTO B VALUES ('b',78);
INSERT INTO B VALUES ('b',89);
INSERT INTO B VALUES ('b',90);
(Edited: there is more than one issue here.)
A primary key for table B must be unique. In your case, it needs to be something other than a2. If you need a primary key (usually you do just as a part of good design), you likely need a separate dedicated column.
Something like:
CREATE TABLE B (
kb INT,
a2 VARCHAR(1),
b2 INT,
PRIMARY KEY (kb),
--FOREIGN KEY (a2) REFERENCES A(a2) -- This is also an issue
);
INSERT INTO B VALUES (101, 's',12);
INSERT INTO B VALUES (102, 's',23);
INSERT INTO B VALUES (103, 's',34);
INSERT INTO B VALUES (104, 'm',45);
INSERT INTO B VALUES (105, 'm',56);
INSERT INTO B VALUES (106, 'b',67);
INSERT INTO B VALUES (107, 'b',78);
INSERT INTO B VALUES (108, 'b',89);
INSERT INTO B VALUES (109, 'b',90);
EDIT:
The second issue is that your foreign key from table B is referencing a non-unique column in table A. Foreign keys define a many-to-one relationship, but your data indicates a potentially many-to-many relationship. The first three "s" rows in table B each match all three "s" rows in table A. While you can define a JOIN in a query that matches ON B.a2 = A.a2, you can't use a foreign key to define this relationship.

Update multiple tables in trigger where one of the tables is used for trigger activation

Let's say I have two tables called widgetCustomer and widgetSale. On an insert in widgetSale I want to add a timestamp to the widgetSale row and add the sale id as last_order_id to the widgetCustomer table.
I understand using AFTER INSERT ON will result in an error on trying to update the NEW row, hence we need to use BEFORE INSERT ON clause. Which brings forward a new issue that AUTO_INCREMENT has not yet generated a id for sale hence last_order_id would all be zero. There is a method to do this at MySQL/MariaDB TRIGGER but it seems to fail on my system (i.e., the last order ids are still zero).
As a work around I'm using two different triggers one before insert and one after insert. Although it does work I'm keen to learn if there is a possible flaws with the method above and is there a better way of doing this (both in terms of performance and data integrity).
My code is given below:
DROP TABLE IF EXISTS widgetSale;
DROP TABLE IF EXISTS widgetCustomer;
DROP TABLE IF EXISTS widgetLog;
CREATE TABLE widgetCustomer ( id integer primary key AUTO_INCREMENT, name TEXT, last_order_id INT, stamp TEXT );
CREATE TABLE widgetSale ( id integer primary key AUTO_INCREMENT, item_id INT, customer_id INTEGER, quan INT, price INT, stamp TEXT );
CREATE TABLE widgetLog ( id integer primary key AUTO_INCREMENT, stamp TEXT, event TEXT, username TEXT, tablename TEXT, table_id INT);
INSERT INTO widgetCustomer (name) VALUES ('Bob');
INSERT INTO widgetCustomer (name) VALUES ('Sally');
INSERT INTO widgetCustomer (name) VALUES ('Fred');
SELECT * FROM widgetCustomer;
CREATE TRIGGER stampSale BEFORE INSERT ON widgetSale
FOR EACH ROW BEGIN
SET NEW.stamp = CURRENT_TIMESTAMP();
END
CREATE TRIGGER stampOnRest AFTER INSERT ON widgetSale
FOR EACH ROW BEGIN
UPDATE widgetCustomer SET last_order_id = NEW.id, stamp = CURRENT_TIMESTAMP()
WHERE widgetCustomer.id = NEW.customer_id;
INSERT INTO widgetLog (stamp, event, username, tablename, table_id)
VALUES (CURRENT_TIMESTAMP(), 'INSERT', 'TRIGGER', 'widgetSale', NEW.id);
END
INSERT INTO widgetSale (item_id, customer_id, quan, price) VALUES (1, 3, 5, 1995);
INSERT INTO widgetSale (item_id, customer_id, quan, price) VALUES (2, 2, 3, 1495);
INSERT INTO widgetSale (item_id, customer_id, quan, price) VALUES (3, 1, 1, 2995);
SELECT * FROM widgetSale;
SELECT * FROM widgetCustomer;
SELECT * FROM widgetLog;
I'm using mariadb 10.6.* on Archlinux.

SQL doesn't allow me to insert data

creating table and inserting data into a table and now it giving me an error
SQL Error: ORA-02291: integrity constraint (S21403051.SYS_C007300)
violated - parent key not found 02291. 00000 - "integrity
constraint (%s.%s) violated - parent key not found" *Cause:
CREATE TABLE CUSTOMER(
CUSTOMER_ID VARCHAR(10) PRIMARY KEY,
FIRST_NAME VARCHAR(10),
SURNAME VARCHAR(15),
CUSTOMER_TEL VARCHAR(12),
CUSTOMER_EMAIL VARCHAR(30)
)
INSERT INTO CUSTOMER_CRUISES VALUES ( 'CRUISE_1', 'CUST_102', 'EMP_51');
INSERT INTO CUSTOMER_CRUISES VALUES ( 'CRUISE_3','CUST_101','EMP_51');
INSERT INTO CUSTOMER_CRUISES VALUES ( 'CRUISE_3','CUST_101','EMP_53');
INSERT INTO CUSTOMER_CRUISES VALUES ( 'CRUISE_5','CUST_103','EMP_54');
INSERT INTO CUSTOMER_CRUISES VALUES ( 'CRUISE_5','CUST_107','EMP_54');
INSERT INTO CUSTOMER_CRUISES VALUES ( 'CRUISE_1', 'CUST_106','EMP_55');
INSERT INTO CUSTOMER_CRUISES VALUES ( 'CRUISE_1','CUST_108','EMP_55');
INSERT INTO CUSTOMER_CRUISES VALUES ( 'CRUISE_5','CUST_104','EMP_51');
INSERT INTO CUSTOMER_CRUISES VALUES ( 'CRUISE_3','CUST_109','EMP_51');
INSERT INTO CUSTOMER_CRUISES VALUES ( 'CRUISE_2','CUST_1010','EMP_52');
INSERT INTO CUSTOMER_CRUISES VALUES ( 'CRUISE_2','CUST_1010','EMP_55');
INSERT INTO CUSTOMER_CRUISES VALUES ( 'CRUISE_5','CUST_101','EMP_51');
INSERT INTO CUSTOMER_CRUISES VALUES ( 'CRUISE_5','CUST_103','EMP_51');
When you have defined 6 columns CUSTOMER_ID , FIRST_NAME , SURNAME ,
CUSTOMER_TEL,CUSTOMER_EMAIL and when you try to insert values, it takes in order of table definition. Instead you can try this way
Example:
INSERT INTO CUSTOMER_CRUISES
(column1, clumn2,column3)
values ('xx','xy','yz')
Yet, you can not insert duplicate value into first column as primary key is defined on it. And, it cant be null.
Hope this helps
Cause: A foreign key value has no matching primary key value.
This problem arises when you attempt to insert a record containing the Customer_ID column into the child table (CUSTOMER_CRUISES) and that this Customer_ID is not present in the parent table (CUSTOMER). When the Customer_ID (Foreign key) in CUSTOMER_CRUISES table does not get to reference the Customer_ID (primary key) in CUSTOMER table, an error is raised.
One workaround is to insert and make sure that the value is present in the CUSTOMER table first before inserting the values into the CUSTOMER_CRUISES table.

SQL: 2 Foreign Keys referencing one Primary Key

I have a database diagram and need to create a Database with different tables.
This is my code:
use FirmaLieferungen;
drop table liefert;
drop table rabatt;
drop table artikel;
drop table firma;
SET DATEFORMAT dmy;
create table firma (
fnr integer primary key,
name char(10),
jahrgruendung integer, -- Gründungsjahr
land char(3)
);
insert into firma values (101,'Schwer' ,1890,'A' );
insert into firma values (102,'Schmal' ,1901,'CH' );
insert into firma values (103,'Tief' ,1945,'I' );
insert into firma values (104,'Breit' ,1950,'A' );
insert into firma values (105,'Leicht' ,1945,'F' );
insert into firma values (106,'Hoch' ,1920,'CH' );
insert into firma values (107,'Hell' ,1900,'A' );
create table artikel (
fnr integer,
lfdnr integer,
bezeichnung char(10),
preis decimal(6,2),
einheit char(3),
land char(3),
primary key(fnr, lfdnr),
foreign key(fnr) references firma
);
insert into artikel values (101,1,'Schaufel' ,12.30,'Stk','A' );
insert into artikel values (101,2,'Hacke' ,15.20,'Stk','F' );
insert into artikel values (102,1,'Spaten' ,13.00,'Stk','A' );
insert into artikel values (103,1,'Schere' , 8.00,'Stk','A' );
insert into artikel values (103,2,'Messer' ,10.60,'Stk','F' );
insert into artikel values (103,3,'Schnur' , 1.10,'m' ,'D' );
insert into artikel values (105,1,'Schnur' , 0.40,'m' ,'D' );
insert into artikel values (106,1,'Hacke' ,20.70,'Stk','CH' );
insert into artikel values (106,2,'Draht' , 0.60,'m' ,'CH' );
create table liefert (
fnrvon integer,
fnran integer,
fnr integer,
lfdnr integer,
datum date,
menge decimal(8,2)
primary key(fnrvon, fnran, fnr, lfdnr, datum),
foreign key(fnr, lfdnr) references artikel,
foreign key(fnr) references firma
);
insert into liefert values (101,102,101,1,'01.02.1999', 3.00);
insert into liefert values (101,102,101,1,'02.01.2000', 2.00);
insert into liefert values (101,104,101,2,'13.02.2000', 11.00);
insert into liefert values (101,104,101,1,'24.11.1999', 19.00);
insert into liefert values (101,105,103,3,'31.03.2001', 1553.00);
insert into liefert values (102,101,102,1,'21.04.1999', 28.00);
insert into liefert values (102,101,101,1,'11.12.1999', 1.00);
insert into liefert values (102,104,101,1,'04.07.2000', 63.00);
insert into liefert values (103,101,103,3,'21.04.1999', 3.25);
insert into liefert values (103,104,101,1,'08.02.1998', 17.00);
insert into liefert values (104,102,105,1,'19.11.2001', 132.50);
insert into liefert values (104,106,101,1,'04.07.2000', 22.00);
insert into liefert values (106,102,101,1,'07.08.2002', 81.00);
insert into liefert values (106,102,106,2,'01.06.2002', 21.30);
insert into liefert values (106,104,101,1,'26.09.2001', 2.00);
create table rabatt (
fnrvon integer,
fnran integer,
prozent decimal (5,2),
primary key (fnrvon, fnran),
foreign key (fnrvon, fnran) references firma
);
insert into rabatt values (101,102, 5.25);
insert into rabatt values (102,101, 5.50);
insert into rabatt values (101,103,15.75);
insert into rabatt values (103,102, 7.50);
insert into rabatt values (102,103,10.50);
insert into rabatt values (105,106, 5.25);
insert into rabatt values (104,101, 7.50);
select * from rabatt;
select * from firma;
select * from liefert;
select * from artikel;
But there's an error in the 'rabatt' creation, it says that the last command is invalid.
foreign key (fnrvon, fnran) references firma
This is somehow wrong, but I don't know why... Is the diagram wrong? There are also two keys going from 'liefert' to 'firma' how do I do this? Please help me!
Thanks! (I'm using Microsoft SQL Server 2008)
When you reference another table, you should specify which column(s) you are referencing.
So, for example:
create table liefert (
fnrvon integer,
fnran integer,
fnr integer,
lfdnr integer,
datum date,
menge decimal(8,2)
primary key(fnrvon, fnran, fnr, lfdnr, datum),
foreign key(fnr, lfdnr) references artikel (fnr, lfdnr),
foreign key(fnr) references firma (fnr)
);
Mureinik is right, just answered 1 sec before me.
For the sake of the question I crated a Fiddle Improve it for further questions
http://sqlfiddle.com/#!6/6a1b7
Your firma table doesn't have columns named fnrvon or fnran so
foreign key (fnrvon, fnran) references firma
fails to figure out what is referenced.
You need to be explicit. Also, If the two columns are both referencing the same foreign key, then it needs to be two separate statements
foreign key (fnran) references firma (fnr)
foreign key (fnrvon) references firma (fnr)