Delete rows from a table in Sql Server - sql-server

How can I delete a row from a table if it has a foreign key?
I have this stored procedure but when I execute it it gives me this error :The DELETE statement conflicted with the REFERENCE constraint "FK__Pilot_Fli__pilot__4E88ABD4". The conflict occurred in database "Airline Reservation", table "dbo.Pilot_Flight", column 'pilot_id'.
create procedure DeletePilot
(#id INTEGER,#result varchar(70) output)
as
If NOT Exists ( Select * From Pilot
Where pilot_id=#id)
Begin
Set #result='There is no record with that ID'
RETURN
END
Delete from Pilot
where pilot_id=#id
set #result='Record was deleted'
RETURN
GO
select * from Pilot
Declare #res varchar(70)
EXEC DeletePilot 7,#res OUTPUT
print(#res)
Can anyone help me please!

You'd have to either run a statement like this (if it's nullable):
UPDATE Pilot_Flight
SET pilot_id = NULL
WHERE pilot_id = #id
or do this:
DELETE Pilot_Flight WHERE pilot_id = #id
Either way you have to do one or the other before the DELETE from Pilot.

There are records in dbo.Pilot_Flight that reference records in dbo.Pilot.
You could delete the records in Pilot_Flight before deleting the records in Pilot, enable (cascade delete which would delete records in Pilot_Flight when Pilot records are deleted (bad), or disable the foreign key reference... (worse).

Related

Re-Inserting deleted rows into the same table SQL Server 2005

After searching many pages I still can't find the answer about re-inserting deleted rows in the same table - not another table.
I have a table named timetable with the primary key made up from 3 columns Schoolcode, Year, Term.
I need for some reason need to insert deleted rows into the same table.
I get the error
Violation of PRIMARY KEY constraint
with the following trigger
ALTER TRIGGER [dbo].[AFTER_delete_]
ON [dbo].timetable
AFTER delete
AS
BEGIN
IF EXISTS (SELECT * FROM deleted)
BEGIN
INSERT INTO timetable
SELECT *
FROM deleted A
WHERE NOT EXISTS (SELECT 1 FROM timetable B
WHERE B.Schoolcode = A.Schoolcode
AND B.Year = A.Year
AND B.Term = A.Term);
END
END
thanks any way.I test the code below and that did work.
ALTER TRIGGER [dbo].[Instead_OfDelSert_Status]
ON [dbo].[Status]
INSTEAD OF delete,insert
AS
BEGIN
PRINT 'You must disable or delete Trigger Instead_OfDelSert_Status to insert or
delete rows!'
END

get last inserted primary key of type varchar in sql server

i have two table userGold and AspNetUserRoles(UserId,RoleId) .
primary key type of UserGold is nvarchar(450)
same for AspNetUserRole.
my problem is that i want to get the last inserted primary key in UsereGold and insert it in AspNetUserRoles table using a trigger.
SCOPE_IDENTITY didn't work cause my primary key type is nvarchar.
i don't know what to do.
i saw solution like output inserted but it didn't work
create trigger addrole
on UserGold
after Insert
as
Begin
declare
#userid nvarchar(450)
set #userid=CAST(SCOPE_IDENTITY() AS nvarchar(450))
insert into AspNetUserRoles(UserId,RoleId)
values(#userid,'2c258e8d-c648-4b38-9b01-989d4dd525fe')
end
You should not write triggers - or anything else in a database - that only expect a single row to change. Databases work with sets of information, not single "records". Imagine what happens if someone create 5 rows in UserGold in a single insert statement. You can't put 5 userid values into a single #userId variable.
What you want is something like
-- assuming your tables are in the dbo schema! Make sure you include the schema name
create trigger AddDefaultRole on dbo.UserGold after insert as begin
set nocount on;
insert dbo.AspNetUserRoles (UserId, RoleId)
select UserId, '2c258e8d-c648-4b38-9b01-989d4dd525fe'
from inserted;
end
For more information, see Inserted and Deleted tables for triggers

SQL Server - Alter Table FOREIGN KEY Conflict when using EXEC sp_msforeachtable

I am attempting to migrate some data from one database to another using Microsoft SQL Server. Both databases have a "Properties/Locations" type of table that is referenced by a foreign key.
Unfortunately, even though the entities referenced in the two tables are the same, the primary keys are not. As such, in order to migrate the data, I am trying to temporarily disable the foreign key constraint, insert and update the data appropriately, and then re-enable the constraint.
However, I am receiving the following message:
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK__TwelveCri__Store__114A936A". The conflict occurred in database "API", table "dbo.Properties", column 'ID'.
While, I understand the general reason why the error is being thrown (it is not finding a match between the column StoreID in the Reports table and the ID columns in Properties), I do not understand why it is doing so in this specific case.
BEGIN TRAN
USE API;
EXEC sp_msforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT ALL";
SET IDENTITY_INSERT Midamcorp.TwelveCriticalsReports ON;
INSERT INTO Midamcorp.TwelveCriticalsReports (ID, StoreID, InspectorName, ReportTime, ReportDate, PointsPoss, PointsReceived)
SELECT
id, storeID, inspectorName, reportTIme, reportDate, pointsPoss, pointsReceived
FROM
midAmCorp.dbo.criticalReports;
SET IDENTITY_INSERT Midamcorp.TwelveCriticalsReports OFF;
UPDATE API.Midamcorp.TwelveCriticalsReports
SET StoreID = 1
WHERE StoreID = 4;
!--- MORE UPDATE STATEMENTS HERE ---!
USE API
SET IDENTITY_INSERT Midamcorp.SecretShopperReportSummary ON;
INSERT INTO Midamcorp.SecretShopperReportSummary(ID, StoreID, PointsPoss, PointsReceived, DriveTime, CompletedBy, DateOfVisit)
SELECT
id, storeID, pointsPoss, pointsReceived, driveTime, completedBy, dateOfVisit
FROM
midamCorp.dbo.secretShopperReportSummary;
SET IDENTITY_INSERT Midamcorp.SecretShopperReportSummary OFF;
!--- MORE UPDATE STATEMENTS HERE ---!
USE API
SET IDENTITY_INSERT Midamcorp.SecretShopperReportDetails ON;
INSERT INTO Midamcorp.SecretShopperReportDetails(ID, ReportID, QuestionID)
SELECT
id, reportID, questionID
FROM
midAmCorp.dbo.secretShopperReportDetails;
SET IDENTITY_INSERT Midamcorp.SecretShopperReportDetails OFF;
SELECT *
FROM Midamcorp.TwelveCriticalsReports
WHERE StoreID NOT IN (SELECT StoreID FROM dbo.Properties);
EXEC sp_msforeachtable "ALTER TABLE ? WITH CHECK CHECK CONSTRAINT ALL";
COMMIT TRAN;
The SELECT statement at near the end returns no results, which is what I would expect if the relationships were properly updated. However, I am still receiving the error message noted above, presumably from the EXEC sp_msforeachtable "ALTER TABLE ? WITH CHECK CHECK CONSTRAINT ALL"; statement.
Any advice would be appreciated.

TRANSACTION rollback not working as expected

I'm doing some DB schema re-structuring.
I have a script that looks broadly like this:
BEGIN TRAN LabelledTransaction
--Remove FKs
ALTER TABLE myOtherTable1 DROP CONSTRAINT <constraintStuff>
ALTER TABLE myOtherTable2 DROP CONSTRAINT <constraintStuff>
--Remove PK
ALTER TABLE myTable DROP CONSTRAINT PK_for_myTable
--Add replacement id column with new type and IDENTITY
ALTER TABLE myTable ADD id_new int Identity(1, 1) NOT NULL
GO
ALTER TABLE myTable ADD CONSTRAINT PK_for_myTable PRIMARY KEY CLUSTERED (id_new)
GO
SELECT * FROM myTable
--Change referencing table types
ALTER TABLE myOtherTable1 ALTER COLUMN col_id int NULL
ALTER TABLE myOtherTable2 ALTER COLUMN col_id int NOT NULL
--Change referencing table values
UPDATE myOtherTable1 SET consignment_id = Target.id_new FROM myOtherTable1 AS Source JOIN <on key table>
UPDATE myOtherTable2 SET consignment_id = Target.id_new FROM myOtherTable2 AS Source JOIN <on key table>
--Replace old column with new column
ALTER TABLE myTable DROP COLUMN col_id
GO
EXEC sp_rename 'myTable.id_new', 'col_id', 'Column'
GO
--Reinstate any OTHER PKs disabled
ALTER TABLE myTable ADD CONSTRAINT <PK defn>
--Reinstate FKs
ALTER TABLE myOtherTable1 WITH CHECK ADD CONSTRAINT <constraintStuff>
ALTER TABLE myOtherTable2 WITH CHECK ADD CONSTRAINT <constraintStuff>
SELECT * FROM myTable
-- Reload out-of-date views
EXEC sp_refreshview 'someView'
-- Remove obsolete sequence
DROP SEQUENCE mySeq
ROLLBACK TRAN LabelledTransaction
Obviously that's all somewhat redacted, but the fine detail isn't the important thing in here.
Naturally, it's quite hard to locate all the things that need to be turned off/editted before the core change (even with some meta-queries to help me), so I don't always get the script correct first time.
But I put in the ROLLBACK in order to ensure that the failed attempts left the DB unchanged.
But what I actually see is that the ROLLBACK doesn't occur if there were errors in the TRAN. I think I get errors about "no matching TRAN for the rollback"?
My first instinct was that it was about the GO statements, but https://stackoverflow.com/a/11121382/1662268 suggests that labeling the TRAN should have fixed that?
What's happening? Why don't the changes get rolled back properly if there are errors.
How can I write and test these scripts in such a way that I don't have to manually revert any partial changes if the script isn't perfect first time?
EDIT:
Additional comments based on the first answer.
If the linked answer is not applicable to this query, could you expand on why that is, and why it's different from the example that they had given in their answer?
I can't (or rather, I believe that I can't) remove the GOs, because the script above requires the GOs in order to compile. If I remove the GOs then later statements that depend on the newly added/renamed columns don't compile. and the query can't run.
Is there any way to work around this, to remove the GOs?
If you have any error which automatically causes the transaction to be rolled back then the transaction will roll back as part of the current batch.
Then, control will return back to the client tool which will then send the next batch to the server and this next batch (and subsequent ones) will not be wrapped in any transaction.
Finally, when the final batch is executed that tries to run the rollback then you'll get the error message you received.
So, you need to protect each batch from running when its not protected by a transaction.
One way to do it would be to insert our old fried GOTO:
GO
IF ##TRANCOUNT=0 GOTO NBATCH
...Rest of Code
NBATCH:
GO
or SET FMTONLY:
GO
IF ##TRANCOUNT=0 BEGIN
SET FMTONLY ON
END
...Rest of Code
GO
Of course, this won't address all issues - some statements need to be the first or only statement in a batch. To resolve these, we have to combine one of the above techniques with an EXEC of some form:
GO
IF ##TRANCOUNT=0 BEGIN
SET FMTONLY ON
END
EXEC sp_executesql N'/*Code that needs to be in its own batch*/'
GO
(You'll also have to employ this technique if a batch of code relies on work a previous batch has performed which introduces new database objects (tables, columns, etc), since if that previous batch never executed, the new object will not exist)
I've also just discovered the existence of the -b option for the sqlcmd tool. The following script generates two errors when run through SSMS:
begin transaction
go
set xact_abort on
go
create table T(ID int not null,constraint CK_ID check (ID=4))
go
insert into T(ID) values (3)
go
rollback
Errors:
Msg 547, Level 16, State 0, Line 7
The INSERT statement conflicted with the CHECK constraint "CK_ID". The conflict occurred in database "TestDB", table "dbo.T", column 'ID'.
Msg 3903, Level 16, State 1, Line 9
The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION.
However, the same script saved as Abortable.sql and run with the following commandline:
sqlcmd -b -E -i Abortable.sql -S .\SQL2014 -d TestDB
Generates the single error:
Msg 547, Level 16, State 1, Server .\SQL2014, Line 1
The INSERT statement conflicted with the CHECK constraint "CK_ID". The conflict
occurred in database "TestDB", table "dbo.T", column 'ID'.
So, it looks like running your scripts from the commandline and using the -b option may be another approach to take. I've just scoured the SSMS options/properties to see if I can find something equivalent to -b but I've not found it.
Remove the 'GO', that finishes the transaction
Only ROLLBACK if completes - just use TRY/CATCH:
BEGIN TRANSACTION;
BEGIN TRY
--Remove FKs
ALTER TABLE myOtherTable1 DROP CONSTRAINT <constraintStuff>
ALTER TABLE myOtherTable2 DROP CONSTRAINT <constraintStuff>
--Remove PK
ALTER TABLE myTable DROP CONSTRAINT PK_for_myTable
--Add replacement id column with new type and IDENTITY
ALTER TABLE myTable ADD id_new int Identity(1, 1) NOT NULL
ALTER TABLE myTable ADD CONSTRAINT PK_for_myTable PRIMARY KEY CLUSTERED (id_new)
SELECT * FROM myTable
--Change referencing table types
ALTER TABLE myOtherTable1 ALTER COLUMN col_id int NULL
ALTER TABLE myOtherTable2 ALTER COLUMN col_id int NOT NULL
--Change referencing table values
UPDATE myOtherTable1 SET consignment_id = Target.id_new FROM myOtherTable1 AS Source JOIN <on key table>
UPDATE myOtherTable2 SET consignment_id = Target.id_new FROM myOtherTable2 AS Source JOIN <on key table>
--Replace old column with new column
ALTER TABLE myTable DROP COLUMN col_id
EXEC sp_rename 'myTable.id_new', 'col_id', 'Column'
--Reinstate any OTHER PKs disabled
ALTER TABLE myTable ADD CONSTRAINT <PK defn>
--Reinstate FKs
ALTER TABLE myOtherTable1 WITH CHECK ADD CONSTRAINT <constraintStuff>
ALTER TABLE myOtherTable2 WITH CHECK ADD CONSTRAINT <constraintStuff>
SELECT * FROM myTable
-- Reload out-of-date views
EXEC sp_refreshview 'someView'
-- Remove obsolete sequence
DROP SEQUENCE mySeq
ROLLBACK TRANSACTION
END TRY
BEGIN CATCH
print 'Error caught'
select ERROR_NUMBER() AS ErrorNumber, ERROR_MESSAGE() AS ErrorMessage;
END CATCH;

DROP TABLE fails for temp table

I have a client application that creates a temp table, the performs a bulk insert into the temp table, then executes some SQL using the table before deleting it.
Pseudo-code:
open connection
begin transaction
CREATE TABLE #Temp ([Id] int NOT NULL)
bulk insert 500 rows into #Temp
UPDATE [OtherTable] SET [Status]=0 WHERE [Id] IN (SELECT [Id] FROM #Temp) AND [Group]=1
DELETE FROM #Temp WHERE [Id] IN (SELECT [Id] FROM [OtherTable] WHERE [Group]=1)
INSERT INTO [OtherTable] ([Group], [Id]) SELECT 1 as [Group], [DocIden] FROM #Temp
DROP TABLE #Temp
COMMIT TRANSACTION
CLOSE CONNECTION
This is failing with an error on the DROP statement:
Cannot drop the table '#Temp', because it does not exist or you do not have permission.
I can't imagine how this failure could occur without something else going on first, but I don't see any other failures occurring before this.
Is there anything that I'm missing that could be causing this to happen?
possibly something is happening in the session in between?
Try checking for the existence of the table before it's dropped:
IF object_id('tempdb..#Temp') is not null
BEGIN
DROP TABLE #Temp
END
I've tested this on SQL Server 2005, and you can drop a temporary table in the transaction that created it:
begin transaction
create table #temp (id int)
drop table #temp
commit transaction
Which version of SQL Server are you using?
You might reconsider why you are dropping the temp table at all. A local temporary table is automatically deleted when the connection ends. There's usually no need to drop it explicitly.
A global temporary table starts with a double hash (f.e. ##MyTable.) But even a global temp table is automatically deleted when no connection refers to it.
I think you aren't creating the table at all, because the statement
CREATE TABLE #Temp ([Id] AS int)
is incorrect. Please, write it as
CREATE TABLE #Temp ([Id] int)
and see if it works.
BEGIN TRAN
IF object_id('DATABASE_NAME..#TABLE_NAME') is not null
BEGIN
DROP TABLE #TABLE_NAME
END
COMMIT TRAN
Note:Please enter your table name where TABLE_NAME and database name where it says DATABASE_NAME

Resources