PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Postgresql exclui várias linhas de várias tabelas


Organizar exclusões em cascata apropriadas é sábio e geralmente é a solução correta para isso. Para certos casos especiais, há outra solução para isso que pode ser relevante.

Se você precisar executar várias exclusões com base em um conjunto comum de dados, use Expressões de tabela comuns (CTE) .

É difícil encontrar um exemplo simples, pois o principal caso de uso para isso pode ser coberto por exclusões em cascata.

Para o exemplo, vamos excluir todos os itens da tabela A cujo valor está no conjunto de valores que estamos excluindo da tabela B. Normalmente, essas seriam chaves, mas onde não são, a exclusão em cascata não pode ser usada .

Para resolver isso você usa CTEs
WITH Bdeletes AS (
    DELETE from B where IsSomethingToDelete = true returning ValueThatRelatesToA
)
delete from A where RelatedValue in (select ValueThatRelatesToA from Bdeletes)

Este exemplo é deliberadamente simples porque meu objetivo não é discutir sobre mapeamento de teclas etc, mas mostrar como duas ou mais exclusões podem ser executadas em um conjunto de dados compartilhado. Isso também pode ser muito mais complexo, incluindo comandos de atualização etc.

Aqui está um exemplo mais complexo (do banco de dados pessoal de Darth Vader). Nesse caso, temos uma tabela que faz referência a uma tabela de endereços. Precisamos deletar endereços da tabela de endereços se eles estiverem na lista de planetas que ele destruiu. Queremos usar essas informações para excluir da tabela de pessoas, mas apenas se elas estiverem no planeta (ou em sua lista de mortes de troféus)
with AddressesToDelete as (
    select AddressId from Addresses a 
    join PlanetsDestroyed pd on pd.PlanetName = a.PlanetName
),
PeopleDeleted as (
    delete from People 
    where AddressId in (select * from AddressesToDelete)
    and OffPlanet = false 
    and TrophyKill = false
    returning Id
),
PeopleMissed as (
    update People 
    set AddressId=null, dead=(OffPlanet=false)
    where AddressId in (select * from AddressesToDelete)
    returning id
)
Delete from Addresses where AddressId in (select * from AddressesToDelete)

Agora seu banco de dados está atualizado. Nenhuma falha de integridade devido à exclusão de endereço. Observe que, embora estejamos retornando dados da atualização e da primeira exclusão, isso não significa que precisamos usá-los. Não tenho certeza se você pode colocar uma exclusão em um CTE sem dados retornados (Meu SQL também pode estar errado no uso de retornar de uma atualização - não consegui testar isso, pois Darth V. humor maluco.