SORU
13 Ocak 2009, Salı


Olası Olası iki tablo için MySQL yabancı anahtar yapmak için?

Burada üç tablo; bölgeler, ülkeler, devletler var benim sorunum. Bölge ülkeleri içinde, devletler, bölgeler içinde olabilir. Bölgeler besin zincirinin en üst düzeyde.

Şimdi iki sütun; region_id ve popular_place_id ile popular_areas bir tablo ekliyorum. Popular_place_id her iki ülke için yabancı anahtar yapmak mümkünYABirleşik Devletleri. Muhtemelen kimliği ülke veya bir devlet tarif olup olmadığını belirlemek için popular_place_type bir sütun eklemek ya da böyle yapacağım.

CEVAP
13 Ocak 2009, Salı


Anladığım kadarıyla bu Polimorfik Dernekler denir. Yani, "yabancı anahtar" sütun hedef tablo olarak bulunması gereken bir kimlik değeri içerir. Genellikle hedef tabloları veri bazı ortak üst sınıf örnekleri gibi bir şekilde bağı vardır. Ayrıca her satırda, başvurulan belirleyebilirsiniz, böylece yanında bir sütun yabancı anahtar sütunu gerekir.

CREATE TABLE popular_places (
  user_id INT NOT NULL,
  place_id INT NOT NULL,
  place_type VARCHAR(10) -- either 'states' or 'countries'
  -- foreign key is not possible
);

Polimorfik Dernekler SQL kısıtlamaları kullanarak modeli yol yok. Yabancı anahtar kısıtlaması her zaman başvuruyorbirtablo hedef.

Polimorfik Dernekler Raylar ve Hazırda bekleme gibi çerçeveler tarafından desteklenmektedir. Ama onlar açıkça SQL kısıtlamaları bu özelliği kullanmak için devre dışı bırakmanız gerektiğini söylüyorlar. Bunun yerine, uygulama veya çerçeve eşdeğer iş başvurusu memnun olduğundan emin olmak için yapmak gerekir. Yani, yabancı anahtar değeri ile olası hedef tablolardan birini hediye.

Polimorfik Dernekler veritabanı tutarlılık uygulanması açısından zayıf. Veri bütünlüğünü tüm istemciler aynı veri bütünlüğü mantık zorlanan veritabanına erişim bağlıdır, ve aynı zamanda icra virüssüz olmalı.

İşte bazı alternatif çözümler yararlanmak veritabanı zorlanan tutarlılığı:

Hedef başına bir ekstra tablo oluşturun.Örneğin popular_states states countries sırasıyla referans popular_countries,. Bunların her biri "popüler" tabloları da referans kullanıcı profili.

CREATE TABLE popular_states (
  state_id INT NOT NULL,
  user_id  INT NOT NULL,
  PRIMARY KEY(state_id, user_id),
  FOREIGN KEY (state_id) REFERENCES states(state_id),
  FOREIGN KEY (user_id) REFERENCES users(user_id),
);

CREATE TABLE popular_countries (
  country_id INT NOT NULL,
  user_id    INT NOT NULL,
  PRIMARY KEY(country_id, user_id),
  FOREIGN KEY (country_id) REFERENCES countries(country_id),
  FOREIGN KEY (user_id) REFERENCES users(user_id),
);

Bu bir kullanıcı popüler en sevdiğim yerlerden almak için bu tabloların her ikisi de sorgulamak gerekir anlamına gelmez. Ama veritabanı tutarlılığını zorlamak için güvenebileceğiniz anlamına gelir.

Bir supertable places bir tablo oluşturmak.Abie bahseder gibi, ikinci bir alternatif popüler yerler states countries hem de bir ebeveyn olduğu places gibi bir tablo başvurusu. Yani, her iki ülke ve ülkeler de places yabancı anahtar (yabancı anahtar bile bu da states countries birincil anahtar olarak yapabilirsiniz).

CREATE TABLE popular_areas (
  user_id INT NOT NULL,
  place_id INT NOT NULL,
  PRIMARY KEY (user_id, place_id),
  FOREIGN KEY (place_id) REFERENCES places(place_id)
);

CREATE TABLE states (
  state_id INT NOT NULL PRIMARY KEY,
  FOREIGN KEY (state_id) REFERENCES places(place_id)
);

CREATE TABLE countries (
  country_id INT NOT NULL PRIMARY KEY,
  FOREIGN KEY (country_id) REFERENCES places(place_id)
);

İki sütun kullanın.İki hedef tabloları da referans olabilecek bir sütun yerine, iki sütun kullanın. Bu iki sütun NULL; aslında sadece bir tanesi olmayanNULL olmalıdır olabilir.

CREATE TABLE popular_areas (
  place_id SERIAL PRIMARY KEY,
  user_id INT NOT NULL,
  state_id INT,
  country_id INT,
  CONSTRAINT UNIQUE (user_id, state_id, country_id), -- UNIQUE permits NULLs
  CONSTRAINT CHECK (state_id IS NOT NULL OR country_id IS NOT NULL),
  FOREIGN KEY (state_id) REFERENCES places(place_id),
  FOREIGN KEY (country_id) REFERENCES places(place_id)
);

Ya da bir devlet veya bir ülke. ilişkisel teorisi açısından, Polimorfik Birlikleri popular_place_id bir sütun iki anlamı ile etkin olduğundan First Normal Form ihlal: Olmaz deposu kişinin age phone_number bir tek sütun, ve aynı sebepten dolayı olmamalı deposu state_id country_id tek bir sütun. Bu iki özellik uyumlu bir veri türü olması tesadüfi değildir; onlar hala farklı bir mantıksal varlık anlamına gelir.

Polimorfik Dernekleri de sütunun anlamı yabancı anahtar anlamına gelir ekstra sütun bağlı olduğundan Third Normal Form, ihlal ediyor. Üçüncü Normal Formda, tablonun bir öznitelik tablo birincil anahtar sadece bağlı olmalıdır.


Re @yorum SavasVedova:

Ben pek emin değilim açıklamanızı görmeden tabloyu tanımlar ya da bir örnek sorgu, ama göründüğü gibi sadece birden fazla Filters tabloları içeren her bir yabancı anahtar başvuruları merkezi Products tablo.

CREATE TABLE Products (
  product_id INT PRIMARY KEY
);

CREATE TABLE FiltersType1 (
  filter_id INT PRIMARY KEY,
  product_id INT NOT NULL,
  FOREIGN KEY (product_id) REFERENCES Products(product_id)
);

CREATE TABLE FiltersType2 (
  filter_id INT  PRIMARY KEY,
  product_id INT NOT NULL,
  FOREIGN KEY (product_id) REFERENCES Products(product_id)
);

...and other filter tables...

Belirli bir filtre türünü ürünler katılması için katılmak istediğiniz biliyorsanız kolaydır:

SELECT * FROM Products
INNER JOIN FiltersType2 USING (product_id)

Eğer dinamik olarak filtre türünü istiyorsanız, uygulama kodu SQL sorgu oluşturmak için yazmak gerekir. SQL tablo belirtilen ve sorgu yazma süresi sabit olmasını gerektirir. Birleştirilen tablo değerleri dinamik olarak Products tek satır bulundu göre seçmiş yapamazsın.

Sadece diğer seçeneği katıltümtablolar dış filtre kullanarak katıldı. Eşleşen product_id bu boşluk sadece tek bir satır olarak iade edilecektir. Ama yine de koda gerektümtabloları katıldı, ve eğer yeni filtre tablo eklerseniz, kodu güncelleştirme.

SELECT * FROM Products
LEFT OUTER JOIN FiltersType1 USING (product_id)
LEFT OUTER JOIN FiltersType2 USING (product_id)
LEFT OUTER JOIN FiltersType3 USING (product_id)
...

Tüm filtre tablolara katılmak için başka bir yoludur seri yapmak için:

SELECT * FROM Product
INNER JOIN FiltersType1 USING (product_id)
UNION ALL
SELECT * FROM Products
INNER JOIN FiltersType2 USING (product_id)
UNION ALL
SELECT * FROM Products
INNER JOIN FiltersType3 USING (product_id)
...

Ama bu biçim, hala tüm tablolar için başvurular yazmak gerekir. Bunun başka çaresi yok.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Flohoo

    Flohoo

    12 EYLÜL 2009
  • Matt Harding

    Matt Harding

    23 Mayıs 2006
  • SegaAmerica

    SegaAmerica

    5 Mart 2008