Cara yang tepat untuk menyimpan nilai yang bisa berupa berbagai jenis

11

Saya memiliki tabel Jawaban dan tabel Pertanyaan .

Jawaban Tabel memiliki nilai, tetapi tergantung pada pertanyaan, nilai ini bisa menjadi bit, nvarcharatau number(sejauh ini). The Question memiliki gagasan tentang apa yang dimaksudkan jenis nilai jawabannya harus.

Penting untuk menguraikan nilai - nilai Jawaban ini pada satu titik atau yang lain karena angka, setidaknya, perlu dibandingkan.

Untuk konteks yang lebih sedikit, pertanyaan dan jawaban potensial (biasanya tipe data yang diizinkan untuk input tipe kotak teks) disediakan oleh beberapa pengguna dalam semacam survei. Jawabannya kemudian diberikan oleh pengguna tertentu lainnya.

Beberapa pilihan yang saya pertimbangkan adalah:

A. XML atau string yang diuraikan berbeda tergantung pada jenis yang dimaksud (yang disimpan dalam pertanyaan)

B. Tiga tabel terpisah yang merujuk (atau direferensikan oleh) tabel Jawaban dan digabungkan berdasarkan tipe yang dimaksud. Dalam hal ini, saya tidak yakin cara terbaik untuk mengatur batasan untuk memastikan setiap pertanyaan hanya memiliki satu jawaban, atau jika itu harus diserahkan kepada aplikasi.

C. Tiga kolom terpisah pada tabel Jawab yang dapat diambil berdasarkan jenis yang dimaksud.

Saya akan senang hanya mendapat masukan tentang pro dan kontra dari pendekatan ini, atau pendekatan alternatif yang tidak saya pertimbangkan.

David Garrison
sumber

Jawaban:

2

Itu sangat tergantung bagaimana front-end Anda mengakses data.

Jika Anda menggunakan O / R-mapper, fokuslah pada desain berorientasi objek dari kelas Anda, bukan pada desain database. Basis data kemudian hanya mencerminkan desain kelas. Desain db yang tepat tergantung pada O / R-mapper dan model pemetaan pewarisan yang Anda gunakan.

Jika Anda mengakses tabel secara langsung melalui set rekaman, data-tabel, data-pembaca atau sejenisnya, hal yang sederhana untuk dilakukan, adalah mengubah nilai menjadi string dengan menggunakan budaya invarian dan menyimpannya dalam kolom teks sederhana . Dan, tentu saja, gunakan budaya yang sama lagi untuk mengubah teks kembali ke tipe nilai khusus saat membaca nilai.

Atau Anda dapat menggunakan satu kolom per jenis nilai. Kami memiliki drive terabyte hari ini!

Kolom XML dimungkinkan, tetapi mungkin menambah kerumitan dibandingkan dengan kolom teks sederhana dan melakukan hal yang hampir sama, yaitu serialisasi / deserialisasi.

Tabel bergabung yang terpisah adalah cara normal yang benar untuk melakukan sesuatu; Namun, mereka menambahkan beberapa kompleksitas juga.

Tetap sederhana.

Lihat juga jawaban saya untuk desain basis data Kuesioner - jalan mana yang lebih baik? .

Olivier Jacot-Descombes
sumber
4

Berdasarkan apa yang Anda katakan saya akan menggunakan skema umum berikut:

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])
)

Anda tidak benar-benar peduli jika jawabannya adalah angka, tanggal, kata, dll. Karena data adalah jawaban untuk pertanyaan, bukan sesuatu yang perlu Anda operasikan secara langsung. Selanjutnya data hanya memiliki makna dalam konteks pertanyaan. Dengan demikian nvarchar adalah mekanisme yang dapat dibaca manusia yang paling serbaguna untuk menyimpan data.

Pertanyaan dan jawaban potensial akan dikumpulkan dari pengguna pertama dan dimasukkan ke dalam tabel PollQuestion dan PollOption. Pengguna kedua yang menjawab pertanyaan akan memilih dari daftar jawaban (true / false = daftar 2). Anda juga dapat memperluas tabel PollQuestion untuk memasukkan id pengguna pembuat jika sesuai untuk melacak pertanyaan yang mereka buat.

Di UI Anda, jawaban yang dipilih pengguna dapat dikaitkan dengan nilai PollOptionId. Bersama dengan PollQuestionId Anda dapat memverifikasi bahwa jawabannya valid untuk pertanyaan dengan cepat. Respons mereka jika valid akan dimasukkan dalam tabel PollResponse.

Ada beberapa potensi masalah tergantung pada detail use case Anda. Jika pengguna pertama ingin menggunakan pertanyaan matematika, dan Anda tidak ingin menawarkan beberapa kemungkinan jawaban. Situasi lain adalah jika opsi yang disediakan pengguna awal bukan satu-satunya pilihan yang bisa dipilih pengguna kedua. Anda bisa mengerjakan ulang skema ini sebagai berikut untuk mendukung kasus penggunaan tambahan ini.

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])
)

Saya mungkin juga akan menambahkan batasan pemeriksaan untuk memastikan bahwa opsi disediakan atau respons alternatif, tetapi tidak keduanya (opsi dan respons alternatif), tergantung pada kebutuhan Anda.

Edit: Mengkomunikasikan tipe data untuk AlternateResponse.

Di dunia yang sempurna kita bisa menggunakan konsep generik untuk menangani berbagai tipe data untuk AlternateReponse. Sayangnya kita tidak hidup di dunia yang sempurna. Kompromi terbaik yang dapat saya pikirkan adalah untuk menentukan apa yang seharusnya datatype AlternateResponse dalam tabel PollQuestion, dan menyimpan AlternateReponse dalam database sebagai nvarchar. Di bawah ini adalah skema pertanyaan yang diperbarui, dan tabel tipe data baru:

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
)

Anda bisa mendaftar semua tipe data yang tersedia untuk pembuat pertanyaan dengan memilih dari tabel QuestionDataType ini. UI Anda dapat mereferensikan QuestionDataTypeId untuk memilih format yang tepat untuk bidang respons alternatif. Anda tidak terbatas pada tipe data TSQL, jadi "Nomor Telepon" bisa menjadi tipe data dan Anda akan mendapatkan pemformatan / masking yang sesuai pada UI. Jika diperlukan, Anda juga dapat mengirimkan data ke jenis yang sesuai melalui pernyataan kasus sederhana untuk melakukan segala jenis pemrosesan (pilih, validasi, dll.) Pada jawaban alternatif.

Erik
sumber
0

Lihatlah Apa yang begitu buruk tentang EAV? oleh Aaron Bertrand untuk beberapa informasi tentang model EAV.

Mungkin akan lebih baik dalam beberapa cara untuk memiliki kolom untuk setiap tipe data daripada memiliki XML atau beberapa tabel.

Bagian kendala mudah:

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
)

Ada banyak pertanyaan dan jawaban yang ada di situs ini yang ditandai , dan mungkin yang lain di mana penanya tidak tahu untuk menggunakan istilah itu dalam pertanyaan mereka.

Saya sangat merekomendasikan membaca semua itu, karena mereka mungkin akan mencakup semua pro dan kontra (ini mencegah orang dari hashing mereka di sini, ketika pada kenyataannya mereka tidak berubah).

Jawab berdasarkan komentar pertanyaan yang ditinggalkan oleh Aaron Bertrand


sumber
-1

Saya pikir masalahnya diberikan terlalu banyak pemikiran atau ada beberapa kendala tambahan mengapa jawaban tertentu mungkin lebih dapat diterima daripada yang lain. Saat ini tampaknya tidak ada bukti bahwa Jawaban harus diproses dengan cara apa pun oleh DB tetapi hanya sebagai bidang log.

Saya akan menggunakan NVARCHAR (MAX) dan kemudian membiarkan frontend berurusan dengan penyimpanan / pengambilan konten. Mungkin bidang bit IS_CORRECT tempat frontend dapat menyimpan jika Jawabannya benar.

HansLindgren
sumber