Em SQL Server 2005, eu posso fazer uma cascata de exclusão sem definir a propriedade em minhas tabelas?
-
02-07-2019 - |
Pergunta
Eu tenho um banco de dados completo dos dados do cliente. É tão grande que é realmente complicado de operar, e eu prefiro apenas fino para baixo a 10% dos clientes, o que é muito para o desenvolvimento. Eu tenho uma enorme quantidade de mesas e eu não quero alterar a todos com "ON DELETE CASCADE", especialmente porque este é um negócio de uma vez.
Posso fazer uma operação de exclusão que cascatas através de todas as minhas tabelas sem configurá-los em primeiro lugar? Se não, qual é a minha melhor opção?
Solução
Combinando o seu conselho e um script que eu encontrei on-line, eu fiz um procedimento que irá produzir SQL você pode executar para executar uma cascata excluir independentemente do ON DELETE CASCADE
. Foi provavelmente um grande desperdício de tempo, mas eu tinha um bom tempo escrevendo. Uma vantagem de fazê-lo desta maneira é, você pode colocar uma declaração GO
entre cada linha, e ele não tem que ser uma grande transação. O original foi um procedimento recursivo; este desenrola a recursão em uma pilha tabela.
create procedure usp_delete_cascade (
@base_table_name varchar(200), @base_criteria nvarchar(1000)
)
as begin
-- Adapted from http://www.sqlteam.com/article/performing-a-cascade-delete-in-sql-server-7
-- Expects the name of a table, and a conditional for selecting rows
-- within that table that you want deleted.
-- Produces SQL that, when run, deletes all table rows referencing the ones
-- you initially selected, cascading into any number of tables,
-- without the need for "ON DELETE CASCADE".
-- Does not appear to work with self-referencing tables, but it will
-- delete everything beneath them.
-- To make it easy on the server, put a "GO" statement between each line.
declare @to_delete table (
id int identity(1, 1) primary key not null,
criteria nvarchar(1000) not null,
table_name varchar(200) not null,
processed bit not null,
delete_sql varchar(1000)
)
insert into @to_delete (criteria, table_name, processed) values (@base_criteria, @base_table_name, 0)
declare @id int, @criteria nvarchar(1000), @table_name varchar(200)
while exists(select 1 from @to_delete where processed = 0) begin
select top 1 @id = id, @criteria = criteria, @table_name = table_name from @to_delete where processed = 0 order by id desc
insert into @to_delete (criteria, table_name, processed)
select referencing_column.name + ' in (select [' + referenced_column.name + '] from [' + @table_name +'] where ' + @criteria + ')',
referencing_table.name,
0
from sys.foreign_key_columns fk
inner join sys.columns referencing_column on fk.parent_object_id = referencing_column.object_id
and fk.parent_column_id = referencing_column.column_id
inner join sys.columns referenced_column on fk.referenced_object_id = referenced_column.object_id
and fk.referenced_column_id = referenced_column.column_id
inner join sys.objects referencing_table on fk.parent_object_id = referencing_table.object_id
inner join sys.objects referenced_table on fk.referenced_object_id = referenced_table.object_id
inner join sys.objects constraint_object on fk.constraint_object_id = constraint_object.object_id
where referenced_table.name = @table_name
and referencing_table.name != referenced_table.name
update @to_delete set
processed = 1
where id = @id
end
select 'print ''deleting from ' + table_name + '...''; delete from [' + table_name + '] where ' + criteria from @to_delete order by id desc
end
exec usp_delete_cascade 'root_table_name', 'id = 123'
Outras dicas
A menos que você quiser manter todas as consultas relacionadas como proposto por Chris, o ON DELETE CASCADE é de longe o mais rápido e a solução mais direta. E se você não quer que ele seja permanente, por que você não tem um código T-SQL que vai mudar essa opção dentro e fora como aqui
-
remover a restrição
Tbl_A_MyFK
original (sem a ON DELETE CASCADE)ALTER TABLE Tbl_A DROP CONSTRAINT Tbl_A_MyFK
-
definir o
Tbl_A_MyFK
restrição com o ON DELETE CASCADEALTER TABLE Tbl_A ADD CONSTRAINT Tbl_A_MyFK FOREIGN KEY (MyFK) REFERENCES Tbl_B(Column) ON DELETE CASCADE
-
Aqui você pode fazer a sua exclusão
DELETE FROM Tbl_A WHERE ...
-
soltar o seu constrangimento
Tbl_A_MyFK
ALTER TABLE Tbl_A DROP CONSTRAINT Tbl_A_MyFK
-
definir o
Tbl_A_MyFK
restrição sem ON DELETE CASCADEALTER TABLE Tbl_A ADD CONSTRAINT Tbl_A_MyFK FOREIGN KEY (MyFK) REFERENCES (Tbl_B)
Aqui está uma versão da resposta aceita otimizado para modelos de dados escassamente povoadas. Ele verifica a existência de dados em uma cadeia FK antes de adicioná-la à lista de exclusão. Eu usá-lo para limpar dados de teste.
Não usá-lo em uma transação ativa db- que irá realizar bloqueios muito tempo.
/*
-- ============================================================================
-- Purpose: Performs a cascading hard-delete.
-- Not for use on an active transactional database- it holds locks for too long.
-- (http://stackoverflow.com/questions/116968/in-sql-server-2005-can-i-do-a-cascade-delete-without-setting-the-property-on-my)
-- eg:
exec dbo.hp_Common_Delete 'tblConsumer', 'Surname = ''TestDxOverdueOneReviewWm''', 1
-- ============================================================================
*/
create proc [dbo].[hp_Common_Delete]
(
@TableName sysname,
@Where nvarchar(4000), -- Shouldn't include 'where' keyword, e.g. Surname = 'smith', NOT where Surname = 'smith'
@IsDebug bit = 0
)
as
set nocount on
begin try
-- Prepare tables to store deletion criteria.
-- #tmp_to_delete stores criteria that is tested for results before being added to #to_delete
create table #to_delete
(
id int identity(1, 1) primary key not null,
criteria nvarchar(4000) not null,
table_name sysname not null,
processed bit not null default(0)
)
create table #tmp_to_delete
(
id int primary key identity(1,1),
criteria nvarchar(4000) not null,
table_name sysname not null
)
-- Open a transaction (it'll be a long one- don't use this on production!)
-- We need a transaction around criteria generation because we only
-- retain criteria that has rows in the db, and we don't want that to change under us.
begin tran
-- If the top-level table meets the deletion criteria, add it
declare @Sql nvarchar(4000)
set @Sql = 'if exists(select top(1) * from ' + @TableName + ' where ' + @Where + ')
insert #to_delete (criteria, table_name) values (''' + replace(@Where, '''', '''''') + ''', ''' + @TableName + ''')'
exec (@Sql)
-- Loop over deletion table, walking foreign keys to generate delete targets
declare @id int, @tmp_id int, @criteria nvarchar(4000), @new_criteria nvarchar(4000), @table_name sysname, @new_table_name sysname
while exists(select 1 from #to_delete where processed = 0)
begin
-- Grab table/criteria to work on
select top(1) @id = id,
@criteria = criteria,
@table_name = table_name
from #to_delete
where processed = 0
order by id desc
-- Insert all immediate child tables into a temp table for processing
insert #tmp_to_delete
select referencing_column.name + ' in (select [' + referenced_column.name + '] from [' + @table_name +'] where ' + @criteria + ')',
referencing_table.name
from sys.foreign_key_columns fk
inner join sys.columns referencing_column on fk.parent_object_id = referencing_column.object_id
and fk.parent_column_id = referencing_column.column_id
inner join sys.columns referenced_column on fk.referenced_object_id = referenced_column.object_id
and fk.referenced_column_id = referenced_column.column_id
inner join sys.objects referencing_table on fk.parent_object_id = referencing_table.object_id
inner join sys.objects referenced_table on fk.referenced_object_id = referenced_table.object_id
inner join sys.objects constraint_object on fk.constraint_object_id = constraint_object.object_id
where referenced_table.name = @table_name
and referencing_table.name != referenced_table.name
-- Loop on child table criteria, and insert them into delete table if they have records in the db
select @tmp_id = max(id) from #tmp_to_delete
while (@tmp_id >= 1)
begin
select @new_criteria = criteria, @new_table_name = table_name from #tmp_to_delete where id = @tmp_id
set @Sql = 'if exists(select top(1) * from ' + @new_table_name + ' where ' + @new_criteria + ')
insert #to_delete (criteria, table_name) values (''' + replace(@new_criteria, '''', '''''') + ''', ''' + @new_table_name + ''')'
exec (@Sql)
set @tmp_id = @tmp_id - 1
end
truncate table #tmp_to_delete
-- Move to next record
update #to_delete
set processed = 1
where id = @id
end
-- We have a list of all tables requiring deletion. Actually delete now.
select @id = max(id) from #to_delete
while (@id >= 1)
begin
select @criteria = criteria, @table_name = table_name from #to_delete where id = @id
set @Sql = 'delete from [' + @table_name + '] where ' + @criteria
if (@IsDebug = 1) print @Sql
exec (@Sql)
-- Next record
set @id = @id - 1
end
commit
end try
begin catch
-- Any error results in a rollback of the entire job
if (@@trancount > 0) rollback
declare @message nvarchar(2047), @errorProcedure nvarchar(126), @errorMessage nvarchar(2048), @errorNumber int, @errorSeverity int, @errorState int, @errorLine int
select @errorProcedure = isnull(error_procedure(), N'hp_Common_Delete'),
@errorMessage = isnull(error_message(), N'hp_Common_Delete unable to determine error message'),
@errorNumber = error_number(), @errorSeverity = error_severity(), @errorState = error_state(), @errorLine = error_line()
-- Prepare error information as it would be output in SQL Mgt Studio
declare @event nvarchar(2047)
select @event = 'Msg ' + isnull(cast(@errorNumber as varchar), 'null') +
', Level ' + isnull(cast(@errorSeverity as varchar), 'null') +
', State ' + isnull(cast(@errorState as varchar), 'null') +
', Procedure ' + isnull(@errorProcedure, 'null') +
', Line ' + isnull(cast(@errorLine as varchar), 'null') +
': ' + isnull(@errorMessage, '@ErrorMessage null')
print @event
-- Re-raise error to ensure admin/job runners understand there was a failure
raiserror(@errorMessage, @errorSeverity, @errorState)
end catch
Vá para o SQL Server Management Studio e clique com o botão direito no banco de dados. Select Tarefas-> Gerar Scripts. Clique em Avançar duas vezes. Na janela Opções de escolha configurá-lo para gerar criar apenas declarações, e colocar tudo para Falso exceto para as chaves estrangeiras. Clique em Avançar. Selecione Tabelas e clique em Avançar novamente. Clique no botão "Selecionar Tudo" e clique em Avançar, em seguida, em Concluir e enviar o script para a sua escolha de uma janela de consulta ou arquivo (não use a área de transferência, uma vez que pode ser um grande script). Agora remover todo o script que adiciona as tabelas e você deve ser deixado com um script para criar suas chaves estrangeiras.
Faça uma cópia desse programa, porque ele é como você vai restaurar o banco de dados para seu estado atual. Use uma pesquisa e substituição para adicionar o CASCADE ON DELETE para o final de cada restrição. Isso pode variar dependendo de como seus FKs estão actualmente a configurar e pode ser necessário fazer alguma edição manual.
Repita a geração de scripts, mas desta vez configurá-lo para gerar apenas DROP. Certifique-se de remover manualmente as gotas de mesa que são gerados . Execute as gotas, em seguida, executar o seu editados cria para torná-los todos em cascata em delete. Faça suas exclusões, executar o script queda novamente e, em seguida, executar o script que guardou off no início.
Além disso! - Faça um backup do seu db PRIMEIRO Mesmo que seja apenas um banco de dados dev, ela vai lhe poupar algumas dores de cabeça se parte do script não é muito justo
.Espero que isso ajude!
BTW - você definitivamente deve fazer alguns testes com os seus dados de teste completo como outro cartaz sugerido, mas eu posso ver porque você pode não precisar que para o desenvolvimento inicial. Só não se esqueça de incluir isso como parte da QA em algum ponto.
Eu normalmente só mão escreve as consultas para excluir os registros que eu não quero e salvar isso como um arquivo .sql para referência futura. O pseudocódigo é:
- select id é de registros da tabela principal que eu quero excluir em uma tabela temporária
- escrever uma consulta de exclusão para cada tabela relacionada que se junta a tabela temporária.
- escrever uma consulta de exclusão para a tabela principal se juntar à minha tabela temporária.
A minha sugestão é ir em frente e escrever um script que irá adicionar o em cascata delete para cada relacionamento no banco de dados ao exportar uma lista de relacionamentos modificados. Depois, você pode reverter o processo e remova o no comando de exclusão em cascata em cada tabela na lista.
Pessoalmente, se você estiver indo para deixar os registros na produção, Também gostaria de deixá-los no desenvolvimento. Caso contrário, você pode escrever código que funciona bem quando o conjunto de registros é pequeno, mas expira quando confrontado com o conjunto de registros real.
Mas se você está determinado a fazer isso, eu iria copiar o campo id dos registros que deseja Dete da tabela principal primeiro a uma mesa de trabalho. Então eu levaria cada tabela relacionada e escrever uma exclusão se juntar a essa mesa de trabalho para excluir somente esses registros. Concluir-se com a tabela pai. Certifique-se que este ia escrito em um script e salvo para a próxima vez que você quer fazer uma coisa semelhante para os dados de teste, você pode facilmente executá-lo sem ter que descobrir o que são as tabelas reated que os registros necessidade excluídos deles.
Tomar um pouco mais a resposta aceita, tive a necessidade de fazer isso através de tabelas em diferentes esquemas. Eu atualizei o script para incluir esquema nos scripts de exclusão emitidas.
CREATE PROCEDURE usp_delete_cascade (
@base_table_schema varchar(100), @base_table_name varchar(200), @base_criteria nvarchar(1000)
)
as begin
-- Expects the name of a table, and a conditional for selecting rows
-- within that table that you want deleted.
-- Produces SQL that, when run, deletes all table rows referencing the ones
-- you initially selected, cascading into any number of tables,
-- without the need for "ON DELETE CASCADE".
-- Does not appear to work with self-referencing tables, but it will
-- delete everything beneath them.
-- To make it easy on the server, put a "GO" statement between each line.
declare @to_delete table (
id int identity(1, 1) primary key not null,
criteria nvarchar(1000) not null,
table_schema varchar(100),
table_name varchar(200) not null,
processed bit not null,
delete_sql varchar(1000)
)
insert into @to_delete (criteria, table_schema, table_name, processed) values (@base_criteria, @base_table_schema, @base_table_name, 0)
declare @id int, @criteria nvarchar(1000), @table_name varchar(200), @table_schema varchar(100)
while exists(select 1 from @to_delete where processed = 0) begin
select top 1 @id = id, @criteria = criteria, @table_name = table_name, @table_schema = table_schema from @to_delete where processed = 0 order by id desc
insert into @to_delete (criteria, table_schema, table_name, processed)
select referencing_column.name + ' in (select [' + referenced_column.name + '] from [' + @table_schema + '].[' + @table_name +'] where ' + @criteria + ')',
schematable.name,
referencing_table.name,
0
from sys.foreign_key_columns fk
inner join sys.columns referencing_column on fk.parent_object_id = referencing_column.object_id
and fk.parent_column_id = referencing_column.column_id
inner join sys.columns referenced_column on fk.referenced_object_id = referenced_column.object_id
and fk.referenced_column_id = referenced_column.column_id
inner join sys.objects referencing_table on fk.parent_object_id = referencing_table.object_id
inner join sys.schemas schematable on referencing_table.schema_id = schematable.schema_id
inner join sys.objects referenced_table on fk.referenced_object_id = referenced_table.object_id
inner join sys.objects constraint_object on fk.constraint_object_id = constraint_object.object_id
where referenced_table.name = @table_name
and referencing_table.name != referenced_table.name
update @to_delete set
processed = 1
where id = @id
end
select 'print ''deleting from ' + table_name + '...''; delete from [' + table_schema + '].[' + table_name + '] where ' + criteria from @to_delete order by id desc
end
exec usp_delete_cascade 'schema', 'RootTable', 'Id = 123'
exec usp_delete_cascade 'schema', 'RootTable', 'GuidId = ''A7202F84-FA57-4355-B499-1F8718E29058'''
Kevin post é incompleta, sua sp t-sql só imprime o comando, para executar estes comandos, antes da última final adicione
DECLARE @commandText VARCHAR(8000)
DECLARE curDeletes CURSOR FOR
select 'delete from [' + table_name + '] where ' + criteria from @to_delete order by id desc
OPEN curDeletes
FETCH NEXT FROM curDeletes
INTO
@commandText
WHILE(@@FETCH_STATUS=0)
BEGIN
EXEC (@commandText)
FETCH NEXT FROM curDeletes INTO @commandText
END
CLOSE curDeletes
DEALLOCATE curDeletes
Expansão da resposta de croisharp tomar gatilhos em consideração, ou seja, solução schema-cientes de que desativa todos os gatilhos que afetam, exclui linhas, e permite que os gatilhos.
CREATE PROCEDURE usp_delete_cascade (
@base_table_schema varchar(100),
@base_table_name varchar(200),
@base_criteria nvarchar(1000)
)
as begin
-- Expects the name of a table, and a conditional for selecting rows
-- within that table that you want deleted.
-- Produces SQL that, when run, deletes all table rows referencing the ones
-- you initially selected, cascading into any number of tables,
-- without the need for "ON DELETE CASCADE".
-- Does not appear to work with self-referencing tables, but it will
-- delete everything beneath them.
-- To make it easy on the server, put a "GO" statement between each line.
declare @to_delete table (
id int identity(1, 1) primary key not null,
criteria nvarchar(1000) not null,
table_schema varchar(100),
table_name varchar(200) not null,
processed bit not null,
delete_sql varchar(1000)
)
insert into @to_delete (criteria, table_schema, table_name, processed) values (@base_criteria, @base_table_schema, @base_table_name, 0)
declare @id int, @criteria nvarchar(1000), @table_name varchar(200), @table_schema varchar(100)
while exists(select 1 from @to_delete where processed = 0) begin
select top 1 @id = id, @criteria = criteria, @table_name = table_name, @table_schema = table_schema from @to_delete where processed = 0 order by id desc
insert into @to_delete (criteria, table_schema, table_name, processed)
select referencing_column.name + ' in (select [' + referenced_column.name + '] from [' + @table_schema + '].[' + @table_name +'] where ' + @criteria + ')',
schematable.name,
referencing_table.name,
0
from sys.foreign_key_columns fk
inner join sys.columns referencing_column on fk.parent_object_id = referencing_column.object_id
and fk.parent_column_id = referencing_column.column_id
inner join sys.columns referenced_column on fk.referenced_object_id = referenced_column.object_id
and fk.referenced_column_id = referenced_column.column_id
inner join sys.objects referencing_table on fk.parent_object_id = referencing_table.object_id
inner join sys.schemas schematable on referencing_table.schema_id = schematable.schema_id
inner join sys.objects referenced_table on fk.referenced_object_id = referenced_table.object_id
inner join sys.objects constraint_object on fk.constraint_object_id = constraint_object.object_id
where referenced_table.name = @table_name
and referencing_table.name != referenced_table.name
update @to_delete set
processed = 1
where id = @id
end
select 'print ''deleting from ' + table_name + '...''; delete from [' + table_schema + '].[' + table_name + '] where ' + criteria from @to_delete order by id desc
DECLARE @commandText VARCHAR(8000), @triggerOn VARCHAR(8000), @triggerOff VARCHAR(8000)
DECLARE curDeletes CURSOR FOR
select
'DELETE FROM [' + table_schema + '].[' + table_name + '] WHERE ' + criteria,
'ALTER TABLE [' + table_schema + '].[' + table_name + '] DISABLE TRIGGER ALL',
'ALTER TABLE [' + table_schema + '].[' + table_name + '] ENABLE TRIGGER ALL'
from @to_delete order by id desc
OPEN curDeletes
FETCH NEXT FROM curDeletes INTO @commandText, @triggerOff, @triggerOn
WHILE(@@FETCH_STATUS=0)
BEGIN
EXEC (@triggerOff)
EXEC (@commandText)
EXEC (@triggerOn)
FETCH NEXT FROM curDeletes INTO @commandText, @triggerOff, @triggerOn
END
CLOSE curDeletes
DEALLOCATE curDeletes
end
depois de selecionar você tem que construir e executar a actual exclusão
declare @deleteSql nvarchar(1200)
declare delete_cursor cursor for
select table_name, criteria
from @to_delete
order by id desc
open delete_cursor
fetch next from delete_cursor
into @table_name, @criteria
while @@fetch_status = 0
begin
select @deleteSql = 'delete from ' + @table_name + ' where ' + @criteria
--print @deleteSql
-- exec sp_execute @deleteSql
EXEC SP_EXECUTESQL @deleteSql
fetch next from delete_cursor
into @table_name, @criteria
end
close delete_cursor
deallocate delete_cursor
Poste aqui um script que irá trabalhar com chaves estrangeiras conter mais de uma coluna.
create procedure usp_delete_cascade (
@TableName varchar(200), @Where nvarchar(1000)
) as begin
declare @to_delete table (
id int identity(1, 1) primary key not null,
criteria nvarchar(1000) not null,
table_name varchar(200) not null,
processed bit not null default(0),
delete_sql varchar(1000)
)
DECLARE @MyCursor CURSOR
declare @referencing_column_name varchar(1000)
declare @referencing_table_name varchar(1000)
declare @Sql nvarchar(4000)
insert into @to_delete (criteria, table_name) values ('', @TableName)
declare @id int, @criteria nvarchar(1000), @table_name varchar(200)
while exists(select 1 from @to_delete where processed = 0) begin
select top 1 @id = id, @criteria = criteria, @table_name = table_name from @to_delete where processed = 0 order by id desc
SET @MyCursor = CURSOR FAST_FORWARD
FOR
select referencing_column.name as column_name,
referencing_table.name as table_name
from sys.foreign_key_columns fk
inner join sys.columns referencing_column on fk.parent_object_id = referencing_column.object_id
and fk.parent_column_id = referencing_column.column_id
inner join sys.columns referenced_column on fk.referenced_object_id = referenced_column.object_id
and fk.referenced_column_id = referenced_column.column_id
inner join sys.objects referencing_table on fk.parent_object_id = referencing_table.object_id
inner join sys.objects referenced_table on fk.referenced_object_id = referenced_table.object_id
inner join sys.objects constraint_object on fk.constraint_object_id = constraint_object.object_id
where referenced_table.name = @table_name
and referencing_table.name != referenced_table.name
OPEN @MyCursor
FETCH NEXT FROM @MYCursor
INTO @referencing_column_name, @referencing_table_name
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT @referencing_column_name
PRINT @referencing_table_name
update @to_delete set criteria = criteria + ' AND '+@table_name+'.'+@referencing_column_name+'='+ @referencing_table_name+'.'+@referencing_column_name
where table_name = @referencing_table_name
if(@@ROWCOUNT = 0)
BEGIN
--if(@id <> 1)
--BEGIN
insert into @to_delete (criteria, table_name)
VALUES( ' LEFT JOIN '+@table_name+' ON '+@table_name+'.'+@referencing_column_name+'='+ @referencing_table_name+'.'+@referencing_column_name+ @criteria,
@referencing_table_name
)
--END
--ELSE
--BEGIN
--insert into @to_delete (criteria, table_name)
--VALUES( ' LEFT JOIN '+@table_name+' ON '+@table_name+'.'+@referencing_column_name+'='+ @referencing_table_name+'.'+@referencing_column_name,
--@referencing_table_name
--)
--END
END
FETCH NEXT FROM @MYCursor
INTO @referencing_column_name, @referencing_table_name
END
CLOSE @MyCursor
DEALLOCATE @MyCursor
update @to_delete set
processed = 1
where id = @id
end
--select 'print ''deleting from ' + table_name + '...''; delete from [' + table_name + '] where ' + criteria from @to_delete order by id desc
--select id, table_name, criteria, @Where from @to_delete order by id desc
select @id = max(id) from @to_delete
while (@id >= 1)
begin
select @criteria = criteria, @table_name = table_name from @to_delete where id = @id
set @Sql = 'delete [' + @table_name + '] from [' + @table_name + '] ' + @criteria+' WHERE '+@Where
exec (@Sql)
PRINT @Sql
-- Next record
set @id = @id - 1
end
end
Este script tem dois problemas: 1. Você deve indicar a condição de 1 = 1, a fim de eliminar toda a base de mesa. 2. Isso cria as relações diretas com apenas a tabela de base. Se a tabela final tem outra relação tabela pai, o da exclusão falhar
DELETE FROM [dbo]. [Table2] ONDE TableID em (seleccionar [id] a partir de [dbo]. [Tabela 3] em que 1 = 1)
Se table2 tem uma relação pai table1