SQL auto-validating data when adding it to row - sql

My SQL code is as follows:
CREATE TABLE personsdb
(personID int IDENTITY(1,1) NOT NULL,
personName varchar(50) NOT NULL,
associatedWith varchar(50) NOT NULL,
CONSTRAINT pk_persondb PRIMARY KEY (personID),
CONSTRAINT uq_persondb UNIQUE (associatedWith))
INSERT INTO personsdb
(personID, personName, associatedWith)
VALUES
('John', 'Mary'),
('Jack', 'Maggie'),
('Jeff', 'Marie')
I have a UNIQUE Constraint on the 'associatedWith' column, as I want to make sure that a person in personName can only be associated with one person in associatedWith, i.e. Mary could not be associated with Jeff because Mary is already associated with John.
My query relates to inserting the next row of the table. I want to insert 'Mary' into the personName column, but need a rule that autopopulates or only allows 'John' to be populated in the corresponding 'associatedWith' field, as a person can only be associated with one other person, and as John is already associated with Mary, when Mary is entered into the table, she should automatically be associated with John.
I'm relatively new to SQL but I'd like to figure it out as much as possible myself - if you could hint at a way to do this (in layman's terms) I'd be grateful so that I can go and research and learn how to do this.
Thanks very much in advance for your help.
David

This is a unary relationship which you cannot implement using foreign keys. You'll have to use a trigger. See below for full implementation.
CREATE TABLE dbo.Person(PersonId int not null primary key identity(1, 1), PersonName varchar(20) not null, AssociatedWith varchar(20));
GO
create trigger dbo.AssociationConstraint
ON dbo.Person
FOR INSERT, UPDATE
AS
IF (EXISTS(SELECT TOP(1) 1 FROM inserted i INNER JOIN dbo.Person p on i.PersonName = p.AssociatedWith)
OR EXISTS(SELECT TOP(1) 1 FROM inserted i INNER JOIN dbo.Person p on i.AssociatedWith = p.PersonName))
BEGIN
RAISERROR('Person is already part of a relationship', 16, 1);
ROLLBACK TRANSACTION;
END
GO
insert into dbo.Person(PersonName, AssociatedWith) values('John', 'Mary'), ('Jack', 'Maggie'), ('Jeff', 'Marie');
--this will error
insert into dbo.Person(PersonName, AssociatedWith) values('Mary', 'Jack');

Related

Why do I receive error 1241 when trying to Create and Insert data into a new table (on phpMyAdmin)?

I am trying to create a new table and insert values into it however I keep receiving "#1241 - Operand should contain 1 column(s)".
Please could someone help to identify what is wrong with my code as I am unsure what this error is referencing?
The code I am inserting into the phpMyAdmin database under the SQL tab. I have tried to remove the auto increment attributes and have tried looking at other examples to check my syntax, but I can't spot the issue. Some guidance on this would be greatly appreciated.
The code I entered begins like this:
# AppSoft Project - Greg Roberts
DROP table if exists Department;
DROP table if exists Role;
DROP table if exists User;
DROP table if exists Appraisal;
DROP table if exists Question;
DROP table if exists Answer;
CREATE table Department(
DeptID int NOT NULL AUTO_INCREMENT,
DeptName varchar(30) NOT NULL,
primary key (DeptID));
INSERT into Department values(
(00, 'SuperAdmin'),
(01, 'Support Staff'),
(02, 'Teaching Staff'),
(03, 'SLT'));
CREATE table Role(
RoleID int NOT NULL AUTO_INCREMENT,
RoleTitle varchar(30) NOT NULL,
primary key (RoleID));
INSERT into Role values(
(00, 'SuperAdmin'),
(01, 'Office Administrator'),
(02, 'Teaching Partner'),
(03, 'Mid Day Supervisor'),
(04, 'Cooks'),
(05, 'Cleaners'),
(06, 'Maintenance'),
(07, 'Teacher'),
(08, 'Department Head'),
(09, 'SENCO'),
(10, 'Head Teacher'),
(11, 'Executive Head'));
Error Code that Occurs
You dont need to insert primary keys, if they are set to auto_increment.
DeptID int NOT NULL AUTO_INCREMENT
Just insert the department name, there are no additional braces required for Values.
INSERT into Department( DeptName) values
('SuperAdmin'),
('Support Staff'),
('Teaching Staff'),
('SLT');
You would need to do the same for Role table as well.
Also if you try to insert 0 into the primary key, it will actually insert 1 you can read about it in the Standard Docs
you seem to be getting the error because your first record inserts 1 into the table and then your second record tries to insert 1 again in the primary key column

Create a view that joins data from other table multiple cells into one oracle sql

I need to create a view that combines two tables (game and developer) together and selects gameID gameName and gameDeveloper from the game table and repaces gameDeveloper with firstname and lastname (from developers table) into one column. gameDeveloper is the same as developerID, but it is not a foreign key yet on purpose. I want to select only firstname and lastname from the row that contains the matching developerID and combine them in one column in my new view. Heres what I have:
CREATE TABLE game (
gameID varchar(3) PRIMARY KEY NOT NULL,
gamenameName varchar(30) NOT NULL,
gameDeveloper varchar(3) NOT NULL
);
INSERT INTO game VALUES (1,'RDR2',2);
INSERT INTO game VALUES (2,'GTAV',7);
INSERT INTO game VALUES (3,'PUBG',9);
/
CREATE TABLE developers (
developerID varchar(3) PRIMARY KEY NOT
NULL,
fname varchar(20) NOT NULL,
lname varchar(20) NOT NULL,
gameID varchar(3) NOT NULL,
CONSTRAINT fk_game
FOREIGN KEY (gameID)
REFERENCES game (GameID)
);
INSERT INTO developers VALUES
(1,'Patrick','Kane',1);
INSERT INTO developers VALUES
(2,'Jonathan','Toews',1);
INSERT INTO developers VALUES
(3,'Alex','Debrincat',1);
INSERT INTO developers VALUES
(4,'Andrew','Shaw',2);
INSERT INTO developers VALUES
(5,'Alex','Nylander',2);
INSERT INTO developers VALUES
(6,'Oli','Maata',2);
INSERT INTO developers VALUES
(7,'Calvin','DeHaan',2);
INSERT INTO developers VALUES
(8,'Brandon','Saad',3);
INSERT INTO developers VALUES
(9,'Corey','Crawford',3);
INSERT INTO developers VALUES
(10,'Connor','Murphy',3);
/
CREATE OR REPLACE VIEW chairs AS
SELECT firstname, lastname
FROM developer
INNER JOIN
I'd like the final table to look something like this with the mapped and combined last cell but I am so lost on what to do.. I figured an inner join would be best?
You can do something like this - JOIN is the equivalent to INNER JOIN but you can be explicit.
CREATE VIEW chairs
AS
SELECT
g.gameID
,g.gamenameName
,d.fname + ' ' + lname AS gameDeveloper
FROM game g
JOIN developers d
ON g.gameDeveloper = d. developerID

Adding new NOT NULL column to existing database

Lets say I have a system that has a person table:
CREATE TABLE Person
(
FirstName NVARCHAR(50) NOT NULL,
LastName NVARCHAR(50) NOT NULL,
DOB DATE NOT NULL
)
If we want to update the system after it has been in place for a number of years and we now want to also capture the person's address (by means of a new NVARCHAR column called Address which is NOT NULL)
Therefore we want all new records to be NOT NULL but we don't have any data for the old records so they would have to be NULL
What is the best way to do this? We cannot add a NOT NULL column because it would be NULL for all the existing records.
Is the best way to add the column and allow NULLS, add some placeholder value (EG '.') to the existing records, then alter the column to be NULL?
Or is there some other way to do it?
You cannot add a new NOT NULL column without assigning non-NULL values to existing rows (via a default constraint). However, you can add a NULL column and ensure only NOT NULL values going forward by specifying a check constraint that prohibits NULL values along with the NOCKECK option so that existing data are not validated:
CREATE TABLE dbo.Person
(
FirstName NVARCHAR(50) NOT NULL,
LastName NVARCHAR(50) NOT NULL,
DOB DATE NOT NULL
)
INSERT INTO dbo.Person (FirstName, LastName , DOB)
VALUES(N'foo', N'bar', '20010101');
GO
--add new column and CHECK constraint with NOCHECK
ALTER TABLE dbo.Person WITH NOCHECK
ADD Address nvarchar(50) NULL
CONSTRAINT CK_Person_Address CHECK (Address IS NOT NULL);
GO
--this fails due to check constraint violation
INSERT INTO dbo.Person (FirstName, LastName , DOB)
VALUES(N'foo2', N'bar2', '20020101');
GO
--this succeeds
INSERT INTO dbo.Person (FirstName, LastName , DOB, Address)
VALUES(N'foo2', N'bar2', '20020101', N'non-null address');
GO
This method provides the proper NULL semantics for existing persons that have no addresses yet guarantee the desired data integrity for new persons.

How to insert value into foreign key in SQL server? (Avoid the duplicate key.)

I create two table. They connected by primary key and foreign key. When I insert new values, it said cannot insert duplicate key in object. Here are my tables
create table person (
sinNum int primary key not null,
gender varchar(6) not null check (gender in ('male','female')) default 'female',
age int not null check (age>=18 and age<=100),
emailAddr varchar (50) not null,
phoneNum int not null,
)
create table employee (
empId int identity (1,1) unique,
lastName varchar (30) not null,
firstName varchar (30) not null,
sinNum int unique foreign key references person (sinNum),
departmentId int foreign key references department (departmentId),
position varchar (20) not null check (position in ('clerk','assistant','supervisor','manager','director','president')) default'clerk',
baseSalary float not null
)
Here are my insert statements
insert into person (sinNum,gender,age,emailAddr, phoneNum) values (333,
'female', 24, 'dds', 2121)
insert into employee(lastName,firstName, sinNum, departmentId,
position,baseSalary) values ('Snow','John',333,20,'clerk',4000)
Here are the error messages
Violation of PRIMARY KEY constraint 'PK__person__228E26BE3A9512B2'.
Cannot insert duplicate key in object 'dbo.person'. The duplicate key
value is (333).
Can anyone show me the way please? Many thanks
You have not set sinNum as identity. Make it auto incremented and then change your insert query as below.
insert into person (sinNum,gender,age,emailAddr, phoneNum) values ((SELECT ISNULL(MAX(sinNum)+1,0) FROM person WITH(SERIALIZABLE, UPDLOCK)),
'female', 24, 'dds', 2121)
You can use simpler version also, but it doesn't guarantee concurrency:
insert into person (sinNum,gender,age,emailAddr, phoneNum) values (NULL,
'female', 24, 'dds', 2121)
Since sinNum is your primary key, if you try to INSERT a new row containing the same value it will reject you.
Just use the following query to delete the rows before adding it again.
DELETE FROM person WHERE sinNum = 333;
You can also update/merge the row or simply not add it, since you have done it already.
As the column 'sinum' is primary key, you can't define it explicitly.
So please have a try with below.
Insert into person (gender,age,emailAddr, phoneNum) values ( 'female', 24, 'dds', 2121)
Declare #sinnum=IDENT_CURRENT('Person')
If ##error=0
Insert into employee(lastName,firstName, sinnum, departmentId, position,baseSalary) values ('Snow','John',#sinnum,20,'clerk',4000)
Ident_current will save the last inserted primary key value in the mentioned table. Saving that value in a temporary variable, inorder to use the same value as FK in the employee table.
##error used here to ensure insert on employee table only on successful insert made in person table.
What's happening here is that your insert on Person table is violating the primary key constraint. So we can use this exception as an antidote.
You can make use of Try-Catch statement and can implement your further logic in the catch block.
/* You an use #output parameter too */
Declare #output bit=1
BEGIN TRY
insert into person (sinNum,gender,age,emailAddr, phoneNum) values (333,
'female', 24, 'dds', 2121)
insert into employee(lastName,firstName, sinNum, departmentId,
position,baseSalary) values ('Snow','John',333,20,'clerk',4000)
print 'Record inserted in both table'
set #output=1
END TRY
BEGIN CATCH
if error_message() like 'Violation of PRIMARY KEY constraint%'
Begin
/* Do whatever you like to do here */
/* You can delete the existing record if you want */
print 'Record already exists is Person table' --just the intimation
set #output=0
End
else
print 'other exception' --just the intimation
END CATCH
You can delete the existing record in catch block or can make new transaction using #output variable.. Hope it works for you.

Oracle SQL Selecting data from one table that relates to another

I do not have that much knowledge of SQL and it is my job to create a basic social network with friendships. To do this, I have created one table (there is more columns but I have removed them for the sake of this question);
CREATE TABLE USERS
(USER_ID CHAR(8) NOT NULL,
USER_LNAME VARCHAR(20) NOT NULL,
USER_FNAME VARCHAR(20) NOT NULL,
PRIMARY KEY (USER_ID));
I have created another table in which you can insert the user_id of two people and it generates the time in which they became friends.
CREATE TABLE USERFRIEND
(USER_ID CHAR(8) NOT NULL,
FRIEND_ID CHAR(8) NOT NULL,
EST_DATE TIMESTAMP NOT NULL,
PRIMARY KEY (USER_ID, FRIEND_ID),
FOREIGN KEY (USER_ID) REFERENCES USERS (USER_ID),
FOREIGN KEY (FRIEND_ID) REFERENCES USERS (USER_ID));
I do not have any trouble inserting the data for either table. For example, here is a sample of the data I have inserted (my actual database has around 15 friends)
INSERT INTO USERS
VALUES ('10000001', 'Jones', 'Tom');
INSERT INTO USERS
VALUES ('10000002', 'Smith', 'Michael');
INSERT INTO USERS
VALUES ('10000003', 'Johnson', 'Andrew');
INSERT INTO USERS
VALUES ('10000004', 'Williams', 'David');
and the friendships
INSERT INTO USERFRIEND
VALUES ('10000001', '100000002', CURRENT_TIMESTAMP);
INSERT INTO USERFRIEND
VALUES ('10000001', '100000003', CURRENT_TIMESTAMP);
INSERT INTO USERFRIEND
VALUES ('10000002', '100000004', CURRENT_TIMESTAMP);
One of the tasks is to get a list of friends that one person has.
For example,
Michael smith would be friends with Tom Jones and David Williams (01, 04)
My issue is that in one friendship, Michael is the user_id and in the other, the friend_id
The best result I have worked out so far is this code;
SELECT user_id, friend_id
FROM USERFRIEND
WHERE USER_ID = 10000002
OR FRIEND_ID = 10000002;
This at least returns the results of all the IDs of people that Smith (10000002) is friends with but I am not sure how to make it return this with the correlating names of those people when both USER_ID and FRIEND_ID both reference the same thing.
SELECT DISTINCT a.user_fname, a.user_lname, b.USER_ID, b.FRIEND_ID
FROM USERS a, USERFRIEND b
WHERE b.USER_ID = 10000002
OR b.FRIEND_ID = 10000002;
I have tried this code and although in my database, there is only 20 friendships made, it returns 80 results and none of the names match up correctly.
Hopefully one of you will find the (probably simple) solution for me because I have no idea what I should be doing.
Your query above makes a cartesian product since there is no join between both the tables. You should have atleast n-1 joins where n is the number of tables used.
You can join both tables like this -
SELECT DISTINCT a.user_fname, a.user_lname, b.USER_ID, b.FRIEND_ID
FROM USERS a, USERFRIEND b
WHERE a.user_id=b.user_id
or a.user_d=b.friend_id