Pages

Thursday, July 21, 2016

How to use "OUTPUT" with Update and Delete (Cascade delete in same table)

Hi fellas,

Today I'm going to discuss how to do a cascade delete on a record set not stored in two tables (parent table and child table) but in a single table. 

Let's imaging we have two tables Set_Folder and Set_Article. The database concept is that the folders in the system will be stored under Set_Folder table and the articles in those folders stored under Set_Article table. Don't be fussy, I'm applying cascade delete for one single table, not parent and child table. When it comes to between parent and child table, it's pretty much simple and straight forward but when it comes to a single table the code will be bit different and complex. Not much complex but not straight forward.

Set_Folder table :-

FolderId   FolderName  ParentId  IsDeleted  IsParentDeleted
      1               folder 1             0                0                  0
      2               folder 2             1                0                  0
      3               folder 3             1                0                  0
      4               folder 4             2                0                  0
      5               folder 5             4                0                  0
      6               folder 6             0                0                  0
      7               folder 7             6                0                  0
      8               folder 8             0                0                  0

According to the table structure root folders are the folders which has parentid as 0. All the other folders are sub folders. Therefor folder 1, folder 6 and folder 8 are root folders and all the others are sub folders.
The requirement is to delete an specific root folder with it's sub folders. Let's say user needs to delete folder 1. folder 2, folder 3, folder 4 and folder 5 should be deleted along with it since those are sub folders in folder 1. 

To do this we have to use WITH key word along with OUTPUT key word.
This is how we gonna do it.

WITH    q AS
(
    SELECT  Folderid
    FROM    Set_Folder
    WHERE   Folderid = 1
    UNION ALL
    SELECT  tc.Folderid
    FROM    q
    JOIN    Set_Folder tc
    ON      tc.parentID = q.Folderid
)
UPDATE Set_Folder
SET IsDeleted = '1'
OUTPUT  DELETED.*
WHERE   EXISTS
(
    SELECT  Folderid
    INTERSECT
    SELECT  Folderid
    FROM    q
)

In here we are doing a self join. I think you all are familiar with DELETED and INSERTED table. Those are like virtual tables and we will discuss about them in a separate section. 

After running this query the table data set will be like,

 FolderId   FolderName  ParentId  IsDeleted  IsParentDeleted
      1               folder 1             0                1                            1
      2               folder 2             1                1                            1
      3               folder 3             1                1                            1
      4               folder 4             2                1                            1
      5               folder 5             4                1                            1
      6               folder 6             0                0                            0
      7               folder 7             6                0                            0
      8               folder 8             0                0                            0

Let's say these folders have articles in them. The Set_Article table is like this.

ArticleId    FolderId    ArticleName    IsDeleted
      1               1                A1                     0
      2               1                A2                     0
      3               2                A3                     0
      4               3                A4                     0
      5               4                A5                     0
      6               5                A6                     0
      7               6                A7                     0
      8               7                A8                     0

Requirement is to delete the root folder 1 and all it's sub folders and all the articles on those tables. Now we know how to delete the folders. Next step is to get the folder ids we deleted and delete all the articles in those folders. We can achieve this with below query.

WITH    q AS
(
    SELECT  Folderid
    FROM    Set_Folder
    WHERE   Folderid = @FolderId
    UNION ALL
    SELECT  tc.Folderid
    FROM    q
    JOIN    Set_Folder tc
    ON      tc.parentID = q.Folderid
)

UPDATE Set_Folder

SET IsParentDeleted = 1, IsDeleted = 1
OUTPUT  DELETED.Folderid,
inserted.Folderid   
    INTO @table
WHERE   EXISTS
(
    SELECT  Folderid
    INTERSECT
    SELECT  Folderid
    FROM    q
)
AND IsDeleted = 0

What we are doing here is deleting the folders and insert those folder ids into a temporary table. Then we can simply get those deleted folder ids from the temporary table and delete relevant articles.