Insert data to column which has two relationships - sql

So, what I want to do in here is I want to insert the data to table1 who has 'username' field, and this 'username' field has two relationships, which is go to student table and teacher table. But, when I insert the data to user table, I have a problem, and the problem caused by this 'username' field. It caused because the data of 'username' field is not the same as a unique key in student table, and when I change it and made the data same, I get an error too, but this time the data is not the same as a unique in teacher table. So, is it possible to make this 'username' field just get one of the table, like if one of student table and teacher table's data is in 'username', it still can be used. Or maybe this is wrong because of bad ERD? Here's my ERD, if you're asking it:
And well, I know this is really, really bad idea but I made the name in teacher table and student table become a unique key, because I can't create foreign key if I didn't do that. Please, I'm really thankful to your answer.
Here's the ddl for that 3 tables :
Student table :
CREATE TABLE [dbo].[student](
[studentid] [int] IDENTITY(2016000001,1) NOT NULL,
[name] [varchar](50) NOT NULL,
[address] [text] NOT NULL,
[gender] [varchar](7) NOT NULL,
[dateofbirth] [date] NOT NULL,
[nohp] [varchar](13) NOT NULL,
CONSTRAINT [PK_student] PRIMARY KEY CLUSTERED
(
[studentid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
CONSTRAINT [IX_student] UNIQUE NONCLUSTERED
(
[name] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
Teacher Table :
CREATE TABLE [dbo].[teacher](
[teacherid] [int] IDENTITY(1,1) NOT NULL,
[name] [varchar](50) NOT NULL,
[gender] [varchar](7) NOT NULL,
CONSTRAINT [PK_teacher] PRIMARY KEY CLUSTERED
(
[teacherid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
CONSTRAINT [IX_teacher] UNIQUE NONCLUSTERED
(
[name] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
User table:
CREATE TABLE [dbo].[user](
[userid] [int] IDENTITY(1,1) NOT NULL,
[username] [varchar](50) NOT NULL,
[password] [varchar](20) NOT NULL,
[role] [varchar](10) NOT NULL,
CONSTRAINT [PK_user] PRIMARY KEY CLUSTERED
(
[userid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[user] WITH CHECK ADD CONSTRAINT [FK_user_student] FOREIGN KEY([username])
REFERENCES [dbo].[student] ([name])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[user] CHECK CONSTRAINT [FK_user_student]
GO
ALTER TABLE [dbo].[user] WITH CHECK ADD CONSTRAINT [FK_user_teacher] FOREIGN KEY([username])
REFERENCES [dbo].[teacher] ([name])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[user] CHECK CONSTRAINT [FK_user_teacher]
GO

The main issue you faced is because your data structure was less than ideal. It did things like prevent you from changing somebody's name. I tossed together a quick example of a cleaner design. There are many assumptions here. I assumed that people have both a first and last name. I would be remiss if I didn't at least point out that assumption is not something you can always make. https://www.kalzumeus.com/2010/06/17/falsehoods-programmers-believe-about-names/ But for a school project it is more than sufficient. I also made the assumption that the addresses are US addresses. Again, this would not work in many real world scenarios. And the last assumption is that everybody can be either Male or Female. In the world today this is not always the case but demonstrates the technique well enough.
Here is how I would probably do this type of design. I would suggest you not just blindly copy this but use it as an idea to get your design more properly normalized.
create table Users
(
UserID int identity not null
, FirstName varchar(50) not null
, LastName varchar(50) not null
, AddressLine1 varchar(50)
, AddressLine2 varchar(50)
, City varchar(50)
, ST char(2)
, ZipCode varchar(9)
, Gender char(1)
, constraint PK_Users primary key clustered
(
UserID
)
, constraint CHK_Users_Gender
CHECK (Gender in ('M', 'F'))
, constraint CHK_Users_ZipCode
CHECK (LEN(ZipCode) in (5,9)) --This ensures you have either the 5 or 9 digiti zip code
)
create table Student
(
StudentID int identity not null
, UserID int not null
, BirthDate date
, constraint PK_Student primary key clustered
(
StudentID
)
, constraint FK_Student_Users foreign key (UserID) references Users(UserID)
)
create table Teacher
(
TeacherID int identity not null
, constraint PK_Teacher primary key clustered
(
TeacherID
)
, constraint FK_Teacher_Users foreign key (TeacherID) references Users(UserID)
)

Related

How to properly create table with 3 columns as primary key?

I have been working with SQL for 3 month, I would like to know create a table with 3 columns as primary key, Any help would be great thank you.
This code below is a Scrip to Create table generated my SQL Server Management Studio of the table
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[REP]
(
[id] [UNIQUEIDENTIFIER] ROWGUIDCOL NOT NULL,
[id_client] [NCHAR](30) NULL,
[id_representant] [UNIQUEIDENTIFIER] NULL,
[date_debut] [DATE] NULL,
[date_fin] [DATE] NULL,
CONSTRAINT [PK_REP]
PRIMARY KEY CLUSTERED ([id] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[REP]
ADD CONSTRAINT [DF_REP_id] DEFAULT (NEWID()) FOR [id]
GO
First all the columns that are part of the primary key have to be not null.
then defining the key just add all columns as comma separated list.
CREATE TABLE [dbo].[REP](
[id] [uniqueidentifier] ROWGUIDCOL NOT NULL,
[id_client] [nchar](30) NOT NULL,
[id_representant] [uniqueidentifier] NULL,
[date_debut] [date] NULL,
[date_fin] [date] NULL,
CONSTRAINT [PK_REP] PRIMARY KEY CLUSTERED
( [id] ASC,id_client ASC )
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]
In the code above I changed the column id_client to be not null and added it to the definition of the primary key ... ([id] ASC, id_client ASC).
To add more columns to a primary Key contraint you'd add the additional fields after the first field.
[id] ASC, nextfield ASC, nextfield2 asc
You can have a one composite key that comprise of more than one primary key.
CREATE TABLE xyz (
primary key (id,id_client,id_representer)
);

How to insert IDENTITY column when creating table by this method (creating IDENTITY in table level)? [duplicate]

I have an existing table that I am about to blow away because I did not create it with the ID column set to be the table's Identity column.
Using SQL Server Management Studio, I scripted a "Create To..." of the existing table and got this:
CREATE TABLE [dbo].[History](
[ID] [int] NOT NULL,
[RequestID] [int] NOT NULL,
[EmployeeID] [varchar](50) NOT NULL,
[DateStamp] [datetime] NOT NULL,
CONSTRAINT [PK_History] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
My question is, how would I modify this SQL so that my resulting table has the ID column set as the Identity?
CREATE TABLE [dbo].[History](
[ID] [int] IDENTITY(1,1) NOT NULL,
[RequestID] [int] NOT NULL,
[EmployeeID] [varchar](50) NOT NULL,
[DateStamp] [datetime] NOT NULL,
CONSTRAINT [PK_History] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
) ON [PRIMARY]
This has already been answered, but I think the simplest syntax is:
CREATE TABLE History (
ID int primary key IDENTITY(1,1) NOT NULL,
. . .
The more complicated constraint index is useful when you actually want to change the options.
By the way, I prefer to name such a column HistoryId, so it matches the names of the columns in foreign key relationships.
[id] [int] IDENTITY(1,1) NOT NULL,
of course since you're creating the table in SQL Server Management Studio you could use the table designer to set the Identity Specification.
Unique key allows max 2 NULL values. Explaination:
create table teppp
(
id int identity(1,1) primary key,
name varchar(10 )unique,
addresss varchar(10)
)
insert into teppp ( name,addresss) values ('','address1')
insert into teppp ( name,addresss) values ('NULL','address2')
insert into teppp ( addresss) values ('address3')
select * from teppp
null string , address1
NULL,address2
NULL,address3
If you try inserting same values as below:
insert into teppp ( name,addresss) values ('','address4')
insert into teppp ( name,addresss) values ('NULL','address5')
insert into teppp ( addresss) values ('address6')
Every time you will get error like:
Violation of UNIQUE KEY constraint 'UQ__teppp__72E12F1B2E1BDC42'. Cannot insert duplicate key in object 'dbo.teppp'.
The statement has been terminated.

How To Create Table with Identity Column

I have an existing table that I am about to blow away because I did not create it with the ID column set to be the table's Identity column.
Using SQL Server Management Studio, I scripted a "Create To..." of the existing table and got this:
CREATE TABLE [dbo].[History](
[ID] [int] NOT NULL,
[RequestID] [int] NOT NULL,
[EmployeeID] [varchar](50) NOT NULL,
[DateStamp] [datetime] NOT NULL,
CONSTRAINT [PK_History] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
My question is, how would I modify this SQL so that my resulting table has the ID column set as the Identity?
CREATE TABLE [dbo].[History](
[ID] [int] IDENTITY(1,1) NOT NULL,
[RequestID] [int] NOT NULL,
[EmployeeID] [varchar](50) NOT NULL,
[DateStamp] [datetime] NOT NULL,
CONSTRAINT [PK_History] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
) ON [PRIMARY]
This has already been answered, but I think the simplest syntax is:
CREATE TABLE History (
ID int primary key IDENTITY(1,1) NOT NULL,
. . .
The more complicated constraint index is useful when you actually want to change the options.
By the way, I prefer to name such a column HistoryId, so it matches the names of the columns in foreign key relationships.
[id] [int] IDENTITY(1,1) NOT NULL,
of course since you're creating the table in SQL Server Management Studio you could use the table designer to set the Identity Specification.
Unique key allows max 2 NULL values. Explaination:
create table teppp
(
id int identity(1,1) primary key,
name varchar(10 )unique,
addresss varchar(10)
)
insert into teppp ( name,addresss) values ('','address1')
insert into teppp ( name,addresss) values ('NULL','address2')
insert into teppp ( addresss) values ('address3')
select * from teppp
null string , address1
NULL,address2
NULL,address3
If you try inserting same values as below:
insert into teppp ( name,addresss) values ('','address4')
insert into teppp ( name,addresss) values ('NULL','address5')
insert into teppp ( addresss) values ('address6')
Every time you will get error like:
Violation of UNIQUE KEY constraint 'UQ__teppp__72E12F1B2E1BDC42'. Cannot insert duplicate key in object 'dbo.teppp'.
The statement has been terminated.

Violation of UNIQUE KEY constraint during SQL update

I have a simple database table (SQL Server 2008 R2 Express), which has a definition as follows:
ID INT Auto Inc, PK
Name VARCHAR(64) Unique Key
Telephone VARCHAR(128)
I have a stored procedure which I execute to update records within the table which basically does the following:
UPDATE customers
SET Name = #name, Telephone = #Telephone
WHERE id = #id
Currently, I have two entries in the table
ID Name Telephone
1 Fred 01234 567890
2 John 09876 543210
When I call my stored procedure to update the telephone number for John, the SQL that is effectively executed is
UPDATE customers
SET Name = 'John', Telephone = '02468 135790'
WHERE id = 2
This generates a UNIQUE KEY violation on the Name field. Now as the Name field doesn't actually change, why does this occur?
As all database actions are being handled by my app using stored procedures, I could fix this by removing the constraint, and modifying the stored procedures to manually enforce the constraint, but this just seems wrong.
Given that my table actually has many more fields, there must be a generic work around that I can employ to prevent these false constraint problems, without having to generate numerous stored procedures to update specific fields?
Edit: The above table was simplified to keep the question more manageable, I'm pretty sure I've not missed anything important, but for info, the actual definition of the table is as follows
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[companies](
[id] [int] IDENTITY(1,1) NOT NULL,
[typeId] [int] NOT NULL,
[name] [varchar](64) NOT NULL,
[displayName] [varchar](128) NOT NULL,
[deliveryAddress] [varchar](1024) NOT NULL,
[invoiceAddress] [varchar](1024) NOT NULL,
[telephone] [varchar](64) NOT NULL,
[fax] [varchar](64) NOT NULL,
[email] [varchar](256) NOT NULL,
[website] [varchar](256) NULL,
[isActive] [bit] NOT NULL,
CONSTRAINT [PK_companies] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
CONSTRAINT [Unique Display Name] UNIQUE NONCLUSTERED
(
[displayName] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
CONSTRAINT [Unique Name] UNIQUE NONCLUSTERED
(
[name] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[companies] WITH CHECK ADD CONSTRAINT [Company Type] FOREIGN KEY([id])
REFERENCES [dbo].[companyTypes] ([id])
GO
ALTER TABLE [dbo].[companies] CHECK CONSTRAINT [Company Type]
GO
...and the stored procedure
ALTER PROCEDURE UpdateCompany
#id INT,
#typeId INT,
#name VARCHAR(64),
#displayName VARCHAR(128),
#deliveryAddress VARCHAR(1024),
#invoiceAddress VARCHAR(1024),
#telephone VARCHAR(64),
#fax VARCHAR(64),
#email VARCHAR(256),
#website VARCHAR(256),
#isActive BIT
AS
BEGIN
UPDATE companies
SET typeid = #typeid,
name = #name,
displayname = #displayname,
deliveryAddress = #deliveryAddress,
invoiceAddress = #invoiceAddress,
telephone = #telephone,
fax = #fax,
email = #email,
website = #website,
isActive = #isActive
EXEC GetCompany #id
END
GO
You're missing the WHERE in your UPDATE statement so currently it will try and update all rows in the table with the same values.

How should I migrate this data into these Sql Server tables?

I wish to migrate some data from a single table into these new THREE tables.
Here's my destination schema:
Notice that I need to insert into the first Location table .. grab the SCOPE_IDENTITY() .. then insert the rows into the Boundary and Country tables.
The SCOPE_IDENTITY() is killing me :( meaning, I can only see a way to do this via CURSORS. Is there a better alternative?
UPDATE
Here's the scripts for the DB Schema....
Location
CREATE TABLE [dbo].[Locations](
[LocationId] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](100) NOT NULL,
[OriginalLocationId] [int] NOT NULL,
CONSTRAINT [PK_Locations] PRIMARY KEY CLUSTERED
(
[LocationId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
)
Country
CREATE TABLE [dbo].[Locations_Country](
[IsoCode] [nchar](2) NOT NULL,
[LocationId] [int] NOT NULL,
CONSTRAINT [PK_Locations_Country] PRIMARY KEY CLUSTERED
(
[LocationId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Locations_Country] WITH CHECK ADD CONSTRAINT [FK_Country_inherits_Location] FOREIGN KEY([LocationId])
REFERENCES [dbo].[Locations] ([LocationId])
GO
ALTER TABLE [dbo].[Locations_Country] CHECK CONSTRAINT [FK_Country_inherits_Location]
GO
Boundary
CREATE TABLE [dbo].[Boundaries](
[LocationId] [int] NOT NULL,
[CentrePoint] [varbinary](max) NOT NULL,
[OriginalBoundary] [varbinary](max) NULL,
[LargeReducedBoundary] [varbinary](max) NULL,
[MediumReducedBoundary] [varbinary](max) NULL,
[SmallReducedBoundary] [varbinary](max) NULL,
CONSTRAINT [PK_Boundaries] PRIMARY KEY CLUSTERED
(
[LocationId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[Boundaries] WITH CHECK ADD CONSTRAINT [FK_LocationBoundary] FOREIGN KEY([LocationId])
REFERENCES [dbo].[Locations] ([LocationId])
GO
ALTER TABLE [dbo].[Boundaries] CHECK CONSTRAINT [FK_LocationBoundary]
GO
I don't see a need for SCOPE_IDENTITY or cursors if you approach the data in order of the parent/child relationship:
INSERT INTO LOCATION
SELECT t.name,
t.originallocationid
FROM ORIGINAL_TABLE t
GROUP BY t.name, t.originallocationid
INSERT INTO COUNTRY
SELECT DISTINCT
t.isocode,
l.locationid
FROM ORIGINAL_TABLE t
JOIN LOCATION l ON l.name = t.name
AND l.originallocationid = t.originalocationid
INSERT INTO BOUNDARY
SELECT DISTINCT
l.locationid,
t.centrepoint,
t.originalboundary,
t.largereducedboundary,
t.mediumreducedboundary,
t.smallreducedboundary
FROM ORIGINAL_TABLE t
JOIN LOCATION l ON l.name = t.name
AND l.originallocationid = t.originalocationid
After loading your Location table you could create a query that joins Location with your source single table. The join criteria would be the natural key (is that the Name column?) and it would return the new LocationId along with the Boundary data. The results would inserted into the new Boundary table.