2011-06-10 14 views
14

Bir satır, FK üzerinden silecek sırayı referans alıyorsa silemezsiniz.SQL Server: Satır sırasına herhangi bir satır atıfta bulunup bulunmadığını öğrenmek için

DELETE ifadesini çalıştırmadan önce, satır sırasına herhangi bir sıranın başvuruda bulunup bulunmadığını bilmek mümkün mü?

+0

olası yinelenen http://stackoverflow.com/questions/6244077/help-on-sql -server-tetikleyici – gbn

+0

Amacım bir basamaklı silme neden değil, kayıt silinebilir ise önceden bilmek. Eğer silinemez değilse, kullanıcı silinemez olmadığını bildirecektir. – Yeonho

+2

Zaten bir cevabı işaretlediğinizi biliyorum, ancak bu çok kullanıcılı bir sistemse, en iyi cevap sadece silme girişiminde bulunmak ve meydana gelen bir hatayla başa çıkmak olabilir - aksi takdirde, burada her türlü yarış koşulları mümkündür. Her şeyi yüksek izolasyonlu bir işlemde sarın. –

cevap

18

Bu komut dosyası silmek çalıştığınız satır başvuru satırları olan tüm tabloları gösterecektir.

3

Seçenek 1 (Algılama):

Bir Select Statement herhangi kayıtları Kayıt-to-silinecek başvuran olup olmadığını belirlemek için gerçekleştirmek - Eğer isterseniz , elle kayıtları silmek ve o referans ver. Bu da tetikleyicilere tavsiye etmeme rağmen bir tetikleyici kullanarak gerçekleştirilebilir, çünkü insanlar (ve kendiniz) yolda şaşırtma eğilimi gösterirler.

Seçenek 2 (Otomasyon):

şekilde konfigüre da silinecek Kayıt-to-silinecek başvuran tüm kayıtları neden olacak Cascading Deletes içine bakabilirsiniz.

zaman Cascade ilişkinin semantik bir açıklama "parçası olan" içerebilir zaman mantıklı olabilir Sil

  • (Joel Coehoorn tarafından yazılan metin paraphrased) Basamaklı siler kullanmak. Örnek: Web Sırası, Web Sırası Satır Öğeleri
  • Geçmişi koruyorsanız veya yalnızca silinmiş bir bit sütunu ayarladığınız bir yumuşak silme kullanarak Cascade Delete'i kullanmamalısınız.
  • Cascading; yabancı anahtarlar yanlış.
  • Tam olarak anlamadan önce basamaklı kullanmak akıllıca değildir. Ancak, bu yararlı bir özelliktir ve bu nedenle anlamak için zaman ayırmaya değer.

Stackoverflow üzerinde Cascading Deletes ile ilgili büyük bir tartışma var. yabancı anahtar kompozit olmadığını

declare @RowId int = 1 
declare @TableName sysname = 'ParentTable' 

declare @Command varchar(max) 

select @Command = isnull(@Command + ' union all ', '') + 'select ''' + object_name(parent_object_id) + 
    ''' where exists(select * from ' + object_name(parent_object_id) + ' where ' + col.name+ ' = ' + cast(@RowId as varchar) + ')' 
from sys.foreign_key_columns fkc 
    join sys.columns col on 
     fkc.parent_object_id = col.object_id and fkc.parent_column_id = col.column_id 
where object_name(referenced_object_id) = @TableName 

execute (@Command) 

Varsayım:

+0

, SQL Server bir istisna atar. SQL Server, referans gösteren herhangi bir kayıt olup olmadığını bilmek için dahili bir SELECT ifadesi gerçekleştiriyor mu? – Yeonho

+2

SQL çeşitli yollarla ilişkileri ve kısıtlamaları takip eder, bu yöntemlerden bazıları seçim ifadelerine benzer. Ancak, daha çok çöp toplama gibi düşünüyorum. "Artık bu bellek parçasına bir şey atıfta bulunmuyor, bu yüzden onu silebilirim" –

0

kimse söz vardır, ama sadece kayıt için ben dbo.mytable ilgili tüm kısıtlamaları bulmak için bir sürü prosedür

sp_helpconstraint 'dbo.mytable' 

kullanın ve hangi tabloları dbo.mytable başvurur. Çok kullanışlı ve kullanışlı buluyorum.

0

Alex Aza'nın çözümünü geliştirdim.

Ben softdelete kullanıyorum, bu yüzden "where" durumunda bir "delete" sütunu eklemek gerekiyor. Ve daha fazlası TSQL'de, tablo, NHibernate'de miras alınan nesneyi temsil ettiğinde ve PK'nin ana tablodan FK olduğunu keşfettiğimde bir işlev yaptım.

Takip:

declare @RowId int = 4 
declare @TableName sysname = 'TABLE' 

declare @Command varchar(max) 

select @Command = isnull(@Command + ' union all ', '') + 'select ''' + object_name(parent_object_id) + 
    ''' where exists(select * from ' + object_name(parent_object_id) + 
    CASE 
     WHEN EXISTS(select object_name(object_id) from sys.columns col where name = 'deleted' and object_id = parent_object_id) 
      THEN ' where ' + col.name+ ' = ' + cast(@RowId as varchar) +' and deleted = 0 ' 
     when dbo.ParentIdFromTable(object_name(parent_object_id)) <> '' 
      then ' inner join ' + dbo.ParentIdFromTable(object_name(parent_object_id)) + ' on id = ' + dbo.PrimaryKey(object_name(parent_object_id)) 
       +' where ' + col.name+ ' = ' + cast(@RowId as varchar) +' and deleted = 0 ' 
     else 
      ' where ' + col.name+ ' = ' + cast(@RowId as varchar) 
     END 
    + ')' 
from sys.foreign_key_columns fkc 
    join sys.columns col on 
     fkc.parent_object_id = col.object_id and fkc.parent_column_id = col.column_id 
where object_name(referenced_object_id) = @TableName 

PRINT @Command 
execute (@Command) 

Depedencies Fonksiyonlar:

CREATE FUNCTION dbo.ParentIdFromTable(@Table varchar(255)) 
RETURNS varchar(255) 
AS 
BEGIN 
    declare @tableParent varchar(255) = '' 

    if exists(select pk.TABLE_NAME, pk.COLUMN_NAME, col.name, object_name(referenced_object_id) Referenced, object_name(parent_object_id) as Parent 
     from sys.columns col 
      inner join sys.foreign_key_columns fkc on 
       fkc.parent_object_id = col.object_id and fkc.parent_column_id = col.column_id 
      inner join INFORMATION_SCHEMA.KEY_COLUMN_USAGE pk on 
       pk.TABLE_NAME = object_name(object_id) and pk.COLUMN_NAME = col.name 
     WHERE OBJECTPROPERTY(OBJECT_ID(constraint_name), 'IsPrimaryKey') = 1 
     AND table_name = @table) 
    begin 

     while exists(select * 
      from sys.columns col 
      inner join sys.foreign_key_columns fkc on 
       fkc.parent_object_id = col.object_id and fkc.parent_column_id = col.column_id 
      inner join INFORMATION_SCHEMA.KEY_COLUMN_USAGE pk on 
       pk.TABLE_NAME = object_name(object_id) and pk.COLUMN_NAME = col.name 
      WHERE OBJECTPROPERTY(OBJECT_ID(constraint_name), 'IsPrimaryKey') = 1 AND table_name = @table) 
     begin 
      -- Descobrir o parent, column 
      select @tableParent = object_name(referenced_object_id) 
      from sys.columns col 
      inner join sys.foreign_key_columns fkc on 
       fkc.parent_object_id = col.object_id and fkc.parent_column_id = col.column_id 
      inner join INFORMATION_SCHEMA.KEY_COLUMN_USAGE pk on 
       pk.TABLE_NAME = object_name(object_id) and pk.COLUMN_NAME = col.name 
      WHERE OBJECTPROPERTY(OBJECT_ID(constraint_name), 'IsPrimaryKey') = 1 
      AND table_name = @table 

      --print @tableParent 
      set @table = @tableParent 
     end 
    end 

    return @tableParent; 
END; 
GO 


CREATE FUNCTION dbo.PrimaryKey(@Table varchar(255)) 
RETURNS varchar(255) 
AS 
BEGIN 
    declare @columnName varchar(255) = '' 
    -- Descobrir o parent, column 
    select @columnName = COLUMN_NAME 
    from INFORMATION_SCHEMA.KEY_COLUMN_USAGE 
    WHERE OBJECTPROPERTY(OBJECT_ID(constraint_name), 'IsPrimaryKey') = 1 
    AND table_name = @Table 

    return @columnName 
end; 
[SQL Server tetiğe Yardım] (içinde
İlgili konular