kendi kendine referans tabloları, iyi ya da kötü? [kapalı]


37

Bir uygulamadaki coğrafi konumları temsil eden, temel veri modelinin tasarımı iki açık seçenek (veya belki daha fazlası?) Önermektedir.

Kendi kendini referans veren parent_id sütununa sahip bir tablo uk - london (london parent id = UK id)

veya iki tablo, bir yabancı anahtar kullanarak bire çok ilişkide.

Tercihim, gerektiği kadar çok alt bölgeye kolayca yayılabildiği için kendi kendine referans veren bir tablo için.

Genelde insanlar kendi kendini referans alan tablolardan uzak dururlar mı, yoksa A-OK mi?

Yanıtlar:


40

Kendinden referans tablolarında yanlış bir şey yok.

Derin (sonsuzluk) iç içe sıradüzenler için ortak veritabanı tasarım desenidir.


@NimChimpsky - Özyineleme kavramı gibi, bu fikir bazıları için zordur.
Oded

2
(En azından) Oracle, kendi kendine referans tablolarıyla başa çıkmak için "START WITH - CONNECT BY" yan tümcesinde özel bir SQL yapılandırmasına bile sahip.
user281377

1
@ user281377 - Ayrıca SQL Server hierarchyidtürü tanıttı .
Oded

hazırda bekletmeden önce kendi özel sosuna sahip olacak
NimChimpsky

4
@NimChimpsky - Bu "parent_id" sütununa bir alternatif olarak "Yuvalanmış Set Modeline" bakmayı da düşünün - aynı işlevselliği sağlar, ancak daha iyi performans ve hiyerarşileri çıkarmak için daha kolay sorgular sağlar. en.wikipedia.org/wiki/Nested_set_model Joe Celko'nun "SQL For Smarties" adlı kitap dizisinin iç içe kümeler ile ilgili bazı büyük örnek SQL'leri var.
Keith Palmer Jr.

7

Necromancing.
Doğru cevap: hangi veritabanı motoruna ve hangi yönetim aracına bağlı olduğuna bağlıdır.

Bir örnek verelim:
Bir rapor tablomuz var
ve bir raporun bir ebeveyni (menupoint, kategori gibi)
olabilir ve o ebeveyni bir ebeveyni (örneğin, Kâr merkezi)
vb.

Herhangi bir kendi kendini referans alan varlık / hiyerarşide olduğu gibi standart özyinelemeli ilişkinin en basit örneği.

Sonuçta ortaya çıkan SQL-Server tablosu:

IF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'dbo.FK_T_FMS_Reports_T_FMS_Reports') AND parent_object_id = OBJECT_ID(N'dbo.T_FMS_Reports'))
ALTER TABLE dbo.T_FMS_Reports DROP CONSTRAINT FK_T_FMS_Reports_T_FMS_Reports
GO

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'dbo.T_FMS_Reports') AND type in (N'U'))
DROP TABLE dbo.T_FMS_Reports 
GO



CREATE TABLE dbo.T_FMS_Reports 
( 
     RE_UID uniqueidentifier NOT NULL 
    ,RE_RE_UID uniqueidentifier NULL 
    ,RE_Text nvarchar(255) NULL 
    ,RE_Link nvarchar(400) NULL 
    ,RE_Sort int NOT NULL 
    ,RE_Status int NOT NULL 
    ,PRIMARY KEY CLUSTERED ( RE_UID ) 
); 

GO

ALTER TABLE dbo.T_FMS_Reports  WITH CHECK ADD  CONSTRAINT FK_T_FMS_Reports_T_FMS_Reports FOREIGN KEY(RE_RE_UID) 
REFERENCES dbo.T_FMS_Reports (RE_UID) 
-- ON DELETE CASCADE -- here, MS-SQL has a problem 
GO

ALTER TABLE dbo.T_FMS_Reports CHECK CONSTRAINT FK_T_FMS_Reports_T_FMS_Reports 
GO

Ama bir sorunun olsun:
Eğer tüm submenupoints ile menupoint silmek gerektiğinde, CAN NOT çünkü silme-kaskad set Microsoft SQL-Sunucu diğer taraftan (özyinelemeli basamaklı siler desteklemez, PostGreSQL yapar [ama sadece grafik döngüsel değildir], ancak MySQL bu tür tablo yapısını hiç beğenmez, çünkü özyinelemeli CTE'leri desteklemez).

Bu nedenle, silme-bütünlüğünü / işlevselliğini bu tür işlevsellikten arındırıp, kendi işlevselliğinizde kendi kodunuzda veya saklı bir prosedürde (RDBMS'niz saklı prosedürleri destekliyorsa) uygulamayı zorunlu kılar.

Bu şüphesiz herhangi bir tam otomatik dinamik veri ithalat / ihracatını havaya uçuracaktır, çünkü (otomatik referans olmayan) yabancı anahtar ilişkilerine göre tüm tablolar için bir silme ifadesini çalıştıramazsınız ya da basit bir seçim yapamazsınız. * ve her satır için isteğe göre bir sıra oluşturun.

Örneğin, SSMS'yi kullanarak bir INSERT betiği oluşturduğunuzda, SSMS yabancı anahtarı almaz ve bu nedenle gerçekten bir hatayla başarısız olacak olan bağımlılığın üstünü eklemeden önce bağımlılıklarla entriks ekleyen insert ifadeleri oluşturur. , çünkü yabancı anahtar yerinde.

Ancak, uygun araç gereç yönetim sistemlerinde (PostgreSQL gibi) uygun araçlarla bu bir problem olmamalı. Sadece RDBMS'niz için çok para ödemenizin (size bakıyorum, Microsoft; Oracle =?) Ve / veya alet kemeri olması, doğru bir şekilde programlandığı anlamına gelmez. Ayrıca OpenSource (örn. MySQL) sizi böyle harika minutilere karşı bağışıklık kazandırmaz.

Eski demişler gibi şeytan ayrıntılarda gizlidir.

Şimdi, bu tür sorunları çözemezsiniz, ancak sisteminiz karmaşık olacaksa (örneğin 200+ masa) gerçekten tavsiye etmem.
Artı, normal bir ticari ortamda (Dilbert tarafından tasvir edildiği gibi), o zaman size sadece bir şey verilmeyecek.

Çok daha iyi bir yaklaşım, daha zor olsa da, bir kapatma masası olacaktır.
Bu aynı zamanda MySQL üzerinde de çalıştığı için ilave bir ikramiye olurdu.
Kapatma fonksiyonelliğini bir kez uyguladığınızda, hemen hemen hiç çalışmayacak ek yerlerde çalışmasını sağlayabilirsiniz.


3
Kapama masalarını dikkatime çekmek için +1 (en azından terminoloji, zaten kavramı biliyordu). İşte ilgini çekebilecek başkaları için iyi bir makale. coderwall.com/p/lixing/closure-tables-for-browsing-trees-in-sql
Outfast Kaynak

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.