I'm working on a site where a user could select certain dates that apply to them, e.g Date 1,Date 2, Date 3, etc.
Each date will have certain questions belonging to it, so if the customer checked off 'Date 1' to indicate that this date applies to him, he'll then see a bunch of textboxes asking him about Date 1 and how it applies to them. Same goes for all other dates.
Date 1 and 2 and several questions, but the remaining dates have just 1 question.
These dates and their answers will later be used to create personalized reminders for the customer and sent out to him.
I'd also like a design which makes it simple (or as simple as possible) to add additional dates and fields.
My question is, what's the best way to store all the dates and their answers related to the user in the database? I was thinking that in the user table, I have boolean columns from Date 1 - Last date (obviously they're not actually named date 1, date 2 etc). If the column for Date 1 is set to 0, it means the customer didn't check it off, and if its 1 then it means he did and he answered the questions for it.
Regarding the actual storage of the dates, I'm considering these two options:
1) 1 table for each date, with columns for every question asked for that date and a user_id column. So in Date_1 table I'll have columns like Q1_name, Q2_name and the answers of the questions that the user gave.
But I want something more elegant because 1), it will make it a pain to fetch all the user's answers when calculating what info. applies to them when sending the personalized emails. 2) Some dates have only 1 question, so it'll be ugly to create a full-blown table for them.
2) A user_answer table, with the columns:
user_id,date_name,question_name,answer_val
2 seems the most elegant so far, but there should be a better solution. Any thoughts?
It sounds like you want something like the following (basic) table structure:
User - userId, userInfo
Date - dateId, dateInfo
Question - questionId, questionInfo
UserDate - userId, dateId - this stores all dates that apply for a given user and represents the many to many relationship between Users and Dates - a user can have many dates and a date can have many users
DateQuestion - dateId, questionId - this stores all questions that apply for a given date and represents the many to many relationship between Dates and Questions - a date can have many questions and, I assume, a question can be used against more than one date
UserResponse - userId, questionId, questionResponse - this stores all user responses to any questions asked. If you need to know which date the question applies to, assuming they can answer the same question more than once for multiple dates, add a dateId column.
Option 2 seems close to the good solution, but I'd replace date_name and question_name with date_id and question_id.
An optimal, and simplest solution that enables adding new questions and dates seems to be:
1. Dates table with the fields date_id, title, date.
2. Questions table with the fields question_id, date_id, title (and possibly type off the answer and description).
3. Answers table with question_id and answer.
You'll also need to decide whether or not you have questions that are common to several dates, and what to do in that case. (you may want two different answers, or a common answer). I'd recommend against the first solution, it'd make the question not dynamic - you'd have to change the sql and table structure for each change in the questions or dates.
I think you've pretty much got it, the only thing is you could possibly separate the question and date names into a separate table, giving you the following schema:
User: id, ... (name, date of birth, favourite food, etc)
DateName: id, name (called it DateName so no conflicts with the word Date, which could mean something else in SQL)
Question: id, date_id, text
UserAnswer: user_id, question_id, answer_val
It's not necessary to split them up, but there are three reasons to do it:
1. Lookups on integers (like question_id) as opposed to text (like question_name) is a lot faster because integers are smaller and fixed in size.
2. If you change the text to a question (like to correct a spelling mistake), you only need to change a single entry in Question, instead of on every single row.
3. Because you're storing each bit of text only once, you save a lot of space. Storing 1000 ints are smaller than storing 1000 strings. Well as long as the strings are longer than a few character that is.
Besides that I think that could work quite well.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I'm a bit unsure what is best way to tackle one requirement that I have on my project (Laravel API and Angular UI). So I have one pretty straightforward task. I need to create database schema for members and their subscription status for months in selected year.
I need to keep this as simple as possible, because this is a very simple admin app, where admin user will manually mark paid status for each member when they pay, so there is nothing special or advanced here. On UI it should look like this:
So basically every year members can pay membership for every month in that year.
Note: x means member payed membership for that month.
From database standpoint I'm thinking and trying to decide about something like this:
Note: membership and another_membership are tables that I'm consider to use, I will chose one of them, based on suggestions
So basically the idea behind this is pretty simple, every time member pays, membership table will be updated with date and member id, and that way I will have all payments for every member.
Because of UI from first picture I have few problems that I'm not really sure how to approach.
In order to generate bootstrap table from first image I'm thinking something like, for example if I want to get all memberships for year 2018 from certain selection I will do something like:
Select * from member m left join membership ms on m.id = ms.member_id where date >= 01-01-2018 and date <= 01-31-2018 and m.selection_id = 1
But I'm still unsure what is best way to map members each month status. I'm thinking maybe to group all dates from membership table and then somehow to generate this table
Anyone have any suggestions on this? Should I use membership table or another_membership table? Should I do mapping (members and months statuses) on UI or API side? Any other suggestion? Someone told me that it might be a "good" idea to create simple table with member_id, year, and all 12 months as attributes and just store true/false for each month there. Something like this:
Also one thing that bothers me, is it good idea maybe to first get all members, and then get all data from membership table based on member ids, so for example if I have pagination of 20 members I will make db call like this:
Get page 0 with 20 members
select * from membership m where m.member_id in (list_of_ids)
You do not want to store membership information in columns. Either membership or another_membership are fine -- they store the values in rows.
Which to choose? That is really up to you. For a general application, I would go for something like:
MemberShipId
EffDate -- from date
EndDate -- to date
PaymentDate
. . . other information
You are set on the memberships being for one month periods, so having either a single date (say the first of the month) or splitting out the columns into (year and month) are fine.
What #GordonLinoff writes is how I would structure the database.
The next thing you probably need is a way of pivoting your rows to columns; you probably end up with a query that produces output along the lines of:
UserName Month Member
---------------------
Tom Jan18 null
Tom Feb18 1
.....
This question shows you how to convert that into the rows your front-end cares about.
I am currently working on a simple booking system and I need to select some ranges and save them to a mysql database.
The problem I am facing is deciding if it's better to save a range, or to save each day separately.
There will be around 500 properties, and each will have from 2 to 5 months booked.
So the client will insert his property and will chose some dates that will be unavailable. The same will happen when someone books a property.
I was thinking of having a separate table for unavailable dates only, so if a property is booked from 10 may to 20 may, instead of having one record (2016-06-10 => 2016-06-20) I will have 10 records, one for each booked day.
I think this is easier to work with when searching between dates, but I am not sure.
Will the performance be noticeable worse ?
Should I save the ranges or single days ?
Thank you
I would advise that all "events" go into one table and they all have a start and end datetime. Use of indexes on these fields is of course recommended.
The reasons are that when you are looking for bookings and available events - you are not selecting from two different tables (or joining them). And storing a full range is much better for the code as you can easily perform the checks within a SQL query and all php code to handle events works as standard for both. If you only store one event type differently to another you'll find loads of "if's" in your code and find it harder to write the SQL.
I run many booking systems at present and have made mistakes in this area before so I know this is good advice - and also a good question.
This is too much for a comment,So I will leave this as an answer
So the table's primary key would be the property_id and the Date of a particular month.
I don't recommend it.Because think of a scenario when u going to apply this logic to 5 or 10 years system,the performance will be worse.You will get approximately 30*12*1= 360 raws for 1 year.Implement a logic to calculate the duration of a booking and add it to table against the user.
Let me start off by stating that I'm a just a self-taught hobbyist at this, so I'm sure I'm doing some things wrong or ineffciently, so any feedback is appreciated. If this question is moot because I've made fundamental errors and need to start from scratch, I guess I need to know so I'll become better.
With that, here's the problem:
I have a database of birth names in MySQL that is intended to let you find the frequency of those names within a given year range. My only table has a lot of columns:
**Name** **Begins** **Popularity** **1800** **1801** **1802**
Aaron A 500 6 7 4
Amy A 100 10 2 12
Ashley A 250 2 5 7
...and so forth until 2013.
Right now I've written a PHP page that can call up a list of names based on the start letter over the entire year range (1800-2013). That works, but what I'd like to do is to let the user specify a custom year range from the dropdowns I put on the home page and use that to calculate the frequency of each name for the custom year range only. I'd also like to be able to sort the resulting list based on those frequency values, not the all-time frequency stored in 'Popularity'.
From what I've looked at, I'm thinking part of the solution might lie in using custom views but I just can't seem to put the pieces all together. Or should I somehow pre-calculate all possible combinations?
Here's is the working query code I'm using right now:
{$query = "SELECT Name
FROM nametable
WHERE Gender = '$genselect'
AND
(BeginsWith = '$begins')
ORDER BY $sortcolumn $sortorder";
goto resultspage;
}
resultspage:
$result = mysqli_query($dbcnx, $query)
or die ("Error in query: $query.".mysqli_error($dbcnx));
$rows = $result->num_rows;
echo "<br>You found $rows names!<br>";
while($row=mysqli_fetch_assoc($result))
{
echo '<br>'.$row['Name'];
}
I think you're going to have to consider structuring your data in a different way to make the most of using an RDBMS.
If it were me, I'd be looking at normalising data into different tables in the first instance and disposing of unnecessary fields such as "Begins" and "Popularity". That kind of information can easily be reproduced or sought out in PHP or within a query itself. The advantage here is that you also reduce the number of columns that actually need to be maintained.
I haven't worked out a silver bullet schema but, roughly, I'd start with something along these lines and expand/modify where appropriate:
Names
- id
- name
- genderID
Genders
- id
- code
Years
- id
Frequencies
- id
- nameID
- yearID
- number
So, for example, a segment of your data may take the following shape:
Names (1, Aaron, 1)
Genders (1, Male)
Years (1987)
Frequencies (1, 1, 1987, 6), (1, 1, 1988, 19)
The beauty of having your data separated out like this is that it becomes much easier to query it. So, if you wanted the frequency of occurrences of the name Aaron between 1987 and 1988 you could do something like the following:
SELECT SUM(frequencies.number) FROM frequencies WHERE frequencies.yearID
BETWEEN 1987 AND 1988
AND frequencies.nameID = 1
Furthermore, doing away with the "Begins" column would mean you can structure a query to use "LIKE"
SELECT * FROM names WHERE name LIKE "A%"
My examples are perhaps a bit contrived but hopefully they illustrate what I'm getting at.
One thing I haven't touched upon is how you might go about physically entering the data. What happens when a new name is added? Does a corresponding entry get made in the frequencies table automatically? Is a check performed in the frequencies table first and, if an entry exists, does it automatically increment the number?
These are important problems to consider but probably best left until after a schema is settled upon.
I'm quite new to programming in general, so I expect this question to have an easy solution. I searched for an answer before posting, but I'm not really sure what I'm looking for.
Basically, I have a database with the following structure:
Table: things
Column 1- ID
Column 2- Name
Column 3- Year
Column 4- Timestamps
I have a large collection of timestamps for many things of the format hh:mm:ss that I want to store in the 4th column of the things table. Each item in the table will have a varying number of timestamps associated with it, so I thought it would make sense to simply store them all in a single column separated by commas (hh:mm:ss,hh:mm:ss) rather than store each timestamp in its own column. From here, I hoped that using PHP I could select the name of a thing and recall its year and timestamps, separating each timestamp into its own variable.
Example:
Column 2- Thing20
Column 3- 1997
Column 4- 00:01:24,00:05:28,00:16:52
$name = "Thing20"
$year = 1997
$ts1 = "00:01:24"
$ts2 = "00:05:28"
$ts3 = "00:16:52"
Here are my questions...
Is this a practical solution for my needs? I'm having trouble
thinking of a better way to do this...
How would I go about separating the timestamps (which are separated
by commas in the database entry) and storing them as incremental
variables? Rather, I suppose you would use an array instead of many
variables.
Any help at all would be greatly appreciated. As I said above, I am a beginner so I'm very sorry if this is a trivial thing to ask!
Thank you!
Design issue
If you need n values for each ID, then instead of storing it in a single column you should split it into two tables.
Table 1: things (ID, name, year), where ID is a primary key
Table 2: timestamps (ID, timestamp), where ID is a foreign key from 'things' and where you can store as many ID,timestamp pairs as you wish (and timestamp is a single value)
So in your example, table 1 will look like this:
ID, Name, Year
1, Thing20, 1997
Table 2 will look like this:
ID, timestamp
1, 00:01:24
1, 00:05:28
1, 00:16:52
Practical solution
However, if changing DB structure is not a case, then you can just use:
$ts = explode(',', $timestamp);
and you will receive an array of all timestamps in $ts variable
I won't try to answer as to the merits of your approach.
On a practical level, you can split your string into an array using the explode:
// where $col4 = "00:01:24,00:05:28,00:16:52"
$tsarray=explode(',',$col4);
// $tsarray = array("00:01:24","00:05:28","00:16:52");
The ways are many and varied for then allocating the array elements to individual variables.
Cheers.
I have two queries ultimately I think they will be in the same context of the other but in all. I have a user database that I want to pull out for tracking records based on hour. Example registrations per hour. But in this registrations per hour I want to have the query to dump results by hour increments (or weeks, or months) ie: 1,000 regitrations in november, 1,014 in december and so on, or similar for weeks hours.
I also have a similar query where I want to generate a list of states with the counts next to them of how many users I have per state.
My issue is, I'm thinking I think to one dimensionally currently cause the best idea I can think of at the moment is making in the case of the states 50 queries, but I know thats insane, and there has to be an easier way thats less intense. So thats what Im hoping someone from here can help me with, by giving me a general idea. Cause I don't know which is the best course of action for this currently.. be it using distinct, group_by or something else.
Experiment a bit and see if that doesn't help you focus on the question a bit more.
Try selecting from your registrations per hour table and appending the time buckets you are interested in to the select list.
like this:
select userid, regid, date_time, week(date_time), year(date_time), day(date_time)
from registraions;
you can then roll up and count things in that table by using group by and an aggregate function like this:
select count(distinct userid), year(date_time)
from registraions
group by year(date_time)
Read about about date time functions:
MySQL Date Time Functions
Read about aggregate functions"
MySQL Group By