Skip to Main Content
  • Questions
  • Question / Answer table structure design

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, James.

Asked: October 16, 2016 - 10:31 am UTC

Last updated: October 18, 2016 - 1:45 am UTC

Version: 12c

Viewed 1000+ times

You Asked

Hi,

We are building a facility that allows our customers to configure questions which there customers in turn can then answer. These questions can be configured in various ways which determines what is / is not a valid answer and importantly (to this question), how and where the data might be stored. Examples of the questions and answers are given below.

Question: What age are you?
Answer type: Number

Question: What nationality are you?
Answer: Varchar2/number (with foreign key to a list of values table)

Question: Tell us about yourself?
Answer type: Clob

Question: Upload a document/photo.
Answer type: Blob.

What table structure would you advise for the storage of the answers? Or what considerations/questions would drive the decision making process. I have considered a few options however the option I am currently learning towards is a single table with a column for each data type (number, Clob, Blob, varchar2) and an additional column with a foreign key constraint to a "lists" table.

If there is a book that deals with this type of design question I'd be interested to know which one.

Thanks in advance,

James

and Chris said...

For some discussion of schemas for surveys, check out:

http://dba.stackexchange.com/q/16002/2264

And this three part series from Vertabelo:

https://www.vertabelo.com/blog/technical-articles/a-database-model-for-an-online-survey-part-1
http://www.vertabelo.com/blog/technical-articles/a-database-model-for-an-online-survey-part-2
http://www.vertabelo.com/blog/technical-articles/a-database-model-for-an-online-survey-part-3

I don't think these address your key question though, which I read as:

"How do I ensure that we store answers in the correct data type?"

If so, your proposal of:

create table answers (
  answer_id       int not null primary key,
  number_answer   number, 
  varchar2_answer varchar2(4000),
  clob_answer     clob,
  blob_answer     blob
);


With a check constraint to ensure only one is set could work. You'll also want to ensure that only the correct data type is not null. Do this by:

- adding a answer_type column stating this
- creating a check constraint inspecting this value and checking the nullness as needed:

( answer_type = 'NUMBER' and number_answer is not null and varchar2_answer is null and ... )  or
( answer_type = 'VARCHAR2' and number_answer is null and varchar2_answer is not null and ... )  or


Personally I prefer a different method. Having a single table per data type (click for pic):

https://blogs.oracle.com/sql/resource/at-survey-answers-schema.png

This is a bit more work to start with. And there's greater overhead (two inserts/answer, more (outer) joins to get the results).

But it avoids you having to deal with nulls. And conditionally selecting the answer column based on the type. For example, instead of:

select case answer_type
    when 'VARCHAR2' then varchar2_answer 
         when 'NUMBER' then to_number(number_answer)
         when 'CLOB' then clob_answer 
         ...
from   answers;


You just union the results together:

select answer 
from   varchar2_answers
union all
select answer 
from   number_answers
union all
select answer
from   ... 


Though you could unpivot the single table for similar results. It also makes it easier if you want to process certain types of answer. For example, to find all the blob/file uploads you just run:

select answer
from   blob_answers;


For your "lists" table, are you referring to a single table to store all lookup values? For example, countries, currencies, etc.?

If so, this is a version of the One True Lookup Table (OTLT). I'm not keen on this because:

- You repeat the data type dilemma above
- It's hard/impossible to add further constraints on the lookup values
- To ensure answers are only from the correct list you need to add type columns
- The optimizer will find it harder to get the best plan when joining a few rows from a huge table (OTLT) vs. a table where these are the only rows you want

The big advantage comes when you add a new list. You can just insert them, instead of creating new tables and FKs. As you're giving this to customers to build their own questions it means you don't need to issue DDL in your application.

It also avoids the "polymorphic assocation" problem with FKs from answers to the lists. With a table/lookup set, the answer FK will point to different tables. You can't do this in a single column:

https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:9532036700346467461

So weigh up the above and decide which downsides you're most willing to accept!


Rating

  (2 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Very helpful

James Blackwell, October 17, 2016 - 1:50 pm UTC

Thanks for the extremely comprehensive answer, it's very much appreciated. The other idea I had considered was a separate table per data type (as per your suggestion) and so that solution is firmly back on the table.

In answer to your question regarding the "lists" table, you are correct in your assumption that this is similar to a OTLT. The reason for taking this approach is that there is a requirement for our customers to easily and quickly create new questions and associated list answers. I do understand the issues you have highlighted and will have a think about possible alternative solutions.

Thanks again!
Chris Saxon
October 17, 2016 - 4:14 pm UTC

If your lists for answers are really choices for the question such as:

- Agree
- Neither agree/disagree
- Disagree

Then I'd stick with a single table for these. But if they're reference data which have context outside the question such as countries I'd lean towards separate tables. Having an app which often creates tables on the fly isn't great though.

You could always have a hybrid method. Create tables for common lookups such as countries, currencies and any business specific items e.g. airports for airlines/travel.

Then allow customers to load their own lists in one table.

A reader, October 17, 2016 - 5:14 pm UTC

When new question post by the user so by default oracle database store a time and date when question post without any user interaction.
I do use date datatype but it can't work so how i can store data and time of the oracle database in the following format like
17-10-2016 22:44:11
Connor McDonald
October 18, 2016 - 1:45 am UTC

There is a difference between what is *stored* and what is *displayed*.

SQL> create table t ( x date default sysdate , y int);

Table created.

SQL>
SQL> insert into t (y) values (0);

1 row created.

SQL> select * from t;

X                  Y
--------- ----------
18-OCT-16          0

--
-- So it LOOKS like it is just the date, but the time IS stored there as well
-- You need to change your settings to SHOW it
--

SQL>
SQL> alter session set nls_date_format = 'dd/mm/yyyy hh24:mi:ss';

Session altered.

SQL> select * from t;

X                            Y
------------------- ----------
18/10/2016 01:44:39          0


More to Explore

CLOB/BLOB/etc

Complete documentation on Securefiles and Large Objects here