Removing Duplicates added by foriegn key in Oracle DB - sql

I'am working on a Hostel Project in Oracle DB, I have 2 tables (students,rooms) and when I run query to get name of students ,their room IDs and facilities that are provided to them it returns duplicate student names with all the facilities and with little editing in query it returns duplicate facilities.
How can I fix those duplicates?
Here is the Code
--CREATE TABLE STUDENTS
Create table students(
regno integer primary key,
name varchar2(30),
phonenum number,
address varchar2(30),
roomalloc number
);
Alter Table students Add CONSTRAINT fk_roomalloc
FOREIGN KEY (roomalloc)
REFERENCES rooms(roomno);
Alter table students drop constraint fk_roomalloc
--ALTER TABLE STUDENTS ADD JOIN DATE
alter table students add (joindate Date);
--Alter Table for Gender
Alter Table students add(gender varchar2(2));
Alter Table students MODIFY gender NOT NULL;
--Constraint on Gender
Alter Table students Add CONSTRAINT gen
Check (gender IN('M','F','m','f'));
Alter Table students MODIFY mess default 'M';
--Constraint Gender Check for Room Allocation
Alter Table students Add CONSTRAINTS gen_check
Check (Room IN(Gender='M' , 'Gender='F'));
--Constraints:ADD MESS AS TRUE/FALSE
ALTER TABLE students ADD (mess varchar2(4));
Alter Table students Add CONSTRAINT mess_present
Check (mess IN('Yes','No','yes','no'));
Alter Table students MODIFY mess default 'No';
--Drop Constraint
ALTER TABLE students
DROP CONSTRAINT mess_present
--ALTER TABLE NAME AS NOT NULL
alter table students MODIFY name NOT NULL;
--ALTER TABLE PHONE NO
alter table students MODIFY phonenum UNIQUE;
--ALTER TABLE Room Allocated
alter table students MODIFY roomalloc Not Null;
Describe students;
--DATA ENTRY and Modification
INSERT INTO students(regno, name, phonenum, address, roomalloc,joindate,mess)
VALUES (1, 'Haseeb', 012345678,'Rawalpindi',1,'1-sep-14','No');
INSERT INTO students(regno, name, phonenum, address, roomalloc,joindate)
VALUES (2, 'Faisal', 03451111111,'Rawalpindi',1,'12-sep-14');
INSERT INTO students(regno, name, phonenum, address, roomalloc,joindate)
VALUES (3, 'Shahbaz', 03313214567,'Khewra',1,'15-feb-15');
INSERT INTO students(regno, name, phonenum, address, roomalloc,joindate)
VALUES (4, 'Muhaddas', 01235131237,'Kashmir',1,'15-feb-15');
INSERT INTO students(regno, name, phonenum, address, roomalloc,joindate,mess)
VALUES (5, 'Haseem', 01254530987,'Islamabad',2,'15-sep-15','Yes');
INSERT INTO students(regno, name, phonenum, address, roomalloc,joindate,mess)
VALUES (6, 'Asim', 03341234567,'Muzzafargarh',3,'15-sep-14','Yes');
INSERT INTO students(regno, name, phonenum, address, roomalloc,joindate,mess)
VALUES (7, 'Izza', 01231234564,'Sialkot',25,'15-sep-15','Yes');
INSERT INTO students(regno, name, phonenum, address, roomalloc,joindate,mess)
VALUES (8, 'Sara', 01231234561,'Narrowal',25,'15-sep-15','Yes');
INSERT INTO students(regno, name, phonenum, address, roomalloc,joindate,mess)
VALUES (9, 'Maria', 01231234567,'Wah',4,'25-sep-15','Yes');
INSERT INTO students(regno, name, phonenum, address, roomalloc,joindate,Gender)
VALUES (10, 'Faha', 0123123452,'Okara',4,'26-sep-15','F');
Update students SET Gender='M' WHERE regno>=1 And regno<=6;
Update students SET roomalloc=4,Gender='F' WHERE regno>=7 And regno<=9;
Describe students;
--Data Fetching Queries
Select *
From students,rooms
Where rooms.facility='Fan/Net/TV'
ORDER BY roomalloc , regno;
Drop table students;
--CREATE TABLE Rooms
Create table rooms(
roomno integer primary key,
facility varchar2(30)
);
--Altering Rooms Types
Alter Table rooms Add CONSTRAINT rtype
Check (facility IN('AC/Net/TV','Fan/Net/TV','Fan/Net'));
Alter Table rooms MODIFY facility default 'Fan/Net';
Alter table rooms drop constraint str
INSERT INTO rooms( roomno, facility)
VALUES (1,'AC/Net/TV');
INSERT INTO rooms( roomno, facility)
VALUES (2,'Fan/Net/TV');
INSERT INTO rooms( roomno, facility)
VALUES (3,'Fan/Net/TV');
INSERT INTO rooms( roomno, facility)
VALUES (4,'Fan/Net');
Alter table rooms Modify facility UNIQUE
Select *
From rooms;
Select students.name,rooms.facility
From students,rooms
Where roomno=4;
Drop table rooms

You need to join the tables properly to get the desired result:
Select students.name,rooms.facility
From students join rooms on students.roomalloc = rooms.roomno
Where rooms.roomno=4;

Related

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.

How to create a constraint for conditional unique values?

I am using SQL Server. I have this table:
CREATE TABLE Student
(
ID int PRIMARY KEY,
FirstName varchar(100),
LastName varchar(100),
Active bit;
)
I want to have unique(FirstName, LastName) students only if Active = 1. If they are inactive, unique constraint should not trigger. Any idea?
You can't create a CONSTRAINT for that, however, you can create a filtered unique index:
USE Sandbox;
GO
CREATE TABLE dbo.Student (ID int IDENTITY(1, 1) PRIMARY KEY,
FirstName varchar(100),
LastName varchar(100),
Active bit);
CREATE UNIQUE INDEX UQ_StudentName
ON Student (FirstName,LastName)
WHERE Active = 1;
GO
INSERT INTO dbo.Student (FirstName,
LastName,
Active)
VALUES ('Jane', 'Smith', 1); --Success
GO
INSERT INTO dbo.Student (FirstName,
LastName,
Active)
VALUES ('Jane', 'Smith', 0); --Success
GO
INSERT INTO dbo.Student (FirstName,
LastName,
Active)
VALUES ('Jane', 'Smith', 0); --Success
GO
INSERT INTO dbo.Student (FirstName,
LastName,
Active)
VALUES ('Jane', 'Smith', 1); --Fails;
GO
UPDATE dbo.Student
SET Active = 1
WHERE ID = 2; --Fails;
GO
SELECT *
FROM dbo.Student;
GO
DROP TABLE dbo.Student;
I however, highly recommend against the thought that names are unique. I (personally) shared my name and date of birth with another person at several places in my youth and businesses that treated names (and date of birth) as unique on their systems were such a head ache for the both of us (there really were places where I (or they) couldn't register without using an abbreviated name because we "already existed").
Create a filtered unique index:
CREATE UNIQUE INDEX UNI_Student_FirstName_LastName ON Student (FirstName, LastName)
WHERE Active = 1

How can I use RETURNING to UPDATE an id in a temp table in PostgreSQL?

I am importing a file from an outside source. I've already gotten the data into a temp table similar to below. I need to get the person_id from the t_person table into my temp table so that I can do several more operations with it.
I have a workaround by using a key on the temp table that also gets inserted into t_person, but it's messy and it feels like there is another way.
We are using postgresql 9.3, and a version change isn't an option at this time.
CREATE TABLE t_person (person_id serial, first_name text, last_name text);
CREATE TEMPORARY TABLE t1 (person_id integer, first_name text, last_name text);
INSERT INTO t1 (first_name, last_name) values ('john', 'doe'), ('jane', 'doe');
WITH ins1 AS
(
INSERT INTO t_person (first_name, last_name)
SELECT first_name, last_name FROM t1
RETURNING person_id
)
UPDATE t1 SET person_id=ins1.person_id FROM ins1;
The above updates all the rows with the person_id from the final insert (as more or less expected). So is there some way to update only the single row in t1 that was just used to insert into t_person?
Thanks,
Sam

Importing into Gender Field in SQL/SSIS

How would you handle importing only male (m) or female (f) data into a gender field, so that it won't get populated with any potential extraneous source data, in SQL or SSIS?
You can create a column constraint:
CREATE TABLE Persons
(
Id int NOT NULL,
LastName varchar(255),
FirstName varchar(255),
Gender varchar(1),
CONSTRAINT chk_Gender CHECK (Gender ='m' or Gender='f')
)
Insert into Persons values(1,'smith', 'jane', 'f');
insert into Persons values(2,'smith', 'john', SUBSTRING('male', 1, 1));
/* this will fail
INSERT INTO Persons values (3,'foo', 'bar', 'u');
*/
select * FROM Persons;
Working Fiddle
It's trival to add a check constraint, something like:
CREATE TABLE #Test (
GENDER CHAR(1) CONSTRAINT Constraint_Gender CHECK (GENDER IN ('A','B','C'))
)
INSERT INTO #Test VALUES ('A')
INSERT INTO #Test VALUES ('D')
(1 row(s) affected)
Msg 547, Level 16, State 0, Line 9
The INSERT statement conflicted with the CHECK constraint "Constraint_Gender".
However, you should really cater for non-binary genders in a similar manner to facebook etc https://www.facebook.com/facebookdiversity/posts/774221582674346 (hence A, B, C in my example above)

Split One table into Two in SQL Server 2008

I need to break one table (structure built by someone else but I need the data it contains thousands of records) into two new tables I created.
Table Name: Customers_Info (Old Table)
FullName Telephone Address
Adam Johnson 01555777 Michigan
John Smith 01222333 New York
John Smith 01222333 New Jersey
Lara Thomas 01888999 New Mexico
The above is the old table. Now I created two tables to hold the data, one table for customers with a default address, and the other table to hold additional addresses. In the shown example I need 3 persons to be listed in the Customers table, and the address of "John Smith" (the second one New Jersey) to be listed in the Addresses table.
The common field to look at here is "Telephone" and it's unique for every customer.
Here's how the result should be display.
Table Name: Customers (New Table)
CustomerID FullName Telephone Default_Address
1 Adam Johnson 01555777 Michigan
2 John Smith 01222333 New York
3 Lara Thomas 01888999 New Mexico
Table Name: Addresses (New Table)
AddressID CustomerID Address
1 2 New Jersey
Of course it was easy to copy all data into the new Customers table, but what I'm stuck at now, is how to remove the duplicates from Customers and insert them into the Addresses table with the Customer ID and Address only.
Thanks!
Give a try with below code and let me know the comments/results.
CREATE TABLE [Customers_Info]
(
FullName VARCHAR(50)
,Telephone VARCHAR(50)
,Address VARCHAR(50)
)
GO
CREATE TABLE Customers
(
CustomerID INT IDENTITY(1,1)
,FullName VARCHAR(50)
,Telephone VARCHAR(50)
,Default_Address VARCHAR(50)
)
GO
ALTER TABLE dbo.Customers ADD CONSTRAINT PK_Customers
PRIMARY KEY CLUSTERED (CustomerID);
GO
CREATE TABLE Addresses
(
AddressID INT IDENTITY(1,1)
,CustomerID INT
,[Address] VARCHAR(50)
)
GO
ALTER TABLE dbo.Addresses ADD CONSTRAINT PK_Addresses
PRIMARY KEY CLUSTERED (AddressID);
GO
ALTER TABLE Addresses ADD CONSTRAINT FK_CustomerID_Addresses_Customers FOREIGN KEY (CustomerID)
REFERENCES dbo.Customers(CustomerID);
GO
INSERT INTO [Customers_Info] VALUES ('Adam Johnson', '01555777', 'Michigan')
INSERT INTO [Customers_Info] VALUES ('John Smith' , '01222333', 'New York')
INSERT INTO [Customers_Info] VALUES ('John Smith' , '01222333', 'New Jersey')
INSERT INTO [Customers_Info] VALUES ('Lara Thomas' , '01888999', 'New Mexico')
INSERT INTO [Customers_Info] VALUES ('Lara Thomas' , '01888999', 'New Mexico1')
INSERT INTO [Customers_Info] VALUES ('Lara Thomas' , '01888999', 'New Mexico2')
INSERT INTO [Customers_Info] VALUES ('Adam Johnson', '01555777', 'Michigan1')
INSERT INTO [Customers_Info] VALUES ('Adam Johnson', '01555777A', 'Michigan')
INSERT INTO [Customers_Info] VALUES ('Adam Johnson', '01555777A', 'Michigan2')
GO
SELECT * FROM [Customers_Info]
--DELETE FROM Customers
--TRUNCATE TABLE Addresses
------------------------------------------------------------------------------------------------------------------
;WITH a as
(
SELECT FullName,Telephone,[Address],
rn = row_number() over (partition by FullName, Telephone order by FullName)
FROM [Customers_Info]
)
INSERT INTO Customers SELECT
FullName,Telephone,[Address] from a where rn = 1
------------------------------------------------------------------------------------------------------------------
;WITH b as
(
SELECT FullName,Telephone,[Address],
rn = row_number() over (partition by FullName, Telephone order by FullName)
FROM [Customers_Info]
)
INSERT INTO Addresses SELECT CI.CustomerID,b.[Address] FROM Customers CI
INNER JOIN b ON b.FullName=CI.FullName AND b.Telephone=CI.Telephone
WHERE b.rn>1
SELECT * FROM Customers
SELECT * FROM Addresses
DROP TABLE [Customers_Info]
GO
DROP TABLE Addresses
GO
DROP TABLE Customers
GO
It would be more normalized if you broke it up into one more table for three total tables. Have the Customers table that has only customer data, have the Address table (which you could possibly rename to State) that has only the Address, then a CustomerAddress table that has both keys to each of those tables as Foreign Keys.
I will start you off to begin:
INSERT INTO Customers (FullName, Telephone)
SELECT DISTINCT FullName, Telephone
FROM Customers_Info
You would do the same for Address. For the 3rd table, you would perform the lookups like this:
INSERT INTO CustomerAddress (CustomerID, AddressID)
SELECT C.CustomerID, A.AddressID
FROM Customers_Info CI
INNER JOIN Customers C
ON CI.Telephone = C.Telephone
INNER JOIN Address A
ON CI.Address = A.Address