互いにリンクされている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を超えるテーブルがあります。
動的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ロジックを提供することでした)
正しいアプローチは、動的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
とにかく削除する必要があるテーブルを明示的にリストする必要があります。
シナリオの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
をテストすることを忘れないでください。