Multiple delete operation in a stored procedure - sql

I want to make some tables empty if a stored procedure runs but I couldn't do that. What I did is
create proc MakeEmpty ()
as
begin
delete from table1
delete from table2
delete from table3
end

Use truncate instead and remove the () like this:
create proc MakeEmpty
as
begin
truncate table table1
truncate table table2
truncate table table3
end

Two things:
1 - Those parentheses should only be used if you are declaring a parameter for the procedure. If there is no param they are unneeded.
2 - If you want to empty the tables, then you should use TRUNCATE - it's minimally logged and is basically a meta-operation instead of a row-by-row delete.
You will need to clarify about what's not working, but something like this should do the trick:
BEGIN
IF EXISTS (SELECT 1 from DatabaseName.sys.Tables WHERE Name = 'Table1')
TRUNCATE TABLE Databasename.dbo.Table1
...repeat for other tables...
END

Try to remove the ( and )
create proc MakeEmpty
as
begin
delete from table1;
delete from table2;
delete from table3;
end
but make sure table2 and table3 does not reference table1 and table3 does not reference table2

Related

POSTGRESQL Trigger that updates a column after having altered the table

I have a populated table that already has some specific columns. I'd like to alter the table structure by adding a new column which will represent a field that is the count of the rows of another table.
Is it possible to implement it through a trigger in order to do it automatically after the alter command?
I have come up with something like this but apparently doesn't update the column:
Function for the trigger:
CREATE FUNCTION update_column() RETURNS TRIGGER AS
$BODY$
DECLARE
num INTEGER;
BEGIN
SELECT COUNT(*) INTO num FROM mytable1, mytable2 WHERE mytable1.field = mytable2.field GROUP BY mytable1.field;
UPDATE mytable1 SET new_column = num;
END;
$BODY$
LANGUAGE PLPGSQL;
The trigger:
CREATE TRIGGER insert
AFTER UPDATE
ON mytable1
FOR EACH ROW
EXECUTE PROCEDURE update_column();
And the alter command:
ALTER TABLE mytable1 ADD new_column INT;
Is it possible to implement it through a trigger in order to do it automatically after the alter command?
Firstly, your trigger fires after each update on the table, not after the alter table. Second, there would not be much point for a trigger on such DDL event anyway.
If your table has data already, you might need to initialize the column after its creation, with something like:
update mytable1 t1
set new_column = (select count(*) from mytable2 t2 where t2.field = t1.field)
As for the logic you wanted in the trigger: you need to use new and old to refer to the row that was changed in the original table - and, typically, you would expect the update to affect either no rows (if field was not changed), or two rows (if it was):
update mytable1 t1
set new_column = (select count(*) from mytable2 t2 where t2.field = t1.field)
where t1.field in (new.field, old.field) and new.field <> old.field
That said, I would not recommend such set up. Maintaining such derived information is expensive and tedious (you have an update trigger, now you need an insert and a delete trigger too). Instead, you can compute the logic on the fly when needed, or create a view:
create view myview as
select t1.*,
(select count(*) from mytable2 t2 where t2.field = t1.field) as new_column
from mytable1 t1
You would not set this value automatically in a trigger based on when the column is added. You would use a trigger to maintain the value when there are changes on the second table.
The process is:
Add the column with a default value:
alter table mytable1 add new_column int default 0;
Initialize the value of the column to the current values:
update mytable1 t1
set new_column = (select count(*) from mytable2 t2 where t2.field = t1.field);
Add insert/update/delete triggers on mytable2. The key logic is:
update mytable1
set cnt = cnt + 1
where t1.field = new.field;
update mytable1
set cnt = cnt - 1
where t1.field = old.field;
If you don't have a foreign key relationship, you may also need to insert a row in mytable1 if the field value is not in the table. However, I strongly recommend an explicit foreign key constraint to prevent this from happening.
This increments/decrements the value when changes are made to the second table.

SQL Server Express Stored procedure: Select, delete, insert

I am using below query to insert record into a table.
DELETE FROM Table1;
INSERT into Table1 (F1,f2,f3...) SELECT * FROM TABLE2 WHERE......
The problem is, SELECT query took some time to fetch due to many conditions, while records are already deleted from Table1, live records may not be available for display in Client Side while waiting for SELECT query result and be inserted in table1.
I need to SELECT record first, then DELETE record from the table1, then insert the selected record to table1. Can anyone help me please?
you can use transaction like and also delete after insert but add somewhere criteria.
BEGIN TRY
BEGIN TRAN
While (i<0)(while loop and so on condition.)
BEGIN
DELETE FROM Table1 ;
INSERT into Table1 (F1,f2,f3...) SELECT * FROM TABLE2 WHERE......
END
COMMIT TRAN
END TRY
BEGIN CATCH
ROLLBACK TRAN
END CATCH
You can use ##rowcount
Declare #row_count int
SELECT #row_count=count(*) FROM TABLE2 WHERE......
INSERT into Table1 (F1,f2,f3...) SELECT * FROM TABLE2 WHERE......
DELETE TOP(#row_count) FROM Table1 ;
First get count how many records you want to insert the,
First data is inserted,
if data insertion success then data is delete
other wise data won't be delete
So, every time data is available in table to show client

SQL Trigger update another table

I am newbie to triggers... can anybody help me with a trigger?
I have Table:
Name | Number
I want to write a trigger when my table receives a query like
update MyTable
set Number = Number + 1
where Name = 'myname'
When this query is running, the trigger should update another table for example:
Update MyTable 2
set Column = 'something'
where Name = 'myname (above name)
Thank you very much !
You will need to write an UPDATE trigger on table 1, to update table 2 accordingly.
Be aware: triggers in SQL Server are not called once per row that gets updated - they're called once per statement, and the internal "pseudo" tables Inserted and Deleted will contain multiple rows, so you need to take that into account when writing your trigger.
In your case, I'd write something like:
-- UPDATE trigger on "dbo.Table1"
CREATE TRIGGER Table1Updated
ON dbo.table1 FOR UPDATE
AS
BEGIN
-- update table2, using the same rows as were updated in table1
UPDATE t2
SET t2.Column = 'something'
FROM dbo.Table2 t2
INNER JOIN Inserted i ON t2.ID = i.ID
END
GO
The trick is to use the Inserted pseudo table (which contains the new values after the UPDATE - it has the exact same structure as your table the trigger is written for - here dbo.Table1) in a set-based fashion - join that to your dbo.Table2 on some column that they have in common (an ID or something).
create a trigger on table 1 for update:
CREATE TRIGGER dbo.update_trigger
ON table1
AFTER UPDATE
AS
BEGIN
DECLARE #Name VARCHAR(50)
SELECT #Name=Name FROM INSERTED
Update MyTable 2
SET Column = 'something'
WHERE Name = #Name
END
GO
try this ;)

How use inserted\deleted table in stored procedure?

I creating triggers for several tables. The triggers have same logic. I will want to use a common stored procedure.
But I don't know how work with inserted and deleted table.
example:
SET #FiledId = (SELECT FiledId FROM inserted)
begin tran
update table with (serializable) set DateVersion = GETDATE()
where FiledId = #FiledId
if ##rowcount = 0
begin
insert table (FiledId) values (#FiledId)
end
commit tran
You can use a table valued parameter to store the inserted / deleted values from triggers, and pass it across to the proc. e.g., if all you need in your proc is the UNIQUE FileID's:
CREATE TYPE FileIds AS TABLE
(
FileId INT
);
-- Create the proc to use the type as a TVP
CREATE PROC commonProc(#FileIds AS FileIds READONLY)
AS
BEGIN
UPDATE at
SET at.DateVersion = CURRENT_TIMESTAMP
FROM ATable at
JOIN #FileIds fi
ON at.FileID = fi.FileID;
END
And then pass the inserted / deleted ids from the trigger, e.g.:
CREATE TRIGGER MyTrigger ON SomeTable FOR INSERT
AS
BEGIN
DECLARE #FileIds FileIDs;
INSERT INTO #FileIds(FileID)
SELECT DISTINCT FileID FROM INSERTED;
EXEC commonProc #FileIds;
END;
You can
select * into #Inserted from inserted
select * into #Deleted from deleted
and then
use these two temp tables in your stored proc
The tables inserted and deleted are only available inside the trigger. You can only use them in run-time. They will then contain the affected rows.
Also, your code might not work as expected if there is not exactly one row inserted.

How to delete master detail records using one sql?

Using Delphi 7 and interbase 7
Is it possible to delete a master detail record and all of its nested detail records in one SQL statement?
Example:
Table1
ID - Integer
TITLE - Varchar(80)
Table2
ID - Integer
Table1_ID - Integer
TITLE - Varchar(80)
Table3
ID - Integer
Table2_ID - Integer
TITLE - Varchar(80)
I would like to delete ID 10 from Table1, and all of its matching records (Table1_ID) in table 2, and all its matching records (Table2_ID) in table 3
If i can't do this in one sql, how do i do it in multiple sqls (correct sequence to call statements)?
Yo can do it witn some SQL's deleteing in order, records on Table3, table2 and table1. All in one transaction to do it like "unique operation".
One alternative is use Triggers for delete record related on table2 when you delete one record on table1, and equivalent in table2 to delete related records on table3.
Another (if DB let you) is use ON CASCADE DELETE (or similar) to delete related records on a tabla2 and table3, when you delete a record un table1 (see help or documentation on your SGBD/Database).
Excuse-me for mistakes with English. It's not my natural language.
Regards.
You can use foreign keys to cascade deletes to child records when the parent record is deleted.
The following command should create the foreign key to delete records in Table2 (Table1_ID) when the record in Table1 (ID) is deleted.
ALTER TABLE TABLE2 ADD CONSTRAINT FK_TABLE2_TABLE1
FOREIGN KEY (Table1_ID) REFERENCES TABLE1 (ID)
ON DELETE CASCADE;
This way the database engine takes care of deletes in child tables so all you need to do is
delete from TABLE1 where ID = :ID_VALUE
Regards,
DELETE FROM Table3 WHERE Table2_ID IN (SELECT ID FROM Table_2 WHERE Table1_ID=xxxx)
DELETE FROM Table2 WHERE Table1_ID=xxxx
DELETE FROM Table1 WHERE ID=xxxx
You cannot do that in a single statement but instead you can use transactions in Delphi make sure that either all or none of the statements are executed.
If you are using BDE, then drop TDatabase component and set the default properties and write the following code.
try
Database1.StartTransaction;
//Execute first query
//Execute second query
//Execute third query
Database1.Commit;
except on E: Exception do
Database1.Rollback;
end;
If you are using ADO then use ADOConnection1.BeginTrans; ADOConnection1.CommitTrans; ADOConnection1.RollbackTrans; statements
If you create foreign key references with cascade option, deleting the parent record will also delete all details (unless other restrictions prevent this).
SQL:
ALTER TABLE Table2 ADD CONSTRAINT Table2_Table1_ID
FOREIGN KEY(Table1_ID) REFERENCES Table1(ID) ON DELETE CASCADE
This solution does not require the cooperation of the client applications, the server will keep the data model consistent.
In addition to the answers already given with multiple SQL statements, foreign key relationships and triggers. In InterBase you can also write a stored procedure to delete the master and detail records. Then you will only need one SQL statement in your program.
Below two kind of stored procedures you could use in this situation.
The first one is almost the same as HeartWave answer, but then in a stored procedure.
CREATE PROCEDURE DELETEMASTERDETAIL_WITHOUTINFO(
pMasterID INTEGER)
RETURNS (
rResult INTEGER)
AS
declare variable vTable2ID integer;
begin
/* don't return information about deleted records */
rResult = 0;
for select id
from table2
where table1_id = :pMasterID
into :vTable2ID do
begin
delete from table3
where table2_id = :vTable2ID;
end
delete from table2
where table1_id = :pMasterID;
delete from table1
where id = :pMasterID;
rResult = rResult + 1;
suspend;
end
The SQL statement to call this stored procedure is:
select rresult
from deletemasterdetail_withoutinfo(:pMasterID)
The second one will return information about the amount of deleted records per table. I don't know if you need it, but perhaps it is helpfull for someone else. If the ID field in Table1 is the primary key the first for select statement is a bit overkill.
CREATE PROCEDURE DELETEMASTERDETAIL_WITHINFO(
pMasterID INTEGER)
RETURNS (
rTable1Deleted INTEGER,
rTable2Deleted INTEGER,
rTable3Deleted INTEGER)
AS
declare variable vTable1ID integer;
declare variable vTable2ID integer;
declare variable vTable3ID integer;
begin
/* return information about deleted records */
rTable1Deleted = 0;
rTable2Deleted = 0;
rTable3Deleted = 0;
for select id
from table1
where id = :pMasterID
into :vTable1ID do
begin
for select id
from table2
where table1_id = :vTable1ID
into :vTable2ID do
begin
for select id
from table3
where table2_id = :vTable2ID
into :vTable3ID do
begin
rTable3Deleted = rTable3Deleted + 1;
delete from table3
where id = :vTable3ID;
end
rTable2Deleted = rTable2Deleted + 1;
delete from table2
where id = :vTable2ID;
end
rTable1Deleted = rTable1Deleted + 1;
delete from table1
where id = :vTable1ID;
end
suspend;
end
The SQL statement to call this stored procedure is:
select rtable1deleted, rtable2deleted, rtable3deleted
from deletemasterdetail_withinfo(:pMasterID)
BTW. I almost always use at least one return parameter in SP's. This will allow to use a Query component to call the stored procedure.
If there are no result parameters a Stored Procedure component must be used to execute the SP.