You have a form editor and can add form fields (inputs). Each form field translates to a different type of data:
<textarea>
becomes a TEXT
column.<input type="text">
becomes a VARCHAR(X)
.<input type="range">
becomes a FLOAT
.<select>
could be a comma-separated list (TEXT
), a separate table with each entry (foreign key) or a reference to an existing table (foreign key).An easy way to store the structure of each:
Two solutions to store the data, if someone would fill such a dynamic form:
VARCHAR
, TEXT
, FLOAT
, ...). This leaves a lot of ugly NULL
values, since each form field value only occupies one column. Also, <select>
fields would be problematic if they refer to an existing table.This problem applies to many other things: a template editor, a settings editor, etc.
How do we store the data for such dynamic forms?
I wouldn't consider using an additional non-relational database. I want to keep the data in one place.
I'm asking about a "general" approach with this problem, not specifically for form editors
This thing keeps popping up again and again and everyone I know seems to have a different take on it - but none of them has a really "proper" solution
After the Relational requirement, which is of course the highest order directive, I will take generic approach and proper solution as over-arching directives.
But first, a correction. In order to elevate the data model to Relational, without which the rather straight-forward solution would be exceedingly complex (which is precisely why [a] there are so many incorrect methods, and [b] none of them are proper solutions).
The great bulk of "literature" and textbooks that is promoted and marketed as "relational" is in fact anti-relational. Pre-1970 Record Filing Systems with relational labels, which is evidently all that the many authors and "theoreticians" can understand. The main difference between such pre-relational filing systems and the Relational Model is, the references are logical, not physical.
ID (INTEGER; GUID; UUID; etc)
, in the Relational paradigm, logical rows (not records) are related by Relational Key.The Record IDs serve no purpose in a Relational database. Their purpose is to propagate what the "theoreticians" understand:
At the least, each such Record ID
will be one additional column and one additional index.
Therefore, your requirement elevated to Relational, with one less column and one less index in each table:
All my data models are rendered in IDEF1X, the Standard for modelling Relational databases.
The second thing that needs to be understood is the Intergrity Features of Relational Keys, which you will not have, due to the "theoreticians" being blissfully unaware of it. This is an explanation relevant to the Question, rather than a full tutorial. Assuming that you do want Data Integrity and Relational Integrity (the logical feature provided by the Relational Model (as distinct from Referential Integrity, which is a physical facility provided by SQL). Which we will need, in order to control (provide integrity to) the data structures that are required 'lower' in the data hierarchy, for "Storage".
FieldType
in the FormField.PK
such that it can be migrated to its child tables.FormField.PK
above [1]. If we do, it would lose its integrity and meaning.FieldType::FormField
from Non-Identifying to Identifying.Now the solution is straightforward.
I see two solutions to this [A] or [B]
Definitely [B], with a couple of improvements to bring it up to Standard.
[A] is an unnormalised mess that has no integrity, and it will be a maintenance nightmare. Nulls are very problematic, Nulls in a Foreign Key is suicide.
but [B] will require a lot more complexity when storing and fetching data, since the program has to know the type, use the right table, etc etc.
Not at all.
FieldType
in the parent FormField
Primary Key, so that it will be migratedUserField
UserField
is CONSTRAINED
to FieldNames
that exist in the applicable FormName
Record ID
based) filing systems that the "theoreticians" fraudulently market as "relational"Further, you should be using ACID Transactions (a requirement for SQL Compliance since the first release), not INSERT/UPDATE/DELETE
directly from the program. That would simplify both the app and the program code, as well as eliminate the otherwise thousands of errors. If implemented to OLTP Standard, it minimises locking and contention, and reduces, if not eliminates, deadlocks.
Not really. It may not be simple, it is definitely not complex, but it is straight-forward.
VIEW
(this is a classic use of VIEWS
)
UNION
) for any Subtype (which will return just one for each Basetype, whichever Subtype it is)