web-dev-qa-db-ja.com

複数のテーブルのレコードを削除するスクリプト

互いにリンクされている2つ以上のテーブルから特定のレコードを削除したいのですが。

例:2つのテーブル、生徒と受賞者の両方のテーブルからRoyとPeterの名前を一度に削除したいと思います。

表:学生

> ID     name      class
> 1      Roy         2
> 2      James       3
> 3      Carl        4
> 4      Peter       4
> 5      Alice       5

表:勝者

St_ID          achievement
1              1
2              1
3              3
4              5
5              5

すべてのテーブルから削除する50の特定のレコードを持つ100を超えるテーブルがあります。

3
l.lijith

動的SQLクエリを使用してこれを達成する必要があります

1-まず、一時テーブルに対応するデータベースがあるすべてのテーブルをリストする必要があります2- StudentsおよびWinners dataTableを含むデータベースのクエリを作成する

スクリプトは次のようになります

--Get all Databases With corresponding Database

declare @SQL nvarchar(max)
DECLARE @strQuery AS NVARCHAR(MAX)

SET @strQuery = ''

CREATE TABLE #TblTemp (DatabaseName Varchar(255), Tablename Varchar(255))



set @SQL = (select 'union all 
select '''+D.name+''' as DatabaseName,
       T.name collate database_default as TableName
from '+quotename(D.name)+'.sys.tables as T
'
from sys.databases as D
for xml path(''), type).value('substring((./text())[1], 13)', 'nvarchar(max)')

--print @SQL
INSERT INTO #TblTemp
exec (@SQL)

-- Building Queries

SELECT @strQuery = @strQuery + 'Delete T1 from [' + name  + '].dbo.Students As T2
                        Inner join  [' + name  + '].dbo.Winners as T1 
                        On T1.[st_ID] = T2.[ID] 
                        Where    T1.[name] = IN(''Roy'',''Peter'')  ;

DELETE FROM [' + name  + '].dbo.Students WHERE [name] = IN(''Roy'',''Peter'') ;

'

 from sys.databases
 WHERE EXISTS (SELECT 1 FROM #TblTemp WHERE #TblTemp.DatabaseName = name AND #TblTemp.TableName = 'Students') AND
 EXISTS (SELECT 1 FROM #TblTemp WHERE #TblTemp.DatabaseName = name AND #TblTemp.TableName = 'Winners')

--VIEW QUERIES (you can copy result and execute it manually)
SELECT @strQuery



--EXECUTE QUERIES
EXEC(@strQuery)

--DROP Temp Table 
DROP TABLE #TblTemp

これにより、次のようなクエリが生成されます(これらのデータベースにStudentsおよびWinners Tableが含まれている場合)

Delete T1 from [master].dbo.Students As T2   Inner join  [master].dbo.Winners as T1    On T1.[st_ID] = T2.[ID]    Where    T1.[name] = IN('Roy','Peter')  ;     
DELETE FROM [master].dbo.Students WHERE [name] = IN('Roy','Peter') ;     
Delete T1 from [tempdb].dbo.Students As T2   Inner join  [tempdb].dbo.Winners as T1    On T1.[st_ID] = T2.[ID]    Where    T1.[name] = IN('Roy','Peter')  ;     
DELETE FROM [tempdb].dbo.Students WHERE [name] = IN('Roy','Peter') ;     
Delete T1 from [model].dbo.Students As T2   Inner join  [model].dbo.Winners as T1    On T1.[st_ID] = T2.[ID]    Where    T1.[name] = IN('Roy','Peter')  ;     
DELETE FROM [model].dbo.Students WHERE [name] = IN('Roy','Peter') ;     
Delete T1 from [msdb].dbo.Students As T2   Inner join  [msdb].dbo.Winners as T1    On T1.[st_ID] = T2.[ID]    Where    T1.[name] = IN('Roy','Peter')  ;     
DELETE FROM [msdb].dbo.Students WHERE [name] = IN('Roy','Peter') ;     
Delete T1 from [AdventureWorks2008R2].dbo.Students As T2   Inner join  [AdventureWorks2008R2].dbo.Winners as T1    On T1.[st_ID] = T2.[ID]    Where    T1.[name] = IN('Roy','Peter')  ;     DELETE FROM [AdventureWorks2008R2].dbo.Students WHERE [name] = IN('Roy','Peter') ;     Delete T1 from [DbMail].dbo.Students As T2   Inner join  [DbMail].dbo.Winners as T1    On T1.[st_ID] = T2.[ID]    Where    T1.[name] = IN('Roy','Peter')  ;     

以下の質問でそれがあなたが求めていたのであれば、私は今はしません(あなたの質問はこのような具体的なものではなかったので、私の答えは一般に動的SQLロジックを提供することでした)

2
Hadi

正しいアプローチは、動的SQLなしで最初にStudentテーブルからレコードを削除し、削除したIDを一時テーブルに保存することだと思います。

このような、

DECLARE @DeletedSTID table(id int not null)

delete from Students
output deleted.id into @DeletedSTID
where name in('Peter','Roy')

select * from @DeletedSTID

上記の例では、毎回「where name in()」を使用する必要はありません。一度使用して、一時テーブルに保存します。

たとえば、Adventure DBを使用しています。

USE AdventureWorks2012
GO

CREATE TABLE #DeletedSTID (id INT NOT NULL)

CREATE TABLE #temp (tablename VARCHAR(100))

DECLARE @Sql VARCHAR(max) = ''

BEGIN TRY
    BEGIN TRANSACTION

    DELETE
    FROM HumanResources.EmployeeDepartmentHistory
    OUTPUT deleted.BusinessEntityID
    INTO #DeletedSTID
    WHERE BusinessEntityID IN (
            1
            ,2
            )

    INSERT INTO #temp
    SELECT TABLE_NAME
    FROM INFORMATION_SCHEMA.COLUMNS
    WHERE COLUMN_NAME = 'BusinessEntityID'
        AND TABLE_NAME NOT LIKE 'v%'

    SELECT *
    FROM #DeletedSTID

    SELECT *
    FROM #temp

    SELECT @Sql = @Sql + ' delete from ' + tablename + ' a where exists 
(select id from #DeletedSTID b where b.id=a.BusinessEntityID)  '
    FROM #temp

    PRINT @Sql

    EXEC (@Sql)

    ROLLBACK
        --COMMIT
END TRY

BEGIN CATCH
    IF @@TRANCOUNT > 0
        ROLLBACK

    SELECT ERROR_NUMBER() AS ErrorNumber
        ,ERROR_SEVERITY() AS ErrorSeverity
        ,ERROR_STATE() AS ErrorState
        ,ERROR_PROCEDURE() AS ErrorProcedure
        ,ERROR_LINE() AS ErrorLine
        ,ERROR_MESSAGE() AS ErrorMessage;
END CATCH

DROP TABLE #temp

DROP TABLE #DeletedSTID
0
KumarHarsh

とにかく削除する必要があるテーブルを明示的にリストする必要があります。

シナリオの1つは、削除するテーブルのリストを使用してテーブルを作成し、特定の名前を持つ学生のid'sに基づいて適切なdeleteステートメントを適用して、それぞれをループ処理することです。

データベース内のすべてのテーブルをループするには、次のようなものを使用できます。

DECLARE c_tables CURSOR
FOR SELECT table_name
    FROM INFORMATION_SCHEMA.TABLES;

DECLARE
  @table_name VARCHAR(100);

OPEN c_tables;

FETCH NEXT FROM c_tables INTO
  @table_name;

WHILE @@FETCH_STATUS=0
BEGIN
--<your command here>
FETCH NEXT FROM c_tables INTO
  @table_name;
END;

CLOSE c_tables;

DEALLOCATE c_tables;

また、テスト環境でdeleteをテストすることを忘れないでください。

0
George K