Birden çok farklı türde olabilen bir değeri depolamanın uygun yolu


11

Bir Yanıtlar tablosu ve Sorular tablosu var.

Cevaplar tablo bir değeri vardır, ama soru bağlı olarak bu değer, bir olabilir bit, nvarcharya da number(şimdiye kadar). Soru amaçlanan cevap değer türü olması gerektiğine dair bir fikri vardır.

En azından sayıların karşılaştırılması gerekeceğinden, bu Cevap değerlerini bir noktada veya başka bir yerde ayrıştırmak önemlidir .

Biraz daha bağlam için, sorular ve potansiyel cevaplar (genellikle bir metin kutusu türü girişi için izin verilen bir veri türü), bazı kullanıcılar tarafından bir tür ankette sağlanır. Yanıtlar daha sonra diğer belirtilen kullanıcılar tarafından verilir.

Düşündüğüm birkaç seçenek:

A. İstenen türe (soruda takip edilen) bağlı olarak farklı şekilde ayrıştırılan XML veya dize

B. Yanıt tablosuna gönderme yapan (veya referans gösterilen) üç ayrı tablo ve istenen türe göre birleştirilir. Bu durumda, her sorunun sadece bir cevabı olduğundan emin olmak için kısıtlamaları ayarlamanın en iyi yolundan emin değilim, ya da bunun uygulamaya bırakılması gerekir.

C. Yanıt tablosunda, istenen türe göre alınabilen üç ayrı sütun.

Bu yaklaşımların artıları ve eksileri ya da düşünmediğim alternatif yaklaşımlar hakkında biraz bilgi almaktan memnuniyet duyarım.

Yanıtlar:


2

Bu gerçekten ön ucunuzun verilere nasıl eriştiğine bağlıdır.

O / R eşleştiricisi kullanıyorsanız, veritabanı tasarımına değil, sınıflarınızın nesneye yönelik tasarımına odaklanın. Veritabanı daha sonra sınıf tasarımını yansıtır. Kesin db tasarımı, kullandığınız O / R-mapper ve miras eşleme modeline bağlıdır.

Tablolara doğrudan kayıt kümeleri, veri tabloları, veri okuyucuları veya benzerleri üzerinden erişiyorsanız, yapılacak basit bir şey, değişmez bir kültür kullanarak değerleri bir dizeye dönüştürmek ve basit bir metin sütununda saklamaktır. . Ve elbette, değerleri okurken metni özel değer türlerine geri dönüştürmek için aynı kültürü tekrar kullanın.

Alternatif olarak, değer türü başına bir sütun kullanabilirsiniz. Bugün terabayt sürücülerimiz var!

Bir XML sütunu mümkündür, ancak muhtemelen basit metin sütununa kıyasla daha fazla karmaşıklık ekler ve hemen hemen aynı şeyi yapar, yani serileştirme / serileştirme.

Ayrılmış birleştirilmiş tablolar, işleri yapmanın doğru normalleştirilmiş yoludur; ancak, oldukça karmaşıklık da eklerler.

Basit tutun.

Ayrıca bkz . Anket veritabanı tasarımına cevabım - hangi yol daha iyi? .


4

Söylediklerinize dayanarak aşağıdaki genel şemayı kullanacağım:

CREATE TABLE [dbo].[PollQuestion]
(
    [PollQuestionId] INT NOT NULL PRIMARY KEY IDENTITY,
    [QuestionText] NVARCHAR(150) NOT NULL, -- Some reasonable character limit
    [Created] DATETIME2(2) NOT NULL DEFAULT SYSUTCDATETIME(),
    [Archived] DATETIME2(2) NULL,  -- Remove this if you don't need to hide questions
)
CREATE TABLE [dbo].[PollOption]
(
    [PollOptionId] INT NOT NULL PRIMARY KEY IDENTITY,
    [PollQuestionId] INT NOT NULL,  -- Link to the question here because options aren't shared across questions
    [OptionText] NVARCHAR(50) NOT NULL, -- Some reasonable character limit
    [Created] DATETIME2(2) NOT NULL DEFAULT SYSUTCDATETIME(),
    [Archived] DATETIME2(2) NULL  -- Remove this if you don't need to hide options

    CONSTRAINT [FK_PollOption_PollQuestionId_to_PollQuestion_PollQuestionId] FOREIGN KEY ([PollQuestionId]) REFERENCES [dbo].[PollQuestion]([PollQuestionId])
)
CREATE TABLE [dbo].[PollResponse]
(
    [PollResponseId] INT NOT NULL PRIMARY KEY IDENTITY,
    [PollOptionId] INT NOT NULL,
    [UserId] INT NOT NULL,
    [Created] DATETIME2(2) NOT NULL DEFAULT SYSUTCDATETIME(),
    [Archived] DATETIME2(2) NULL,  -- Remove this if you don't need to hide answers

    CONSTRAINT [FK_PollResponse_PollOptionId_to_PollOption_PollOptionId] FOREIGN KEY ([PollOptionId]) REFERENCES [dbo].[PollOption]([PollOptionId]),
    CONSTRAINT [FK_PollResponse_UserId_to_User_UserId] FOREIGN KEY ([UserId]) REFERENCES [dbo].[User]([UserId])
)

Cevabın bir sayı, tarih, kelime vb. Olup olmadığını gerçekten umursamazsınız çünkü veriler doğrudan üzerinde çalışmanız gereken bir şey değil, bir soruya cevaptır. Ayrıca verilerin sadece soru bağlamında bir anlamı vardır. Bu nedenle bir nvarchar, verileri depolamak için en çok yönlü insan tarafından okunabilir mekanizmadır.

Soru ve potansiyel cevaplar ilk kullanıcıdan toplanacak ve PollQuestion ve PollOption tablolarına eklenecektir. Soruları cevaplayan ikinci kullanıcı cevap listesinden seçim yapacaktır (true / false = 2 listesi). Ayrıca PollQuestion tablosunu, oluşturdukları soruları izlemek için uygunsa yaratıcının kullanıcı kimliğini içerecek şekilde genişletebilirsiniz.

Kullanıcı arayüzünüzde kullanıcının seçtiği yanıt PollOptionId değerine bağlanabilir. PollQuestionId ile birlikte cevabın soru için hızlı bir şekilde geçerli olduğunu doğrulayabilirsiniz. Geçerliyse yanıtları PollResponse tablosuna girilir.

Kullanım durumunuzun ayrıntılarına bağlı olarak birkaç potansiyel sorun vardır. İlk kullanıcı matematik sorusu kullanmak istiyorsa ve birden fazla olası cevap sunmak istemiyorsanız. Başka bir durum, ilk kullanıcının sağladığı seçenekler ikinci kullanıcının seçebileceği tek seçenek değilse. Bu ek kullanım durumlarını desteklemek için bu şemayı aşağıdaki gibi yeniden çalıştırabilirsiniz.

CREATE TABLE [dbo].[PollResponse]
(
    [PollResponseId] INT NOT NULL PRIMARY KEY IDENTITY,
    [PollOptionId] INT NULL,
    [PollQuestionId] INT NOT NULL,
    [UserId] INT NOT NULL,
    [AlternateResponse] NVARCHAR(50) NULL, -- Some reasonable character limit
    [Created] DATETIME2(2) NOT NULL DEFAULT SYSUTCDATETIME(),
    [Archived] DATETIME2(2) NULL,  -- Remove this if you don't need to hide answers

    CONSTRAINT [FK_PollResponse_PollOptionId_to_PollOption_PollOptionId] FOREIGN KEY ([PollOptionId]) REFERENCES [dbo].[PollOption]([PollOptionId]),
    CONSTRAINT [FK_PollResponse_UserId_to_User_UserId] FOREIGN KEY ([UserId]) REFERENCES [dbo].[User]([UserId])
)

Ayrıca muhtemelen bir seçeneğin sağlandığından veya alternatif bir yanıt olduğundan emin olmak için bir kontrol kısıtlaması eklerim, ancak ihtiyaçlarınıza bağlı olarak (seçenek ve alternatif yanıt) değil.

Düzenleme: AlternateResponse için veri türünü iletme.

Mükemmel bir dünyada, jenerikler kavramını AlternateReponse için çeşitli veri türlerini ele almak için kullanabiliriz. Ne yazık ki mükemmel bir dünyada yaşamıyoruz. Düşünebileceğim en iyi uzlaşma, AlternateResponse veri tipinin PollQuestion tablosunda ne olması gerektiğini belirtmek ve AlternateReponse'u veritabanında nvarchar olarak depolamaktır. Güncelleştirilmiş soru şeması ve yeni veri türü tablosu aşağıdadır:

CREATE TABLE [dbo].[PollQuestion]
(
    [PollQuestionId] INT NOT NULL PRIMARY KEY IDENTITY,
    [QuestionText] NVARCHAR(150) NOT NULL, -- Some reasonable character limit
    [QuestionDataTypeId] INT NOT NULL,
    [Created] DATETIME2(2) NOT NULL DEFAULT SYSUTCDATETIME(),
    [Archived] DATETIME2(2) NULL,  -- Remove this if you don't need to hide questions
    -- Insert FK here for QuestionDataTypeId
)
CREATE TABLE [dbo].[QuestionDataType]
(
    [QuestionDataTypeId] INT NOT NULL PRIMARY KEY IDENTITY,
    [Description] NVARCHAR(50) NOT NULL, -- Some reasonable character limit
)

Bu QuestionDataType tablosundan seçim yaparak soru yaratıcıları için mevcut tüm veri türlerini listeleyebilirsiniz. Kullanıcı arayüzünüz, alternatif yanıt alanı için uygun biçimi seçmek üzere QuestionDataTypeId dosyasına başvurabilir. TSQL veri türleriyle sınırlı değilsiniz, bu nedenle "Telefon Numarası" bir veri türü olabilir ve kullanıcı arayüzünde uygun biçimlendirme / maskeleme elde edersiniz. Ayrıca gerekirse, alternatif cevaplar üzerinde her türlü işlem (seçme, doğrulama, vb.) Yapmak için verilerinizi basit bir vaka bildirimi yoluyla uygun türlere aktarabilirsiniz.


0

Yine de, EAV hakkında bu kadar kötü olan neye bakalım ? Aaron Bertrand tarafından EAV modeli hakkında bazı bilgiler için.

XML veya birden çok tabloya sahip olmak yerine her veri türü için bir sütuna sahip olmak büyük olasılıkla daha iyi olacaktır.

Kısıtlama kısmı kolaydır:

CHECK 
(
    CASE WHEN col1 IS NOT NULL THEN 1 ELSE 0 END + 
    CASE WHEN col2 IS NOT NULL THEN 1 ELSE 0 END + 
    CASE WHEN col3 IS NOT NULL THEN 1 ELSE 0 END = 1
)

Bu sitede etiketli birçok soru ve cevap var ve muhtemelen askerin bu terimi kendi sorularında kullanmayı bilmediği başkaları.

Muhtemelen tüm artıları ve eksileri kapsayacağı için bunları okumanızı tavsiye ederim (bu, gerçekte değişmediklerinde insanların onları yeniden hash etmelerini önler).

Yanıt Aaron Bertrand tarafından bırakılan soru yorumlarına dayanmaktadır


-1

Sorunun çok fazla düşünülmüş olduğunu düşünüyorum ya da bazı cevapların diğerlerinden daha neden uyum sağlayabileceğine dair bazı ek kısıtlamalar var. Şu anda Cevabın DB tarafından herhangi bir şekilde işlenmesi gerektiğine dair bir kanıt yok gibi görünüyor, sadece bir kayıt alanı olarak.

Ben bir NVARCHAR (MAX) ile gitmek istiyorum ve sonra sadece ön uç içeriği depolamak / almak ile başa çıkmak izin. Yanıt doğruysa ön ucun saklayabileceği bir IS_CORRECT bit alanı olabilir.

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.