Cascading delete rows from multiple tables in SQL - sql

I've got two tables with the following structure:
Person
Id
Name
Class
Id
PersonId
Sequence
and some data:
Person
1 name1
2 name2
3 name3
Class
1 1 3
2 1 1
3 1 2
4 2 1
Class table can contain multiple rows related to one row from Person. PersonId from Class table is foreign key to Id in Person table. I'd like to delete data related to Person with Id 1, so remove the 3 rows from Class, and 1 row from Person using one query.
How can I do that in SQL?

Try This:
CREATE TABLE [dbo].[Class](
[Id] [int] IDENTITY(1,1) NOT NULL,
[PersonId] [int] NULL,
[Sequence] [int] NULL,
CONSTRAINT [PK_Class] 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
/****** Object: Table [dbo].[Person] Script Date: 26-05-2014 07:54:26 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Person](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Person] [nchar](10) NULL,
CONSTRAINT [PK_Person] 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].[Class] WITH CHECK ADD CONSTRAINT [FK_Class_Person] FOREIGN KEY([PersonId])
REFERENCES [dbo].[Person] ([Id])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[Class] CHECK CONSTRAINT [FK_Class_Person]
GO

Related

Trigger to update table after insert to insert or update into another table

I am having a little trouble with my after insert trigger it does not update/insert into the table and I am not sure why.
I have the tables employee, position, certification, employeecertification, positioncertification.
What I need to do is after a Position is assigned a Certification then all employees that are defined in that position (Employee:PositionId = Ins.PositionId] need to get the certification added (if it does not already exist in their record) , I might need to update them where they do exist (but for the moment do not believe that will be a requirement).
I have been getting a couple different results (neither is correct)
1: EmployeeId can not insert null into EmployeeId
2: On some other test data - nothing is inserted.
I have the following trigger with the sql for creation of tables that follows:
The Trigger
CREATE TRIGGER [dbo].[trig_InsNew_PositionCertification]
ON [dbo].[PositionCertification]
AFTER INSERT
AS
Insert into EmployeeCertification
(CertificationId, EmployeeId)
Select Ins.CertificationId, Emp.EmployeeId
From inserted Ins
Left Join dbo.Employee Emp On Emp.PositionId = Ins.PositionId
Left Join dbo.Certification Trw On Trw.CertificationId = Ins.CertificationId
WHERE NOT EXISTS
(SELECT EmployeeId, CertificationId
FROM
EmployeeCertification
WHERE EmployeeId = Emp.EmployeeId AND CertificationId = Ins.CertificationId);
GO
ALTER TABLE [dbo].[PositionCertification] ENABLE TRIGGER [trig_InsNew_PositionCertification]
GO
CREATE TABLES:
CREATE TABLE [dbo].[Position](
[PositionId] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_Position] PRIMARY KEY CLUSTERED
(
[PositionId] 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
CREATE TABLE [dbo].[Employee](
[EmployeeId] [int] IDENTITY(1,1) NOT NULL,
[EmployeeName] [nvarchar](512) NOT NULL,
[PositionId] [int] NOT NULL,
CONSTRAINT [PK_Employee] PRIMARY KEY CLUSTERED
(
[EmployeeId] 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].[Employee] WITH CHECK ADD CONSTRAINT [FK_Employee_Position] FOREIGN KEY([PositionId])
REFERENCES [dbo].[Position] ([PositionId])
GO
ALTER TABLE [dbo].[Position] CHECK CONSTRAINT [FK_Employee_Position]
GO
CREATE TABLE [dbo].[Certification](
[CertificationId] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](512) NOT NULL,
CONSTRAINT [PK_Certification] PRIMARY KEY CLUSTERED
(
[CertificationId] 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
CREATE TABLE [dbo].[EmployeeCertification](
[EmployeeCertificationId] [int] IDENTITY(1,1) NOT NULL,
[EmployeeId] [int] NOT NULL,
[CertificationId] [int] NOT NULL,
CONSTRAINT [PK_EmployeeCertification] PRIMARY KEY CLUSTERED
(
[EmployeeId] ASC,
[CertificationId] 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
ALTER TABLE [dbo].[EmployeeCertification] WITH CHECK ADD CONSTRAINT [FK_EmpCertification_Certification] FOREIGN KEY([CertificationId])
REFERENCES [dbo].[Certification] ([CertificationId])
GO
ALTER TABLE [dbo].[EmployeeCertification] CHECK CONSTRAINT [FK_EmpCertification_Certification]
GO
ALTER TABLE [dbo].[EmployeeCertification] WITH CHECK ADD CONSTRAINT [FK_EmpCertification_Employee] FOREIGN KEY([EmployeeId])
REFERENCES [dbo].[Employee] ([EmployeeId])
GO
ALTER TABLE [dbo].[EmployeeCertification] CHECK CONSTRAINT [FK_EmpCertification_Employee]
GO
CREATE TABLE [dbo].[PositionCertification](
[PositionCertificationId] [int] IDENTITY(1,1) NOT NULL,
[PositionId] [int] NOT NULL,
[CertificationId] [int] NOT NULL,
CONSTRAINT [PK_PositionCertification] PRIMARY KEY CLUSTERED
(
[PositionId] ASC,
[CertificationId] 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

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)
);

Trigger causing primary key violation

We have a trigger that we are trying to update so that when a record is updated, the trigger will update a second table. When we activate the change, we get an error
Violation of PRIMARY KEY contstraint 'KPRIMARY_SO_SalesOrderHeader". Cannot insert duplicate key in object 'dbo.SO_SalesOrderHeader". The duplicate key is XXXXXX.
I'm really confused by this because I don't see in the trigger where we are trying to insert a key.
ALTER Trigger [dbo].[SO_SALESORDERHEADER_onOrderChange]
ON [dbo].[SO_SalesOrderHeader]
FOR INSERT, UPDATE
AS
SET NOCOUNT ON;
--+
INSERT INTO dbo.OrderUpdateQueue (SourceId, OrderNumber, Action)
SELECT DISTINCT
N'SO', Inserted.SALESORDERNO, N'U'
FROM
Inserted
LEFT JOIN
dbo.OrderUpdateQueue ON (Inserted.SALESORDERNO = OrderUpdateQueue.OrderNumber)
AND (OrderUpdateQueue.SourceID = N'SO')
AND (OrderUpdateQueue.Action = N'U')
WHERE
(OrderUpdateQueue.[Key] IS NULL)
AND (Inserted.SALESORDERNO IS NOT NULL);
--+ New Trigger Stuff
UPDATE MO
SET MO.[ShipDate] = I.ShipExpireDate
FROM [BACKEND_db].[dbo].[Order] MO
INNER JOIN Inserted I ON I.SalesOrderNo = MO.OrderId
WHERE MO.ShipDate <> I.ShipExpireDate;
CREATE TABLE [dbo].[SO_SalesOrderHeader](
[SalesOrderNo] [varchar](7) NOT NULL
CONSTRAINT [KPRIMARY_SO_SalesOrderHeader] PRIMARY KEY CLUSTERED
(
[SalesOrderNo] 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
CREATE TABLE [dbo].[OrderUpdateQueue](
[Key] [int] IDENTITY(1,1) NOT NULL,
[SourceId] [nvarchar](50) NOT NULL,
[OrderNumber] [nvarchar](50) NOT NULL,
[Action] [nchar](1) NOT NULL,
CONSTRAINT [PK_OrderUpdateQueue] PRIMARY KEY CLUSTERED
(
[Key] 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
USE [BACKEND_db]
CREATE TABLE [dbo].[Order](
[Key] [int] IDENTITY(1,1) NOT NULL,
[OrderId] [nvarchar](10) NULL,
[ShipDate] [datetime] NULL
CONSTRAINT [PK_MasOrder] PRIMARY KEY CLUSTERED
(
[Key] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
) ON [PRIMARY]
GO
How you do not post the schema of OrderUpdateQueue table, I believe the pk is the OrderNumber field. You can try to change your trigger to:
ALTER Trigger [dbo].[SO_SALESORDERHEADER_onOrderChange]
ON [dbo].[SO_SalesOrderHeader]
FOR INSERT, UPDATE
AS
SET NOCOUNT ON;
--+
INSERT INTO dbo.OrderUpdateQueue (SourceId, OrderNumber, Action)
SELECT DISTINCT
N'SO', Inserted.SALESORDERNO, N'U'
FROM
Inserted
WHERE not exists (SELECT 1 FROM dbo.OrderUpdateQueue where Inserted.SALESORDERNO = OrderUpdateQueue.OrderNumber)
UPDATE MO
SET MO.[ShipDate] = I.ShipExpireDate
FROM [BACKEND_db].[dbo].[Order] MO
INNER JOIN Inserted I ON I.SalesOrderNo = MO.OrderId
WHERE MO.ShipDate <> I.ShipExpireDate;

How I can change the incerement value of cloumn

I have a table and have a lot of records and i can't drop and recreate it
I need to change the increment value of the Id column to 2 the old value is 1
this is an example of the table I need to change the identity increment of
CREATE TABLE [dbo].[RELATED](
[Id] [int] IDENTITY(1,1) NOT NULL,
[RELATEDDESC] [nvarchar](50) NOT NULL,
[USER_ID] [int] NULL,
[ALTER_DATE] [datetime2](7) NULL,
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
To specify that the "ID" column should start at value 1 and increment by 2, change it to IDENTITY(1,2).
EDIT*
ALTER TABLE [dbo].[RELATED]
ALTER COLUMN [Id] [int] IDENTITY(1,2) NOT NULL

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.