Storing associative array into database - php

I have 3 tables:
1- questions
2- answers
3- user_answers
questions
_________________
| id | question |
|____|__________|
| 1 | 1+1 |
|____|__________|
answers
_________________
| id | answer |
|____|__________|
| 1 | 1 |
|____|__________|
| 2 | 3 |
|____|__________|
| 3 | 2 |
|____|__________|
user_answers
______________________________________________
| id | answer_id | question_id | user_id |
|____|_____________|______________|___________|
| 1 | 1 | 1 | 1 |
|____|_____________|______________|___________|
| 2 | 3 | 2 | 1 |
|____|_____________|______________|___________|
| 3 | 2 | 3 | 1 |
|____|_____________|______________|___________|
So as you see there is many to many relation within user_answers table.
Instead of saving each question with its answer in a row, I want to save all questions and answers as an array. So there will be 1 row for each user for performance.
I searched about that and found serialize() function and that the datatype for that column should be Blob.
So the new table would be like this:
user_answers
______________________________
| id | array | user_id |
|______|_________|___________|
| 1 | Blob | 1 |
|______|_________|___________|
The array could be like that:
$array = array(
1 => 1,
2 => 3,
3 => 2
);
There could be like 20s or more questions.
Is that's the best way for doing this? or saving each question in a row? or using another datatype for the array column?

1 row for each user for performance
That may backfire.
If you pack a bunch of stuff together via serialization, JSON, etc, you need to avoid looking into the stuff. That is, the only practical and efficient thing to do is fetch the entire string into your application and break it apart there.
If you might need to, say, fetch "what every user gave as an answer just for question 3, then the question number needs to be its own column.

Related

MYSQL UPDATE from SELECT INNER JOIN statement

Hello :) I am fairly new to using INNER JOIN and still trying to comprehend it's logic which I think I am sort of beginning to understand. After being across a few different articles on the topic I have generated a query for finding duplicates in my table of phone numbers.
My table structure is as such:
+---------+-------+
| PhoneID | Phone |
+---------+-------+
Very simple. I created this query:
SELECT A.PhoneID, B.PhoneID FROM T_Phone A
INNER JOIN T_Phone B
ON A.Phone = B.Phone AND A.PhoneID < B.PhoneID
Which returns the ID of a phone that matches another one. I don't know how to word that properly so here is an example output:
+---------+---------+
| PhoneID | PhoneID |
+---------+---------+
| 17919 | 17969 |
| 17919 | 22206 |
| 17919 | 23837 |
| 17920 | 17970 |
| 17920 | 22203 |
| 17920 | 23834 |
| 17921 | 17971 |
| 17921 | 22225 |
| 17921 | 22465 |
| 17921 | 24011 |
| 17921 | 24047 |
| 17922 | 17972 |
| 17922 | 22198 |
| 17922 | 23879 |
| 17923 | 17973 |
| 17923 | 22199 |
| 17923 | 23880 |
+---------+---------+
You can note that on the left there is repeating IDs, the phone number that matches will be on the right (These are just the IDs of said numbers). what I am trying to accomplish, is to actually change a join table relative to the ID on the right. The join table structure is as such:
+----------+-----------+
| T_JoinID | T_PhoneID |
+----------+-----------+
Where T_JoinID is a larger object with a collection of those T_PhoneIDs, hence the join table. What I want to do is take a row from the original match query, and find the right side PhoneID in the join table, then update that item in the Join to be equal to the left side PhoneID. Repeating this for each row.
It's sort of a way to save space and get rid of matching numbers, I can just point the matching ones to the original and use that as a reference when I need to retrieve it.
After that I need to actually delete the original numbers that I reset the reference for but... This seems like a job for 2 or 3 different queries.
EDIT:
Sorry I know I didn't include enough detail. Here is some additional info:
My exact table structure is not the same as here but I am only using the columns that I listed so I didn't consider the fact that any of the others would matter. Most of the tables have a unique ID that is auto incremented. The phone table has carrier, type, ect columns. The additional columns I felt were irrelevant to include, but if there is a solution that includes the auto incremented ID of each table, let me know :) Anyway, I sort of found a solution, using multiple queries though I am still interested to learn and apply knowledge based on this question. So I have a that join table that I mentioned. It might look something like this for the expected results. There is a before and after table in one sorry for poor formatting.
+--------------------+---------+----------+---------+
| Join Table Results | | | |
+--------------------+---------+----------+---------+
| Before | | After | |
| Join | Table | Join | Table |
| PersonID | PhoneID | PersonID | PhoneID |
| 1 | 1 | 1 | 1 |
| 1 | 2 | 1 | 2 |
| 1 | 3 | 1 | 3 |
| 2 | 4 | 2 | 1 |
| 2 | 5 | 2 | 5 |
| 2 | 6 | 2 | 6 |
| 3 | 7 | 3 | 5 |
| 3 | 8 | 3 | 5 |
| 3 | 9 | 3 | 5 |
| 3 | 10 | 3 | 8 |
| 3 | 11 | 3 | 9 |
+--------------------+---------+----------+---------+
So you can see that in the before columns, 7, 8, and 9 would all be duplicate phone numbers in the PhoneID - PhoneID relationship table I posted originally. After the query I wanted to retrieve the duplicates using the PhoneID - PhoneID comparison and take the ones that match, to change the join table in a way that I have shown directly above. So 7, 8, 9 all turn to 5. Because 5 is the original number, and 7, 8, 9 coincidentally were duplicates of 5. So I am basically pointing all of them to 5, and then deleting what would have been 7, 8, 9 in my Phone table since they all have a new relationship to 5. Is this making sense? xD It sounds outrageous typing it out.
End Edit
How can I improve my query to accomplish this task? Is it possible using an UPDATE statement? I was also considering just looping through this output and updating each row individually but I had a hope to just use a single query to save time and code. Typing it out makes me feel a tad obnoxious but I had hope there was a solution out there!
Thank you to anyone in advance for taking your time to help me out :) I really appreciate it. If it sounds outlandish, let me know I will just use multiple queries.

Database multiple choice and comments structure

I've read a lot of pages but didn't find what I was looking for.
I am trying to figure out which is the most appropriate solution for my problem here. I currently got a multiple choice form with 23 questions and 23 comments section (650 characters each, basically a comment per question) and I am not sure if I should go with a single table or if that would be too much.
So basically something like:
id
user_id
date
multiplechoice1
..
multiplechoice23
comment1
..
comment23
status
That will be around 50 columns :/ Is there a better way to do this? Like split the comments on a different table or somehow combine all the multiple choices in a single column? Since each answer will be 1-5.
Example of the question:
How long do you usually surf the NET on a daily basis?
0-1 hour
2-3 hours
4-6 hours
more than 7 hours
Taking your comments into consideration, being that you don't want to normalize too much and prefer something slightly flattened, I think this may be a proper solution for you.
questions
+----+-------------------------------+
| id | question |
+----+-------------------------------+
| 1 | What is your favorite food? |
+----+-------------------------------+
| 2 | What is your favorite animal? |
+----+-------------------------------+
answers - question 1 has three answers, question 2 has two answers
+----+-------------+-----------+
| id | question_id | answer |
+----+-------------+-----------+
| 1 | 1 | Spaghetti |
+----+-------------+-----------+
| 2 | 1 | Chicken |
+----+-------------+-----------+
| 3 | 1 | Sushi |
+----+-------------+-----------+
| 4 | 2 | Dog |
+----+-------------+-----------+
| 5 | 2 | Cat |
+----+-------------+-----------+
answer_data - one person answered "spaghetti" for question 1, one person answered "cat" for question 2, and one person answered "dog" for question 2
+----+-------------+-----------+
| id | question_id | answer_id |
+----+-------------+-----------+
| 1 | 1 | 1 |
+----+-------------+-----------+
| 2 | 2 | 4 |
+----+-------------+-----------+
| 3 | 2 | 5 |
+----+-------------+-----------+
Truthfully I'm not great with MySQL, I'm a T-SQL guy, but the query would probably look something like this:
SELECT q.question, a.answer, COUNT(ad.answer_id) as `Count`
FROM questions q
JOIN answers a ON a.question_id = q.question_id
JOIN answer_data ad ON ad.question_id = q.question_id
GROUP BY q.question, a.answer
+-------------------------------+-----------+-------+
| question | answer | count |
+-------------------------------+-----------+-------+
| What is your favorite food? | Spaghetti | 1 |
+-------------------------------+-----------+-------+
| What is your favorite animal? | Dog | 1 |
+-------------------------------+-----------+-------+
| What is your favorite animal? | Cat | 1 |
+-------------------------------+-----------+-------+

Normalized Database schema of quiz in php

I am little confusing for building schema of quiz
In this I have to upload many questions and having four options each option contains textbox and corresponding checkbox that denotes for right answer. if admin select one checkbox that could be right answer.
Note:- In some cases I have uploaded many option 6 to 7 and answers might be 2 or 3 are correct and admin will click on many checkboxes
Can anyone helping in schema
This seems fairly straight forward. You just have three tables, one for quizzes, one for questions and one for answers. Something like this:
Quizzes
+----+-------------+-----------------+
| id | name | description |
+----+-------------+-----------------+
| 1 | Sample Quiz | An example quiz |
+----+-------------+-----------------+
Questions
+----+---------+------------+
| id | quiz_id | question |
+----+---------+------------+
| 1 | 1 | Question 1 |
+----+---------+------------+
Answers
+----+-------------+----------+------------+
| id | question_id | answer | is_correct |
+----+-------------+----------+------------+
| 1 | 1 | Answer 1 | 0 |
| 2 | 1 | Answer 2 | 1 |
| 3 | 1 | Answer 3 | 0 |
| 4 | 1 | Answer 4 | 0 |
+----+-------------+----------+------------+
This schema will support as many quizzes as you need, each with any number of questions and each question can have any number of answers.

Assigned multiple users to a 'task'

Okay so I'm creating a task manager for my company. A user can assign assign a task to multiple other users. So I've though of 2 ways of implementing this.
This is my tasks table for option one (at least the columns that are important in this discussion ):
----------------------------------------------
| id | assigned_to | assigned_from |
---------------------------------------------
| 1 | 1,3,6 | 4 |
--------------------------------------------
| 2 | 1,4 | 2 |
---------------------------------------------
So here I pretty much just comma separate each user_id that is assigned to this particular task
Option 2:
----------------------------------------------------------
| id | task_id | assigned_to | assigned_from |
------------------------------------------------------------
| 1 | 335901 | 1 | 4 |
-----------------------------------------------------------
| 2 | 335901 | 3 | 4 |
-----------------------------------------------------------
| 3 | 335901 | 6 | 4 |
-----------------------------------------------------------
| 4 | 564520 | 1 | 2 |
-----------------------------------------------------------
| 4 | 564520 | 4 | 2 |
-----------------------------------------------------------
So as you can see here instead of putting the assiged_to is's here I just create a task id which is a random number and then I can groupBy 'task_id'. This is currently they way I have built it but for some reason it feels like it might screw me over in the future (not that option one doesn't give me the same feeling). So my question is which way do you guys recommend or is there maybe a different better way that I could be doing this?
Option 2 ist the better solution since you can acutally work with the table. You may e.g. create another table Tasks with
Task_id | Task_name | Budget | ...
Or a table with user-IDs for assigned_to and assigned_from. All these tables can be joined together if you use 2nd Option.
btw it is the correct normalization form
You can use Option 2 and normalize further if tasks are always assigned by/from the same person.
Tasks table:
task_id | assigned_from
1 | 4
2 | 2
The Assignees table then doesn't need to have the assigned_from since it's always the same for that task_id:
id | task_id | assigned_to
1 | 1 | 1
2 | 1 | 3
3 | 1 | 6
4 | 2 | 1
5 | 2 | 4

MySQL query how to get list of all distinct values from columns that contain multiple string values?

I am trying to get a list of distinct values from the columns out of a table.
Each column can contain multiple comma delimited values. I just want to eliminate duplicate values and come up with a list of unique values.
I know how to do this with PHP by grabbing the entire table and then looping the rows and placing the unique values into a unique array.
But can the same thing be done with a MySQL query?
My table looks something like this:
| ID | VALUES |
---------------------------------------------------
| 1 | Acadian,Dart,Monarch |
| 2 | Cadillac,Dart,Lincoln,Uplander |
| 3 | Acadian,Freestar,Saturn |
| 4 | Cadillac,Uplander |
| 5 | Dart |
| 6 | Dart,Cadillac,Freestar,Lincoln,Uplander |
So my list of unique VALUES would then contain:
Acadian
Cadillac
Dart
Freestar
Lincoln
Monarch
Saturn
Uplander
Can this be done with a MySQL call alone, or is there a need for some PHP sorting as well?
Thanks
Why would you store your data like this in a database? You deliberately nullify all the extensive querying features you would want to use a database for in the first place. Instead, have a table like this:
| valueID | groupID | name |
----------------------------------
| 1 | 1 | Acadian |
| 2 | 1 | Dart |
| 3 | 1 | Monarch |
| 4 | 2 | Cadillac |
| 2 | 2 | Dart |
Notice the different valueID for Dart compared to Matthew's suggestion. That's to have same values have the same valueID (you may want to refer to these later on, and you don't want to make the same mistake of not thinking ahead again, do you?). Then make the primary key contain both the valueID and the groupID.
Then, to answer your actual question, you can retrieve all distinct values through this query:
SELECT name FROM mytable GROUP BY valueID
(GROUP BY should perform better here than a DISTINCT since it shouldn't have to do a table scan)
I would suggest selecting (and splitting) into a temp table and then making a call against that.
First, there is apparently no split function in MySQL http://blog.fedecarg.com/2009/02/22/mysql-split-string-function/ (this is three years old so someone can comment if this has changed?)
Push all of it into a temp table and select from there.
Better would be if it is possible to break these out into a table with this structure:
| ID | VALUES |AttachedRecordID |
---------------------------------------------------------------------
| 1 | Acadian | 1 |
| 2 | Dart | 1 |
| 3 | Monarch | 1 |
| 4 | Cadillac | 2 |
| 5 | Dart | 2 |
etc.

Categories