Foreign Key Error in Oracle to SQL Server Migration - sql

So I have been tasked with converting an Oracle DB to SQL Server. I have never worked with DB's before so I am just running MS SQL Server Migration Assistant to start and only received one error regarding foreign keys. I have done some research but don't understand the principal enough to know how the change needs to be made. Below are the Oracle and SQL Tables from the migration. At the very bottom is the error on the SQL Server side. If anyone could lead me in the right direction I would appreciate it.
Oracle Table:
CREATE TABLE XYZUSER.XYZCMDARGS
(
CMDROWKEY NUMBER(10, 0) NOT NULL,
CMDARGNUM NUMBER(3, 0) NOT NULL,
MEMBERNAME VARCHAR2(50) NOT NULL,
MEMBERTYPE NUMBER(1, 0) NOT NULL,
ARGFORMAT NUMBER(1, 0) NOT NULL,
STARTBIT NUMBER(2, 0) NOT NULL,
TOTALBITS NUMBER(2, 0) NOT NULL,
MSBORLSBFIRST CHAR(1) NOT NULL,
MEMBERVALUE NUMBER(20, 0) NOT NULL,
STATELIST VARCHAR2(200) NOT NULL,
RANGEHIGHFLOAT FLOAT(52) NOT NULL,
RANGELOWFLOAT FLOAT(52) NOT NULL,
RANGEHIGHINT NUMBER(20, 0) NOT NULL,
RANGELOWINT NUMBER(20, 0) NOT NULL,
UNITS CHAR(8) NOT NULL,
INCRPERBIT FLOAT(52) NOT NULL,
ARGPROCESSING NUMBER(1, 0) NOT NULL
);
ALTER TABLE XYZUSER.XYZCMDARGS ADD CONSTRAINT XYZCMDARGS_PK
PRIMARY KEY (CMDROWKEY, CMDARGNUM);
ALTER TABLE XYZUSER.XYZCMDARGS ADD CONSTRAINT XYZCMDARGS_CMDROWKEY_FK
FOREIGN KEY (CMDROWKEY)
REFERENCES XYZUSER.XYZCMDS (CMDROWKEY);
SQL Server:
IF EXISTS (SELECT * FROM sys.objects so JOIN sys.schemas sc ON so.schema_id = sc.schema_id WHERE so.name = N'XYZCMDARGS' AND sc.name = N'XYZUSER' AND type in (N'U'))
BEGIN
DECLARE #drop_statement nvarchar(500)
DECLARE drop_cursor CURSOR FOR
SELECT 'alter table '+quotename(schema_name(ob.schema_id))+
'.'+quotename(object_name(ob.object_id))+ ' drop constraint ' + quotename(fk.name)
FROM sys.objects ob INNER JOIN sys.foreign_keys fk ON fk.parent_object_id = ob.object_id
WHERE fk.referenced_object_id =
(
SELECT so.object_id
FROM sys.objects so JOIN sys.schemas sc
ON so.schema_id = sc.schema_id
WHERE so.name = N'XYZCMDARGS' AND sc.name = N'XYZUSER' AND type in (N'U')
)
OPEN drop_cursor
FETCH NEXT FROM drop_cursor
INTO #drop_statement
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC (#drop_statement)
FETCH NEXT FROM drop_cursor
INTO #drop_statement
END
CLOSE drop_cursor
DEALLOCATE drop_cursor
DROP TABLE [XYZUSER].[XYZCMDARGS]
END
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE
[XYZUSER].[XYZCMDARGS]
(
[CMDROWKEY] numeric(10, 0) NOT NULL,
[CMDARGNUM] numeric(3, 0) NOT NULL,
[MEMBERNAME] varchar(50) NOT NULL,
[MEMBERTYPE] numeric(1, 0) NOT NULL,
[ARGFORMAT] numeric(1, 0) NOT NULL,
[STARTBIT] numeric(2, 0) NOT NULL,
[TOTALBITS] numeric(2, 0) NOT NULL,
[MSBORLSBFIRST] char(1) NOT NULL,
[MEMBERVALUE] numeric(20, 0) NOT NULL,
[STATELIST] varchar(200) NOT NULL,
[RANGEHIGHFLOAT] float(52) NOT NULL,
[RANGELOWFLOAT] float(52) NOT NULL,
[RANGEHIGHINT] numeric(20, 0) NOT NULL,
[RANGELOWINT] numeric(20, 0) NOT NULL,
[UNITS] char(8) NOT NULL,
[INCRPERBIT] float(52) NOT NULL,
[ARGPROCESSING] numeric(1, 0) NOT NULL
)
WITH (DATA_COMPRESSION = NONE)
GO
IF EXISTS (SELECT * FROM sys.objects so JOIN sys.schemas sc ON so.schema_id = sc.schema_id WHERE so.name = N'XYZCMDARGS_PK' AND sc.name = N'XYZUSER' AND type in (N'PK'))
ALTER TABLE [XYZUSER].[XYZCMDARGS] DROP CONSTRAINT [XYZCMDARGS_PK]
GO
ALTER TABLE [XYZUSER].[XYZCMDARGS]
ADD CONSTRAINT [XYZCMDARGS_PK]
PRIMARY KEY
CLUSTERED ([CMDROWKEY] ASC, [CMDARGNUM] ASC)
GO
IF EXISTS (SELECT * FROM sys.objects so JOIN sys.schemas sc ON so.schema_id = sc.schema_id WHERE so.name = N'XYZCMDARGS_CMDROWKEY_FK' AND sc.name = N'XYZUSER' AND type in (N'F'))
ALTER TABLE [XYZUSER].[XYZCMDARGS] DROP CONSTRAINT [XYZCMDARGS_CMDROWKEY_FK]
GO
/*
* SSMA error messages:
* O2SS0231: Foreign keys with different types of columns and referenced columns cannot be converted:XYZCMDARGS_CMDROWKEY_FK.
ALTER TABLE [XYZUSER].[XYZCMDARGS]
ADD CONSTRAINT [XYZCMDARGS_CMDROWKEY_FK]
FOREIGN KEY
([CMDROWKEY])
REFERENCES
[ACEDB1A].[XYZUSER].[XYZCMDS] ([CMDROWKEY])
ON DELETE NO ACTION
ON UPDATE NO ACTION
*/

The issue appears to be that the parent table column XYZUSER.XYZCMDS (CMDROWKEY) is declared as a NUMBER(9,0) while the child table column XYZUSER.XYZCMDARGS (CMDROWKEY) is declared as a NUMBER(10,0). Since the child table declared a larger column than the parent table allows, it is probably safe to change the child table column to a NUMBER(9,0) (assuming nothing weird is going on where the child table was allowed to store values that are larger than what the parent table allows). Alternately, you could redefine the parent table column as a NUMBER(10,0) but then you'd need to redefine the column in any other child tables that reference this parent.

Related

Check column data type and change it in SQL Server

All I want to do is check if the hire_state column's data type is bit, and if so, change it to SmallInt.
Here is my code
IF OBJECT_ID(N'dbo.employees') IS NULL
BEGIN
CREATE TABLE dbo.employees
(
employees_id INT IDENTITY(1, 1) PRIMARY KEY,
employees_number INT NOT NULL,
first_name NVARCHAR(120) NOT NULL,
last_name NVARCHAR(120) NOT NULL,
birthday DATE NOT NULL,
gender TINYINT NOT NULL,
hire_date DATE NOT NULL,
phone1 NCHAR(25) NOT NULL,
phone2 NVARCHAR(25),
home_address NVARCHAR(255) NOT NULL,
granty NVARCHAR(250),
hire_state BIT NOT NULL DEFAULT 1,
leave_Date DATE,
job SMALLINT NOT NULL
);
END
ELSE
BEGIN
IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS C
WHERE C.TABLE_NAME = N'employees'
AND C.COLUMN_NAME = 'employee_image')
ALTER TABLE dbo.employees
ADD employee_image NVARCHAR(255)
ALTER TABLE dbo.employees
ALTER COLUMN hire_state TINYINT NOT NULL
END;
How can I check whether hire_state is bit or not and then change it to TinyInt?
When I execute my code shown above, I get this error
Msg 5074, Level 16, State 1, Line 49
The object 'DF__employees__hire___267ABA7A' is dependent on column 'hire_state'.
Msg 4922, Level 16, State 9, Line 49
ALTER TABLE ALTER COLUMN hire_state failed because one or more objects access this column.
I did not use hire_state in any other table
Ok I Change my code base on comment and it work
IF EXISTS (SELECT * FROM sys.columns WHERE name =
N'hire_state' AND
object_id= OBJECT_ID('dbo.employees') AND
system_type_id = 104)
BEGIN
ALTER TABLE dbo.employees DROP CONSTRAINT DF__employees__hire___267ABA7A
ALTER TABLE dbo.employees ALTER COLUMN hire_state TINYINT NOT NULL
END;

Trouble using an equal sign in SQL trigger

This is my table:
CREATE TABLE [dbo].[tblVisitors] (
[Id] BIGINT IDENTITY (1, 1) NOT NULL,
[IP] NVARCHAR (100) NOT NULL,
[ProfileId] INT NULL,
[DateVisit] DATE NOT NULL,
[TimeVisit] TIME (0) NOT NULL,
[Browser] NVARCHAR (50) NOT NULL,
[UserOS] NVARCHAR (500) NOT NULL,
CONSTRAINT [PK_tblVisitors] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_tblVisitors_tblProfile] FOREIGN KEY ([ProfileId]) REFERENCES [dbo].[tblProfile] ([Id]) ON DELETE SET NULL
);
I wrote a trigger to avoid redundancy:
CREATE TRIGGER [dbo].[Trigger_tblVisitors_OnInsert]
ON [dbo].[tblVisitors]
INSTEAD OF INSERT
AS
BEGIN
SET NoCount ON;
DECLARE #C INT;
SELECT *
INTO #TEMP
FROM inserted A
WHERE
NOT EXISTS (SELECT *
FROM tblVisitors B
WHERE (A.IP = B.IP)
AND (A.DateVisit = B.DateVisit)
AND (A.ProfileId = B.ProfileId));
IF (SELECT COUNT(*) FROM #TEMP) = 0
BEGIN
PRINT 'DUPLICATE RECORD DETECTED';
ROLLBACK TRANSACTION;
RETURN;
END
INSERT INTO tblVisitors (IP, ProfileId, DateVisit, TimeVisit, Browser, UserOS)
SELECT IP, ProfileId, DateVisit, TimeVisit, Browser, UserOS
FROM #TEMP;
END
But as this part of the code does not work, redundancy occurs:
(A.ProfileId = B.ProfileId)
Because after deleting this section, the operation is performed correctly. But this condition must be checked.
Using my psychic skills, I suspect that you have ProfileId values that are null, and in SQL the expression null = null is not true, but your logic requires it to be true.
Try this:
AND (A.ProfileId = B.ProfileId OR (A.ProfileId IS NULL AND B.ProfileId IS NULL))

Creating a single table for two different entities

What is an appropriate way to structure the database table for the following scenario?
I'm trying to model an incident report, part of it will be recording whether (as part of the incident) an employee or customer had to receive medical attention. The same details are to be recorded for both. In the paper version of the form and in the interface, it is shown as a single table. The table headings would be:
Person (either employee or customer)
Injured
First aid administered
Hospitalised
Details
We already have separate employee and customer tables which old their personal details. The new table would include the ID, details on whether the person was injured, received first aid, hospitalised and any other additional details.
So I've been pondering on a few possibilities of how this could be structured:
Two separate tables for employee and customer incidents. The two tables will hold mostly the same fields with the exception of the foreign keys for EmployeeID or CustomerID.
A single table that includes all the incident related fields and additional fields for EmployeeID and CustomerID where these are nullable foreign keys to the primary keys of the Employee and Customer table respectively. A constraint to ensure that EmployeeID XOR CustomerID is not null.
Create 3 new tables: one to just hold the incidents, one to link customer ID with an incident and another to link employee ID with an incident - is this too normalised? (assuming I will never have more than customers or employees to record incident details for)
A single table that includes all the incident related fields with a single field to store either the employee ID or customer ID and a type field to specify whether it's employee or customer.
I'm leaning towards option 1, it seems to be the cleanest and should different fields need to be recorded for customers and employees, it's easy to update a single table without affecting the other. I've discounted option 4, I think this is bad design since I'm not able to add a FK constraint to the ID column.
Are there any reasons why I shouldn't go for option 1 or are there better alternatives I should also consider?
I would create "link" tables. And not repeat the DDL for the Incident.
then you have the ability to create a view which would bring together customers and employees with the incident data.
I agree with the previous answer to separate the incident details.
-- START TSQL
SET NOCOUNT ON
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'vwIncidents' and TABLE_TYPE = N'VIEW' )
BEGIN
DROP VIEW [dbo].[vwIncidents]
END
GO
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'CustomerToIncidentLink' and TABLE_TYPE = N'BASE TABLE' )
BEGIN
DROP TABLE [dbo].[CustomerToIncidentLink]
END
GO
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'EmployeeToIncidentLink' and TABLE_TYPE = N'BASE TABLE' )
BEGIN
DROP TABLE [dbo].[EmployeeToIncidentLink]
END
GO
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'Incident' and TABLE_TYPE = N'BASE TABLE' )
BEGIN
DROP TABLE [dbo].[Incident]
END
GO
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'Employee' and TABLE_TYPE = N'BASE TABLE' )
BEGIN
DROP TABLE [dbo].[Employee]
END
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'Customer' and TABLE_TYPE = N'BASE TABLE' )
BEGIN DROP TABLE [dbo].[Customer]
END
CREATE TABLE [dbo].[Employee] (
[EmployeeUUID] [uniqueidentifier] NOT NULL,
[TheVersionProperty] [timestamp] NOT NULL,
[SSN] [nvarchar](11) NOT NULL,
[LastName] [varchar](64) NOT NULL,
[FirstName] [varchar](64) NOT NULL,
[CreateDate] [datetime] NOT NULL,
[HireDate] [datetime] NOT NULL
)
GO
ALTER TABLE dbo.Employee ADD CONSTRAINT PK_Employee PRIMARY KEY NONCLUSTERED (EmployeeUUID)
GO
ALTER TABLE [dbo].[Employee] ADD CONSTRAINT CK_SSN_Unique UNIQUE (SSN)
GO
CREATE TABLE [dbo].[Customer] (
[CustomerUUID] [uniqueidentifier] NOT NULL,
[TheVersionProperty] [timestamp] NOT NULL,
[CustomerNumber] [nvarchar](11) NOT NULL,
[LastName] [varchar](64) NOT NULL,
[FirstName] [varchar](64) NOT NULL,
[CreateDate] [datetime] NOT NULL
)
GO
ALTER TABLE dbo.Customer ADD CONSTRAINT PK_Customer PRIMARY KEY NONCLUSTERED (CustomerUUID)
GO
ALTER TABLE [dbo].[Customer] ADD CONSTRAINT CK_CustomerNumber_Unique UNIQUE (CustomerNumber)
GO
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id(N'[dbo].[Incident]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
BEGIN DROP TABLE [dbo].[Incident]
END
GO
CREATE TABLE [dbo].[Incident]
(
IncidentUUID [UNIQUEIDENTIFIER] NOT NULL DEFAULT NEWSEQUENTIALID()
, IncidentName varchar(24) not null
, CreateDate smalldatetime not null
)
GO
ALTER TABLE dbo.Incident ADD CONSTRAINT PK_Incident PRIMARY KEY NONCLUSTERED (IncidentUUID)
GO
ALTER TABLE [dbo].[Incident] ADD CONSTRAINT CK_IncidentName_Unique UNIQUE (IncidentName)
GO
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id(N'[dbo].[EmployeeToIncidentLink]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
BEGIN DROP TABLE [dbo].[EmployeeToIncidentLink]
END
GO
CREATE TABLE [dbo].[EmployeeToIncidentLink] (
[LinkSurrogateUUID] [uniqueidentifier] NOT NULL,
[TheEmployeeUUID] [uniqueidentifier] NOT NULL,
[TheIncidentUUID] [uniqueidentifier] NOT NULL
)
GO
ALTER TABLE dbo.EmployeeToIncidentLink ADD CONSTRAINT PK_EmployeeToIncidentLink PRIMARY KEY NONCLUSTERED (LinkSurrogateUUID)
GO
ALTER TABLE [dbo].[EmployeeToIncidentLink] ADD CONSTRAINT FK_EmployeeToIncidentLinkToEmployee FOREIGN KEY (TheEmployeeUUID) REFERENCES dbo.Employee (EmployeeUUID)
GO
ALTER TABLE [dbo].[EmployeeToIncidentLink] ADD CONSTRAINT FK_EmployeeToIncidentLinkToIncident FOREIGN KEY (TheIncidentUUID) REFERENCES dbo.Incident (IncidentUUID)
GO
ALTER TABLE [dbo].[EmployeeToIncidentLink] ADD CONSTRAINT CONST_UNIQUE_EmpUUID_InciUUID UNIQUE (TheEmployeeUUID , TheIncidentUUID)
GO
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id(N'[dbo].[CustomerToIncidentLink]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
BEGIN DROP TABLE [dbo].[CustomerToIncidentLink]
END
GO
CREATE TABLE [dbo].[CustomerToIncidentLink] (
[LinkSurrogateUUID] [uniqueidentifier] NOT NULL,
[TheCustomerUUID] [uniqueidentifier] NOT NULL,
[TheIncidentUUID] [uniqueidentifier] NOT NULL
)
GO
ALTER TABLE dbo.CustomerToIncidentLink ADD CONSTRAINT PK_CustomerToIncidentLink PRIMARY KEY NONCLUSTERED (LinkSurrogateUUID)
GO
ALTER TABLE [dbo].[CustomerToIncidentLink] ADD CONSTRAINT FK_CustomerToIncidentLinkToCustomer FOREIGN KEY (TheCustomerUUID) REFERENCES dbo.Customer (CustomerUUID)
GO
ALTER TABLE [dbo].[CustomerToIncidentLink] ADD CONSTRAINT FK_CustomerToIncidentLinkToIncident FOREIGN KEY (TheIncidentUUID) REFERENCES dbo.Incident (IncidentUUID)
GO
ALTER TABLE [dbo].[CustomerToIncidentLink] ADD CONSTRAINT CONST_UNIQUE_CustomerUUID_InciUUID UNIQUE (TheCustomerUUID , TheIncidentUUID)
GO
CREATE VIEW dbo.vwIncidents
AS
/* combine what is in common with employees and customers for this view */
select e.LastName, e.FirstName, inc.IncidentName
from dbo.Employee e
join
dbo.EmployeeToIncidentLink link on e.EmployeeUUID = link.TheEmployeeUUID
join
dbo.Incident inc on inc.IncidentUUID = link.TheIncidentUUID
UNION ALL
select c.LastName, c.FirstName, inc.IncidentName
from dbo.Customer c
join
dbo.CustomerToIncidentLink link on c.CustomerUUID = link.TheCustomerUUID
join
dbo.Incident inc on inc.IncidentUUID = link.TheIncidentUUID
GO
There is another option (I think?)
Create a Person table, (this has info in common with customers and employees) and then create "sub class" tables for customer and employee that has unique to that entity data.
That's a topic unto itself.
See
How do we implement an IS-A Relationship?
"IS A"
or "how to subclass in a database" would be search tips.
I have this example that is close to yours, that does a "subclassing"
-- START TSQL
SET NOCOUNT ON
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'vwPersonEmail' and TABLE_TYPE = N'VIEW' )
BEGIN
DROP VIEW [dbo].[vwPersonEmail]
END
GO
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'PersonEmail' and TABLE_TYPE = N'BASE TABLE' )
BEGIN
DROP TABLE [dbo].[PersonEmail]
END
GO
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'Customer' and TABLE_TYPE = N'BASE TABLE' )
BEGIN
DROP TABLE [dbo].[Customer]
END
GO
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'Employee' and TABLE_TYPE = N'BASE TABLE' )
BEGIN
DROP TABLE [dbo].[Employee]
END
GO
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'PersonSuperType' and TABLE_TYPE = N'BASE TABLE' )
BEGIN
DROP TABLE [dbo].[PersonSuperType]
END
GO
IF EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = N'dbo' and TABLE_NAME = N'Department' and TABLE_TYPE = N'BASE TABLE' )
BEGIN
DROP TABLE [dbo].[Department]
END
GO
CREATE TABLE [dbo].[Department](
[DepartmentUUID] [uniqueidentifier] NOT NULL,
[TheVersionProperty] [timestamp] NOT NULL,
[DepartmentName] [nvarchar](80) NULL,
[CreateDate] [datetime] NOT NULL,
[MyTinyInt] tinyint not null
)
ALTER TABLE dbo.[Department] ADD CONSTRAINT PK_Department PRIMARY KEY NONCLUSTERED ([DepartmentUUID])
GO
ALTER TABLE [dbo].[Department] ADD CONSTRAINT CK_DepartmentName_Unique UNIQUE ([DepartmentName])
GO
CREATE TABLE [dbo].[PersonSuperType] (
[PersonSuperTypeUUID] [uniqueidentifier] not null default NEWSEQUENTIALID(),
[LastName] [varchar](64) NOT NULL,
[FirstName] [varchar](64) NOT NULL
)
GO
ALTER TABLE dbo.PersonSuperType ADD CONSTRAINT PK_PersonSuperTypeUUID PRIMARY KEY CLUSTERED (PersonSuperTypeUUID)
GO
CREATE TABLE [dbo].[Employee] (
[EmployeeUUID] [uniqueidentifier] NOT NULL,
[ParentDepartmentUUID] [uniqueidentifier] NOT NULL,
[TheVersionProperty] [timestamp] NOT NULL,
[SSN] [nvarchar](11) NOT NULL,
[CreateDate] [datetime] NOT NULL,
[HireDate] [datetime] NOT NULL
)
GO
ALTER TABLE dbo.Employee ADD CONSTRAINT PK_Employee PRIMARY KEY NONCLUSTERED (EmployeeUUID)
GO
ALTER TABLE [dbo].[Employee] ADD CONSTRAINT CK_SSN_Unique UNIQUE (SSN)
GO
ALTER TABLE [dbo].[Employee] ADD CONSTRAINT FK_EmployeeToDepartment FOREIGN KEY (ParentDepartmentUUID) REFERENCES dbo.Department (DepartmentUUID)
GO
ALTER TABLE [dbo].[Employee] ADD CONSTRAINT FK_EmployeeToPersonSuperType FOREIGN KEY (EmployeeUUID) REFERENCES dbo.PersonSuperType (PersonSuperTypeUUID)
GO
CREATE TABLE [dbo].[Customer] (
[CustomerUUID] [uniqueidentifier] NOT NULL,
[TheVersionProperty] [timestamp] NOT NULL,
[CustomerNumber] [nvarchar](11) NOT NULL,
[CreateDate] [datetime] NOT NULL,
)
GO
ALTER TABLE [dbo].[Customer] ADD CONSTRAINT PK_Customer PRIMARY KEY NONCLUSTERED (CustomerUUID)
GO
ALTER TABLE [dbo].[Customer] ADD CONSTRAINT CK_Customer_CustomerNumber_Unique UNIQUE (CustomerNumber)
GO
ALTER TABLE [dbo].[Customer] ADD CONSTRAINT FK_CustomerToPersonSuperType FOREIGN KEY (CustomerUUID) REFERENCES dbo.PersonSuperType (PersonSuperTypeUUID)
GO
CREATE TABLE [dbo].[PersonEmail] (
[PersonEmailUUID] [uniqueidentifier] NOT NULL,
[PersonSuperTypeUUID] [uniqueidentifier] NOT NULL,
[EmailAddress] [varchar](256) NOT NULL
)
GO
ALTER TABLE [dbo].[PersonEmail] ADD CONSTRAINT PK_PersonEmail PRIMARY KEY NONCLUSTERED (PersonEmailUUID)
GO
ALTER TABLE [dbo].[PersonEmail] ADD CONSTRAINT CK_PersonEmail_EmailAddress_Unique UNIQUE (EmailAddress)
GO
ALTER TABLE [dbo].[PersonEmail] ADD CONSTRAINT FK_PersonEmailToPersonSuperType FOREIGN KEY (PersonSuperTypeUUID) REFERENCES dbo.PersonSuperType (PersonSuperTypeUUID)
GO
CREATE VIEW dbo.vwPersonEmail
AS
/* combine what is in common with employees and customers for this view */
select per.LastName, per.FirstName, [UniqueIdentifier] = emp.SSN, pemail.EmailAddress
from dbo.PersonSuperType per
join
dbo.Employee emp on per.PersonSuperTypeUUID = emp.EmployeeUUID
join
dbo.PersonEmail pemail on per.PersonSuperTypeUUID = pemail.PersonSuperTypeUUID
UNION ALL
select per.LastName, per.FirstName, [UniqueIdentifier] = cust.CustomerNumber, pemail.EmailAddress
from dbo.PersonSuperType per
join
dbo.Customer cust on per.PersonSuperTypeUUID = cust.CustomerUUID
join
dbo.PersonEmail pemail on per.PersonSuperTypeUUID = pemail.PersonSuperTypeUUID
GO
So now that I think about it, I might lean toward the "subclassing" way..since your two types of people might have alot of common attributes, and a few distinct ones.
If you want only to show information about 2 diferent tables in only one, you could use a View. Here you have an example check it out.
https://www.w3schools.com/sql/sql_view.asp => tutorial
https://www.ibm.com/support/knowledgecenter/en/ssw_i5_54/rzatc/rzatcviewmultsql.htm => example
I'd formalize the distinction between the incident and the details.
INCIDENT_HEADER
Customer ID <nullable, fk into the customer table>
Employee ID <nullable, fk into the employee table, which already exsits>
Summary
Date
Status (?)
INCIDENT_DETAIL
DETAIL_TYPE_ID <fk into a type table, it's up next...>
DESCRIPTION
DETAIL_TYPE
ID
DESCRIPTION
DETAIL_TYPE will end up with things like "Injury", "Hospitalized", and "First Aid". You can add more to that table later without touching the details table.
This design lets you add more kinds of details without altering the header table.

How to save auto generated primary key Id in foreign key column in same table

Following is the table structure:
CREATE TABLE [User] (
[Id] bigint identity(1,1) not null,
[FirstName] nvarchar(100) not null,
[LastName] nvarchar(100) not null,
[Title] nvarchar(5) null,
[UserName] nvarchar(100) not null,
[Password] nvarchar(100) not null,
[Inactive] bit null,
[Created] Datetime not null,
[Creator] bigint not null,
[Modified] DateTime null,
[Modifier] bigint null
CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED
(
[Id] Asc
)
);
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[FK_User_Creator]') AND parent_object_id = OBJECT_ID(N'[User]'))
ALTER TABLE [User] ADD CONSTRAINT [FK_User_Creator] FOREIGN KEY([Creator]) REFERENCES [User]([Id])
GO
INSERT INTO [User] (Creator) Values ([Id] ?)
This is a case when table is empty and first user is going to add in table. Otherwise I don't have issue.
How can I insert Id in creator column with insert statement at the same time?
One way could be using Sequence instead of identity column. The below script might serve the same purpose:
CREATE SEQUENCE dbo.useridsequence
AS int
START WITH 1
INCREMENT BY 1 ;
GO
CREATE TABLE [User] (
[Id] bigint DEFAULT (NEXT VALUE FOR dbo.useridsequence) ,
[FirstName] nvarchar(100) not null,
[LastName] nvarchar(100) not null,
[Title] nvarchar(5) null,
[UserName] nvarchar(100) not null,
[Password] nvarchar(100) not null,
[Inactive] bit null,
[Created] Datetime not null,
[Creator] bigint DEFAULT NEXT VALUE FOR dbo.useridsequence ,
[Modified] DateTime null,
[Modifier] bigint null
CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED
(
[Id] Asc
)
);
IF NOT EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[FK_User_Creator]') AND parent_object_id = OBJECT_ID(N'[User]'))
ALTER TABLE [User] ADD CONSTRAINT [FK_User_Creator] FOREIGN KEY([Creator]) REFERENCES [User]([Id])
GO
INSERT INTO [User]
(
-- Id -- this column value is auto-generated
FirstName,
LastName,
Title,
UserName,
[Password],
Inactive,
Created,
Creator,
Modified,
Modifier
)
VALUES
(
'Foo',
'Bar',
'Title',
'UserName ',
'Password',
0,
GETDATE(),
DEFAULT,
GETDATE(),
1
)
SELECT * FROM [User] AS u
Result :
The short answer is that you can't do this. And I suggest your model is logically flawed in the first place. Do you intend to define all actual database users (e.g., create user ... for login ...) as rows in [Users]? You need to think about that - but the typical answer is no. If the answer is yes, then you don't need the creator column at all because it is redundant. All you need is the created date - for which you probably should have defined a default.
But if you want to do this, you will need to do it in two steps (and you will need to make the column nullable). You insert a row (or rows) with values for the "real" data columns. Then update those same rows with the identity values generated for id. An example showing different ways to do this
use tempdb;
set nocount on;
CREATE TABLE dbo.[user] (
[user_id] smallint identity(3,10) not null primary key,
[name] nvarchar(20) not null,
[active] bit not null default (1),
[created] Datetime not null default (current_timestamp),
[creator] smallint null
);
ALTER TABLE dbo.[user] ADD CONSTRAINT [fk_user] FOREIGN KEY(creator) REFERENCES dbo.[user](user_id);
GO
-- add first row
insert dbo.[user] (name) values ('test');
update dbo.[user] set creator = SCOPE_IDENTITY() where user_id = SCOPE_IDENTITY()
-- add two more rows
declare #ids table (user_id smallint not null);
insert dbo.[user] (name) output inserted.user_id into #ids
values ('nerk'), ('pom');
update t1 set creator = t1.user_id
from #ids as newrows inner join dbo.[user] as t1 on newrows.user_id = t1.user_id;
select * from dbo.[user] order by user_id;
-- mess things up a bit
delete dbo.[user] where name = 'pom';
-- create an error, consume an identity value
insert dbo.[user](name) values (null);
-- add 2 morerows
delete #ids;
insert dbo.[user] (name) output inserted.user_id into #ids
values ('nerk'), ('pom');
update t1 set creator = t1.user_id
from #ids as newrows inner join dbo.[user] as t1 on newrows.user_id = t1.user_id;
select * from dbo.[user] order by user_id;
drop table dbo.[user];
And I changed the identity specification to demonstrate something few developers realize. It isn't always defined as (1,1) and the next inserted value can jump for many reasons - errors and caching/restarts for example. Lastly, I think you will regret naming a table with a reserved word since references to it will require the use of delimiters. Reduce the pain.

Checking for table columns before adding them in SQL Server

I need to script out a table modification at work. Rather than do a simple "if exists then drop and create", they want it to check for the new columns I'm adding, and only then alter the table with them if they don't exist.
Could someone help me with the script? Assume a simple table that looks like this currently:
CREATE TABLE myTable (
[ID] [int] NOT NULL,
[FirstName] [varchar] (20) NOT NULL,
[LastName] [varchar] (20) NOT NULL
)
.. I'd like to add an Address field, varchar(50) let's say, but only if it doesn't already exist in the schema.
IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'myTable' AND COLUMN_NAME = 'Address')
BEGIN
ALTER TABLE [dbo].[myTable] ADD
[Address] varchar(50) NOT NULL
END
Try this
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[myTable ]') AND type in (N'U'))
BEGIN
DROP TABLE [dbo].[myTable ]
END
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE myTable (
[ID] [int] NOT NULL,
[FirstName] [varchar] (20) NOT NULL,
[LastName] [varchar] (20) NOT NULL,
[Address] [varchar] (50) NOT NULL
)
OR
if not exists(select * from sys.columns
where Name = N'Address' and Object_ID = Object_ID(N'myTable'))
begin
alter table myTable
add Address varchar(50) NOT NULL
end
GO
Try this:
Here using it you can make check for multiple columns and get you table altered...
DECLARE #query VARCHAR(MAX)
IF EXISTS(SELECT * FROM sys.columns
WHERE Name = N'Address' AND OBJECT_ID = OBJECT_ID(N'<TableName>'))
BEGIN
SET
#query = 'ALTER TABLE <TableName> ADD Address varchar(50) GO'
END
--You can give multiple If conditions, example:
--IF EXISTS(SELECT * FROM sys.columns
--WHERE Name = N'<SomeOtherColumn>' AND OBJECT_ID = OBJECT_ID(N'<TableName>'))
--BEGIN
--SET
--#query = #query + 'ALTER TABLE <TableName> ADD <SomeOtherColumn> varchar(50) GO'
--END
EXEC sp_Executesql #query
IF 'col_name'
NOT IN
SELECT Name
FROM table_name.columns
ALTER TABLE table_name
ADD 'col_name' VARCHAR(65) NOT NULL
something like this?
EDIT: my friend believes this is much better
IF NOT EXISTS
(SELECT Name
FROM table_name.columns
Where Name='target_column_name')
ALTER TABLE table_name
ADD 'target_column_name' VARCHAR(65) NOTNULL