Firstly I think this question can be related to any language, but I specified what I was using.
Excuse me if I start to bore also, but I am trying to find out the best way to build a dynamic survey management system.
My client basically has said to me that the data has to be stored in MS SQL as his client has only got MS SQL connector for SAS, which is going to do reporting.
My logic so far is this:
1st. Setup the survey itself, i.e. ask for title, quick overview, etc, etc.
2nd. Define your questions.
3rd. Publish survey.
Now what I have done so far is that when they "publish survey", I have created a dedicated database table for this survey which will house the responses.
From the admin side of this, they will not be able to modify the questions, maybe the question title but that is about it. They cant add/remove questions.
Question is, is creating individual database tables a good thing? My only worry really is that say the admin creates like 30 questions, I will have 30 columns in that dedicated table. To go with that, this way might be easy for the SAS system to pull in data for reporting. The administrator will not see the survey responses in the admin panel btw.
I have done something similar for a language grading exam. I opted for a more flexible approach with the following tables
+------+ +-------------+ +-------------+ +-------------+ +----------+
| Exam | | Question | | Choice | | Answer | | User |
+------+ +-------------+ +-------------+ +-------------+ +----------+
| id | | id | | id | | id | | id |
| name | | questionNb | | choice | | user_id | | name |
+------+ | question | | question_id | | exam_id | | email |
| exam_id | | isAnswer | | question_id | | password |
+-------------+ +-------------+ | choice_id | +----------+
| isGood |
+-------------+
This model allowed me to easilly have a 15 questions exam, a 30 questions exam and a 50 questions exam. To adapt this model for survey, you might just have to remove the isAnswer and isGood part and you should be good and replace users data with anonymous general data like age, income, sex.
Creating a column for each question is totally wrong, altering the database at runtime for business oriented purpose is a "never ever do".
Read something about "relational databases" things should look like this:
table_surveys
id
survey_name
table_questions
id
fk_survey (foreign key to table_surveys)
question_text
(question value? maybe)
table_questions_options
id
question_id(foreign key to table_questions)
option_value (this can be true/false for a test or a numeric value for a survey)
option_label
table_users
id
username
pass
name
table_answers
id
options_fk (foreign key to table_question_options)
users_fk (foreign key to table_users)
This way everything is linked together (No reusing of options,or questions or stuff into different surveys)
According to the comments in the documentation, MS SQL Support in PHP is iffy at best. Is PHP the only language you are allowed to use for the project? If not, you might want to consider using C#, VB.Net or something more compatible with SQL Server. Otherwise, you could initially store the data in MySQL, and export it to MS SQL Server when you needed to do analysis.
Dont know, if I really understand your question. But I once built such a survey system. And it came out pretty quick and easy with about the following tables (if I remember right):
USER, SURVEYS, QUESTIONS, ANSWERS, [some mapping tables]
The SAS will fetch the data from virtual any table. If everything in one or two tables, it will even be easier.
With all due respect to Kibbee, PHP/MSSQL support is actually VERY good. We do it quite often, and the performance bests PHP/MySQL and matches compiled C#/MSSQL (in our very limited and unscientific testing). This is assuming you're running PHP on a Win machine. Running PHP with a TLS connector to a separate MSSQL box is another ball of wax and can be a pain to configure.
Anyway, we had a similar scenario and went with one table to manage forms (Forms w/ FormID as the primary), another to manage fields/questions (Fields w/FieldID, FieldType such as Y/N, text, select, etc.), and another to "assign" a field to a form (FormFields w/ FormFieldID, FormID, FieldID, parameters in an array for select items, etc.). Then yet another set of tables to deal with the answering of the questions.
I agree with the rest of the group. Make sure to normalize and don't create a separate column for each question. It'll be more work initially, but you'll appreciate it when you simply have to add a few rows to a table instead of re-writing your queries and re-designing your tables.
Related
I've got the following poll form for my users but I am not sure how I should structure the DB around it.
The user will get 20-30 poll questions like the following:
What is your favorite color?
Blue
Green
Yellow
Red
Other
Will be able to choose one of the above answers and must also provide around 100 words explaining why he chose that answer.
I've currently got two tables. One that holds the poll questions and one that holds the poll options. What I am not sure about is how should I hold the user answers.
The thing is because the poll is so big, the user can do it partially, come back at a later time, alter his answers and keep going until he is 100% done which is then that I'll be able to view the whole result in my panel. So he can basically save his progress and alter it at anytime. On top of that I would like to "remove" the whole poll for a specific user and be able to redo it all over again but at the same time keep a history of his previous answers.
So I am not sure if a table like this would be the best option for my needs:
id
user_id
poll_questiond
poll_answer
poll_text
last_update
status
Seems like something like this will create a huge mess. Is there a better way to do this?
I would create 3 tables:
table_polls
+----+---------------------+--------+
| id | description | status |
+----+---------------------+--------+
| 1 | Example description | 1 |
+----+---------------------+--------+
table_poll_options
+----+---------+-------------+
| id | poll_id | description |
+----+---------+-------------+
| 1 | 1 | Question 1 |
| 2 | 1 | Question 2 |
+----+---------+-------------+
table_poll_answers
+----+-----------+---------+----------------+---------------------+
| id | option_id | user_id | description | created_at |
+----+-----------+---------+----------------+---------------------+
| 1 | 1 | 1 | A valid reason | 1970-01-01 00:00:00 |
| 1 | 2 | 2 | Another reason | 1970-01-01 00:00:00 |
+----+-----------+---------+----------------+---------------------+
To recapitulate the above:
A poll has many questions.
A poll question has many answers
A poll answer has one user.
This way you have everything split up with pivot tables and you no longer need to create messy rows in your poll table.
You can expand on the tables of course, if you need extra information for dates etc.
I think you will find it easier if you define your problem domain in semi-structured language. You may decide to delegate some of the logic to the application layer, rather than embedding in the database schema - for instance, saving partially-completed polls might be easier within the application layer.
You might start with something like this, capturing the major entities in your domain, and their relationships, but not their attributes.
The system consists of many polls.
One poll has many questions. A question belongs to 1
poll.
A question can be of type multiple choice (select one) or
multiple choice (select n) or free text
A question may be mandatory or optional
A multiple choice question has 1..n answer options
A question has a sequential relationship to other questions
(e.g. the free text question must follow the favourite colour
question)
The system consists of many users
A user answers many polls
When the user answers a poll, they answer 0..n questions
When the user answers a poll, the answer is only valid if the
user completes all mandatory questions
This suggests that you have two polymorphic entities - question (which can be free text or multiple choice), and answer (as the answer is related to the question, it is also free text or multiple choice).
You have to decide how to model this in your schema - Stack Overflow has many questions on this topic - but I'll pick the simplest.
Poll
-----
Poll_id
Question
------
Question_id
Poll_id
Sequence
Is_mandatory
Description
Question_option
-------------
Question_option_id
Question_id
Option_id
Sequence
Description
User
-----
User_id
Poll_session
------
Poll_session_id
User_id
Poll_id
Date
Status
Poll_session_answer
-----
Poll_session_id
Quesion_id
Free_text_answer
Question_option_id_answer
I am planning an application and wish to maintain a relational database and other non-relational, respectively, MySQL and MongoDB.
One fact is that in relational database are maintained users, and non-relational, is maintained by this user generated content, where involves geo queries.
The problem now is how to *create a link between user and your item*s using both databases and maintaining the performance or am adopting the wrong approach?
My idea is to create a product table with a foreign key to the user in mysql and objectId of the product in the database non-relational.
Example MySQL Table:
table: products_relationship
| account_id | product_objectid |
| ---------- | -------------------------------- |
| 1 | 0b694fc34c9663883a5d4b32371f8333 |
| 1 | 0b694fc34c9663883a5d4b32371f9837 |
| 2 | 0b694fc34c9663883a5d4b32371f9bfc |
| 5 | 0b694fc34c9663883a5d4b32371fcb5f |
| 1 | 0b694fc34c9663883a5d4b32371fd809 |
So, the user at account_id = 1 has a first name, email and other data. And owns 3 products.
Should I adopt a new methodology? I'll be gaining performance with that? Am I losing the functionality of NoSQL with that?
I work on a system at work that does just this. We have relational databases and NoSQL databases and we use a product called Mule (http://www.mulesoft.org/) to integrate them.
I would strongly recommend picking either MySQL or Mongo and doing all your PHP work against one of those databases. You can move data in near real time from MySQL->Mongo or from Mongo->MySQL. Mule is good at that.
You aren't going to be able to efficiently do "joins" across systems.
Mule will also help you do transformations on the data when you move it. As an example, you can take normalized data in MySQL and denormalize it for storing in Mongo.
I realized that I adopted a complex architecture while I did not need much complexity. There is no reason for me to want my users are in relational databases. Yes they can stay within the MongoDB without any problem, and the products within each user. This is a relationship that I create.
If I want, I can make the connection using _objectId
I am developing a website which will collect and store information for users.
I need to create a table specific to each individual user on registration to store the information they are searching for using the website. The table created will be named after the newly registered user's username.
Then when the user is logged in and runs the search, the data collected will be stored in a database using a MySQL insert query where the table name is a variable containing the logged-in user's username which will also be the table name.
I am an amateur developer and have searched everywhere to try and find a solution but I cannot seem to find anything evenly remotely similar to my problem.
Thank you in advance for any help!
Creating tables on the fly is more trouble than it's worth and very much swimming against the tide with any SQL database.
The reason you haven't found any docs about the approach you mention is because this problem is generally (almost without exception) solved best by having all the data in one or more tables, and including a column to specify which entity (user) the row is associated with. In your case, this might be an email address, or a username, or just a sequential number.
E.g.
| user_id | email | first_name | last_name | fave_color |
- - - - - -
| 1 | "a#b.c" | "anton" | "aardvark" | "red" |
| 2 | "b#c.d" | "miles" | "o'brien" | "infrared" |
| ... | | | | |
First take name from user like:
$fullname="$fname"."_"."$lname";
Then, write a query like this to create a table of that name
$sql="CREATE TABLE $fullname(ALL THE COLLUMNS YOU WANT TO CREATE)";
$result1=mysql_query($sql, $db_link);
this query is from my project. Works fine in wampserver.
Apologies if this has been covered thoroughly in the past - I've seen some related posts but haven't found anything that satisfies me with regards to this specific scenario.
I've been recently looking over a relatively simple game with around 10k players. In the game you can catch and breed pets that have certain attributes (i.e. wings, horns, manes). There's currently a table in the database that looks something like this:
-------------------------------------------------------------------------------
| pet_id | wings1 | wings1_hex | wings2 | wings2_hex | horns1 | horns1_hex | ...
-------------------------------------------------------------------------------
| 1 | 1 | ffffff | NULL | NULL | 2 | 000000 | ...
| 2 | NULL | NULL | NULL | NULL | NULL | NULL | ...
| 3 | 2 | ff0000 | 1 | ffffff | 3 | 00ff00 | ...
| 4 | NULL | NULL | NULL | NULL | 1 | 0000ff | ...
etc...
The table goes on like that and currently has 100+ columns, but in general a single pet will only have around 1-8 of these attributes. A new attribute is added every 1-2 months which requires table columns to be added. The table is rarely updated and read frequently.
I've been proposing that we move to a more vertical design scheme for better flexibility as we want to start adding larger volumes of attributes in the future, i.e.:
----------------------------------------------------------------
| pet_id | attribute_id | attribute_color | attribute_position |
----------------------------------------------------------------
| 1 | 1 | ffffff | 1 |
| 1 | 3 | 000000 | 2 |
| 3 | 2 | ffffff | 1 |
| 3 | 1 | ff0000 | 2 |
| 3 | 3 | 00ff00 | 3 |
| 4 | 3 | 0000ff | 1 |
etc...
The old developer has raised concerns that this will create performance issues as users very frequently search for pets with specific attributes (i.e. must have these attributes, must have at least one in this colour or position, must have > 30 attributes). Currently the search is quite fast as there are no JOINS required, but introducing a vertical table would presumably mean an additional join for every attribute searched and would also triple the number of rows or so.
The first part of my question is if anyone has any recommendations with regards to this? I'm not particularly experienced with database design or optimisation.
I've run tests for a variety of cases but they've been largely inconclusive - the times vary quite significantly for all of the queries that I ran (i.e. between half a second and 20+ seconds), so I suppose the second part of my question is whether there's a more reliable way of profiling query times than using microtime(true) in PHP.
Thanks.
This is called the Entity-Attribute-Value-Model, and relational database systems are really not suited for it at all.
To quote someone who deems it one of the five errors not to make:
So what are the benefits that are touted for EAV? Well, there are none. Since EAV tables will contain any kind of data, we have to PIVOT the data to a tabular representation, with appropriate columns, in order to make it useful. In many cases, there is middleware or client-side software that does this behind the scenes, thereby providing the illusion to the user that they are dealing with well-designed data.
EAV models have a host of problems.
Firstly, the massive amount of data is, in itself, essentially unmanageable.
Secondly, there is no possible way to define the necessary constraints -- any potential check constraints will have to include extensive hard-coding for appropriate attribute names. Since a single column holds all possible values, the datatype is usually VARCHAR(n).
Thirdly, don't even think about having any useful foreign keys.
Finally, there is the complexity and awkwardness of queries. Some folks consider it a benefit to be able to jam a variety of data into a single table when necessary -- they call it "scalable". In reality, since EAV mixes up data with metadata, it is lot more difficult to manipulate data even for simple requirements.
The solution to the EAV nightmare is simple: Analyze and research the users' needs and identify the data requirements up-front. A relational database maintains the integrity and consistency of data. It is virtually impossible to make a case for designing such a database without well-defined requirements. Period.
The table goes on like that and currently has 100+ columns, but in general a single pet will only have around 1-8 of these attributes.
That looks like a case for normalization: Break the table into multiple, for example one for horns, one for wings, all connected by foreign key to the main entity table. But do make sure that every attribute still maps to one or more columns, so that you can define constraints, data types, indexes, and so on.
Do the join. The database was specifically designed to support joins for your use case. If there is any doubt, then benchmark.
EDIT: A better way to profile the queries is to run the query directly in the MySQL interpretter on the CLI. It will give you the exact time that it took to run the query. The PHP microtime() function will also introduce other latencies (Apache, PHP, server resource allocation, network if connection to a remote MySQL instance, etc).
What you are proposing is called 'normalization'. This is exactly what relational databases were made for - if you take care of your indexes, the joins will run almost as fast as if the data were in one table.
Actually, they might even go faster: instead of loading 1 table row with 100 columns, you can just load the columns you need. If a pet only has 8 attributes, you only load those 8.
This question is a very subjective. If you have the resources to update the middleware to reflect the column that has been added then, by all means, go with horizontal there is nothing safer and easier to learn than a fixed structure. One thing to remember, anytime you update a tables structure you have to update each one of its dependencies unless there is some catch-all like *, which I suggest you stay aware from unless you are just dumping data to a screen and order of columns is irrelevant.
With that said, Verticle is the way to go if you don't have all of your requirements in place or don't have the desire to update code in n number of areas. Most of the time you just need storage containers to store data. I would segregate things like numbers, dates, binary, and text in separate columns to preserve some data integrity, but there is nothing wrong with verticle storage, as long as you know how to formulate and structure queries to bring back the data in the appropriate format.
FYI, Wordpress uses verticle data storage for majority of the dynamic content it has to store for the millions of uses it has.
First thing from Database point of view is that your data should be grow vertically not in horizontal way. So, adding a new column is not a good design at all. Second thing, this is very common scenario in DB design. And the way to solve this you have to create three tables. 1st is of Pets, 2nd is of Attributes and 3rd is mapping table between theres two. Here is the example:
Table 1 (Pet)
Pet_ID | Pet_Name
1 | Dog
2 | Cat
Table 2 (Attribute)
Attribute_ID | Attribute_Name
1 | Wings
2 | Eyes
Table 3 (Pet_Attribute)
Pet_ID | Attribute_ID | Attribute_Value
1 | 1 | 0
1 | 2 | 2
About Performance:
Pet_ID and Attribute_ID are the primary keys which are indexed (http://developer.mimer.com/documentation/html_92/Mimer_SQL_Engine_DocSet/Basic_concepts4.html), so the search is very fast. And this is the right way to sovle the problem. Hope, now it will be clear to you.
Probably a silly question, but I'm new to all this.
I am creating a basic quiz program in PHP, I want to have a MySQL database cantoning a table for each quiz, each table needs to have the same headings (Question, 1st 2nd 3rd and 4th multiple choice answer, and correct answer). Each table will then contain how ever many questions are in that particular quiz.
I am using PHPMyAdmin running on WAMP Server.
I am not sure if that's the most efficient way to do it, but I have no other ideas, I'm very open to suggestions :)
My question is: How can I automatically create more tables within that database with these same headings, so the user can easily create new quizzes.
I am then going to go on to link this with my PHP code, and make a nice user interface for the users to create and do quizzes.
I would be so grateful to any answers, and welcome suggestions. Sorry I made this question quite long. Thanks again in advance :) xx
A far more flexible design would be to have 3 tables;
quizzes: overall info about each quiz
id: int - unique ID of a quiz
name: text - descriptive text
questions:
id - int - unique id of question
quiz_id - int - foreign key pointing at quizzes table
name: text - text of a question
choices:
id - int - unique id of a choice/answer for a question
question_id - int - foreign key pointing at questions table
name: text - text of this particular choice
Which this, you're free to have as many quizzes you want, each having as many questions as it wants, and each question has as many (or few) possible answers.
The SQL way is more like creating, say four tables:
Quizzes(id,name)
Questions(id,quizz_id,title,answer1,answer2,...,solution)
Users(id,name,...)
Quizz_results(id,user_id,quizz_id,result)
For a given quizz, a php script is responsible for pulling the questions for that quizz and another script where you will post users answers will be responsible for calculating the result and feeding the Quizz_result table.
Multiple tables approach suggested by others is "more proper" from the "software design" standpoint, however, it requires you to write far more pretty advanced code.
I'd suggest a simpler structure to get you started, which is much easier to program. Have one single table for all quizzes and have a column "quiz-name" in the each row, like this:
Quiz name | Question | 1st | 2nd | 3rd | 4th | correct
--------------------------------------------------------------------
PHP does it work | yes | no | maybe | no idea | 1
PHP looks good | yes | no | maybe | no idea | 2
mysql does it work | yes | no | maybe | no idea | 2
mysql looks good | yes | no | maybe | no idea | 3
As you get more proficient, you can revisit your design and use on of the suggested multitable structures.