How to simplify the following tables and optimize? - php

Now i have a table with the following fields
id
country
hdate
religions
season
description
link
rate
and i store the data within this table , my sample data will be
1 Afghanistan 2008-01-19 Islamic Winter Ashura ashura 2
2 Afghanistan 2008-03-20 Islamic Winter Mouloud (Birth of the Prophet) mouloud 4
3 Afghanistan 2008-01-01 Common Winter New Year Day new-year 5
4 Albania 2008-04-28 Christian Spring Orthodox Easter Monday easter-monday 4
5 Albania 2008-01-01 Common Winter New Year Day new-year 5
here you can look there is data redundancy and so i've decided to break up the tables and bring some common sense.
I've created a draft but i couldn't finalize what could i do to bring a best data structure.
I decided to bring all countries in one table
and all the holidays data into one table (id, holiday, celebrated_by, religions season link rate) the celebrated_by stores the id of the countries seperated by comma
and the holiday_dates for storing the dates of the holiday.
(holiday_id, date, year) date stores the complete date and the year stores only the year as 2009,2008 etc..
Now i want to list all the holidays of a particular country , list the countries which celebrates the same holiday (when a holiday is listed) etc..
Please suggest me whether this structure is enough or is there any flaws or any changes to be made.
help me

You should have two (or three) tables. one for countries and one for holidays for sure. I would suggest even adding a third for religion, if more than 1 religion share the same holiday. The latter can have a foreign key that links it to the countries table
countries
================
country_id (auto increment)
name
religion
============
religion_id (auto increment)
name
holidays
===============
holiday_id (auto increment)
date
season
description
link
rate
country_id (FK)
religion_id (FK)
Let me know if you need a hand with the joins to query.

if celebrated_by links with the country table's unique key, then it is good, u can easily handle this. But redundany would be there in holiday table
If not then u could either create one or can create another table which links b/w country and holiday (country_id, holiday_id) fields would be enough to sort out queries and reduce redundancy

the proposed structure is fine except that you shouldn't use comma-separated list of ids for linkage. Make 'celebrated_by' a separate table with fields country_id, holiday_id
Theoretically you might want to replace direct references to 'religion' or 'season' with reference tables (like pocketfullofcheese suggested), but I doubt this will be of any practical benefit.

Related

Mysql summary from colums

I need to summary columns together on each row, like a leaderboard. How it looks:
Name | country | track 1 | track 2 | track 3 | Total
John ENG 32 56 24
Peter POL 45 43 35
Two issues here, I could use the
update 'table' set Total = track 1 + track 2 + track 3
BUT it's not always 3 tracks, anywhere from 3 to 20.
Secound if I don't SUM it in mysql I can not sort it when I present data in HTML/php.
Or is there some other smart way to build leaderboards?
You need to redesign your table to have colums for name, country, track number and data Then instead if having a wide table with just 3 track numbers you have a tall, thin table with each row being the data for a given name, country and track.
Then you can summarise using something like
SELECT
country,
name,
sum(data) as total
FROM trackdata
GROUP BY
name,
country
ORDER BY
sum(data) desc
Take a look here where I have made a SQL fiddle showing this working the way you want it
Depending upon your expected data however you might really be better having a separate table for Country, where each country name only appears once (and also for name maybe). For example, if John is always associated with ENG then you have a repeating group and its better to remove that association from the table above which is really about scores on a track not who is in what country and put that into its own table which is then joined to the track data.
A full solution might have the following tables
**Athlete**
athlete_id
athlete_name
(other data about athletes)
**Country**
country_id
country_name
(other data about countries)
**Track**
Track_id
Track_number
(other data about tracks)
**country_athlete** (this joining table allows for the one to many of one country having many athletes
country_athlete_id
country_id
athlete_id
**Times**
country_athlete_id <--- this identifies a given combination of athlete and country
track_id <--- this identifies the track
data <--- this is where you store the actual time
It can get more complex depending on your data, eg can the same track number appear in different countries? if so then you need another joining table to join one track number to many countries.
Alternatively, even with the poor design of my SQL fiddle example, it might be good to make name,country and track a primary key so that you can only ever have one 'data' value for a given combination of name, country and track. However, this decision, and that of normalising your table into multiple joined tables would be based upon the data you expect to get.
But either way as soon as you say 'I don't know how many tracks there will be' then you should start thinking 'each track's data appears in one ROW and not one COLUMN'.
Like others mentioned, you need to redesign your database. You need an One-To-Many relationship between your Leaderboard table and a new Tracks table. This means that one User can have many Tracks, with each track being represented by a record in the Tracks table.
These two databases should be connected by a foreign key, in this case it could be a user_id field.
The total field in the leaderboard table could be updated every time a new track is inserted or updated, or you could have a query similar to the one you wanted. Here is how such a query could look like:
UPDATE leaderboard SET total = (
SELECT SUM(track) FROM tracks WHERE user_id = leaderboard.user_id
)
I recommend you read about database relationships, here is a link:
https://code.tutsplus.com/articles/sql-for-beginners-part-3-database-relationships--net-8561
I still get a lot of issues with this... I don't think that the issue is the database though, I think it's more they way I pressent the date on the web.
I'm able to get all the data etc. The only thing is my is not filling up the right way.
What I do now is like: "SELECT * FROM `times` NATURAL JOIN `players`
Then <?php foreach... ?>
<tr>
<td> <?php echo $row[playerID];?> </td>
<td> <?php echo $row[Time];?> </td>
....
The thing is it's hard to get sorting, order and SUM all in ones with this static table solution.
I searched around for leaderboards and I really don't understand how they build theres with active order etc. like. https://www.pgatour.com/leaderboard.html
How do they build leaderboards like that? With sorting and everything.

INSERT INTO table in a loop with a WHERE statement (to populate foreign key column)

I'm trying to create a database for a school project and have to use multiple foreign keys. I already added raw data, and I'm wondering how to populate the foreign key columns dynamically.
For example I've got a city table and a country table. The city table has a country_id column that will contain the id from the right entry in the country table.
For now, the table city has the following columns :
id,
name,
code (like 'USA' for the US and the country has the same info, I was thinking about using that as an identifier with a WHERE statement)
country_id
I'm a complete beginner with mySql and feel totally lost right now !
Thanks for the help
Before normalization, a flat file could be used to describe the city and state data:
id city code country
1 Amsterdam NED Netherlands
2 Anvers BEL Belgium
3 Athènes GRE Greece
4 Atlanta USA United States
5 Barcelone ESP Spain
For this data, no more normalization is necessary. In fact, it would be counter-productive.
But what if you wanted to store information about the country that you don't want repeated in every city's record? i.e., you wanted to keep population size, crime rate, name of currency... whatever. You wouldn't want to store that information with every record that references the country; that would be a lot of duplicated information, and if you wanted to update the country's data, you'd have to change it in every record that has a city in that country.
This is where the concept of foreign keys comes in to play. You would split this into two different tables: city and country. Information that is specific about a city (city name etc) goes into the city table, and information that is specific to a country (population of country, currency name, etc) goes in to the country table.
But now, how do we populate the tables?
In a web-based environment, typically you would have a data entry page that would have an input for the city name, and a drop down box (or AJAX lookup) for the country with the value being the id for the country name. This way, when you submit the city and country pair, you have the country id to insert with the name of the city.
But in this case, you already have the city and country tables populated. In order to update the city table with the country id, you have to be able to join the tables. Fortunately, you have such a field in the country code. This is a happy accident, because this is actually duplicate information that shouldn't be in the city table... not to mention it's really not a good idea to rely on a varchar field to join on (hard to guarantee that values are identical)
But since it's there, let's use it!
First, how do you connect the tables? You join them on a field that they share.
Given:
City:
id name code country_id
1 Amsterdam NED
2 Anvers BEL
3 Athènes GRE
4 Atlanta USA
5 Barcelone ESP
Country
id name code
1 Afghanistan AFG
2 Albanie ALB
3 Algérie ALG
4 Andorre AND
5 Angola ANG
...
20 Belgium BEL
...
30 Netherlands NED
SELECT CITY.*, COUNTRY.*
FROM CITY
INNER JOIN COUNTRY ON CITY.CODE = COUNTRY.CODE
result (only two match with the result set I'm showing):
1 Amsterdam NED null 30 Netherlands NED
2 Anvers BEL null 20 Belgium BEL
Now that you can join the two tables, you can update the city table based on that data. MySql has its own way to do that:
UPDATE CITY
INNER JOIN COUNTRY ON CITY.CODE=COUNTRY.CODE
SET CITY.COUNTRY_ID = COUNTRY.ID
(See MySQL - UPDATE query based on SELECT Query)
You can just select all city from city table and take the code and compare to that of to the country table, when match found insert the country_id in city table. I hope it will help you.

GROUP_CONCAT() in MySQL not working while inserting value selecting from an another table

I want to insert the ids separated by commas from one table to another with where clause. The SELECT statement is working fine but while inserting for the specified keyword it's returning only 1 id.
My table structure:
TABLE 1
id property_id keyword
(auto-increment) (separated by commas from table 2 where keyword matches) (matched keyword with the description column in table 1 with like clause)
TABLE 2
id property_name city country property_address property_description
1 Ashish JK Apartments Bangalore India Thubarahalli A Tranquil - Soul Inspiring abode is just waiting for you. Come make the Most of it. 2 BHK Ashish J K Apartment: Total No. of Flats in the Project - 216 A house is the starting point of a new journey through life. The house becomes a reflection of ourselves because we base our lives around it. We see our lives pass by and our children grow up. And all these memories accumulate and make our house a home. It has been designed keeping us as individuals in mind. We all are different. We have our own unique sensibility that is why when we built Aashish J K Apartments we thought of it as a canvas, a canvas you could paint your life on. we did that by building a house that requires, minimum maintenance, with all the systems has been designed to work in a harmonious manner that ensures you a get a good night's sleep, every night Aashish J K Apartments: Seated Between Marathalli and Whitefield, an area that is fast escalating in the property market. Aashish J K apartment is indeed a wise investment to make from the business point of view. It shares its neighborhood with ITPL, Oracle, IGate, HUL, AAI and Other IT Parks located in a very prime place. This location today is a seat of contention for many of Bangalore's real estate developers. One thing that all of us can agree on, is that we all want value for money, and we are sure you would love to know just what Aashish J K Apartments would offer to you and your loved ones within your Pocket limits.
2 Aban Essence Bangalore India Sarjapur Road A home is not just a structure, it is a part of a flourishing future and the roof that keeps the present intact. We understand this well and hence the apartments are equipped with all the necessary amenities for a family, like swimming pools, gym, club houses, jogging track, garden etc. Along with this beauty are the ample number of trees and plants in the properties. At aban you will find a happy and a peaceful living with luxury and security
So, in Table 1 I basically want where TABLE 1 actually have 7000 data:
id property_id keyword
1 1,2 Bangalore
I've tried:
insert into TABLE_1(property_id,keyword)
SELECT group_concat(id separator ','),'Bangalore' from TABLE_2 AS a
WHERE a.description like '%Bangalore%' OR a.city like '%Banglore%' group by 'Bangalore';
The individual SELECT statement is working fine and returning proper result,
but when I use the INSERT statement it's just returning the TABLE_2 with the first id matching with the keyword. i.e:
TABLE_2 after running the query:
id property_id keyword
1 1 Bangalore
Now how to get the Comma Separated ids in the property_id column like what the SELECT statement returns.
I'm stuck with this since yesterday and found only UPDATE things like such. but nothing with insert in proper.
I know WHERE clause works first then GROUP_CONCAT() but how to get such results with INSERT also?
Any help is appreciated.
It should be
insert into TABLE_1(property_id,keyword)
SELECT group_concat(id),'Bangalore' from TABLE_2 AS a
WHERE a.description like '%Bangalore%' OR a.city like '%Banglore%'
try this
INSERT INTO TABLE_1(property_id, keyword)
(
SELECT GROUP_CONCAT(DISTINCT id separator ','), 'Bangalore' FROM TABLE_2
WHERE description LIKE '%Bangalore%' OR city LIKE '%Banglore%'
)

How can I store dates/attendance?

I'm looking for for an opinion.
I have a list of people and will need to store when they are present at a location so those in charge can check them off a list. I'm not 100% sure how long the dates will be needed but I'm assuming they may need to look at previous attendance lists.
My first instinct is to have a column for each date but that could result in many many columns. I could just store a list of dates next to each person:
"01/01/2012,01/15/2012,02/18/2012..."
that could result in a very long entry. It seems like neither is a good option.
If anyone has a suggestion or guidance on an approach please let me know. Thanks.
A complex, but also very clean approach would be
Table "persons":
id
name
Table "dates":
id
location
date
... whatever info the "dates" table needs
Table "attendances":
date_id (link to an entry in the "dates" table)
person_id (link to an entry in the "persons" table)
attended (yes/no)
Then fill the database with the appropriate dates, and fill the "attendances" table according to which persons need to be present at each date.
This is, as said, complex to implement, but it's incredibly flexible - you can have any number of dates and attendees; you can excuse people from attending a specific date programmatically; you can add people to groups...
Link tables.
One table of people
ID
Name
One table of classes
ID
Name
One table linking person to class to date.
ID
personID
classID
cDate
So all you would need to do to determine which students were preset on a certain date in a certain class:
SELECT *
FROM people p
LEFT JOIN peopletoclass ptc ON p.id = ptc.personid
LEFT join class c ON c.id = ptc.classid
WHERE ptc.cDate = '2011-11-07' AND c.id = '1';
Above (for example) would get all people in class id 1 on November 7th 2011.
Create a table "attendance" consisting of a person_id field and a date_present field. You can't store this into columns or a long list using a string ;-).
Than you can use queries where you join the table Person with Attendance.
Your first instinct would result in a horrible table design. What you should have is a seperate table that stores the users/locations/dates tuples
e.g.
userID locationID date
1 party 1/1/2011 00:00:00
1 bathroom 1/1/2011 00:05:00
1 party 1/1/2011 00:15:00
would show that user #1 was at a New Year's Eve party, then went to pray before the porcelain altar at 12:05am, then returned to the party 10 minutes later.

Multi-class, interlinked school timetable as a MySQL database

I've looked around for a bit now at other suggestions relating to this, but nothing I've seen has quite suited my needs, so here goes!
What I have is a multi-class (Australian secondary school; Years 7-12), multi-day (Mon-Fri) school timetable. What I now want to build is a MySQL database with the following information to be deployed on an account driven website.
Subjects:
Running time (as "Period 1 on Wednesday", "Period 2 on Friday", etc. -- multiple values in this column) Instructor (linked to separate database of all teachers) -- This would additionally need to change (temporarily) if a teacher was sick and replaced; perhaps a "replacementinstructor" column to be ignorned when NULL. Location (different, but specifically allocated, rooms on different days) -- As above, change temporarily when room altered.Other obviousnesses: Course name ("Year 7 Health"), Unique ID (Something like "7.HEALTH", rather than just auto-incrementing INT.), etc.
Teachers:
First name, last name Courses they take Contact infoOther obviousnesses: Unique ID (Auto-incrementing INT), Username (fname.lname), Password for their account, etc.
Students:
First name, last name Courses they attend (stored as an individual list for each student) Year level / Form (Year 7, Year 11, etc.)Basic personal info (Home suburb, email, etc.)More obviousnesses: Unique ID (same setup as teachers), Username (same as teachers), password, etc.
Any insight as to how I might design such a data structure would be greatly appreciated, I'm more of a UI fanatic than a MySQL thinker ;-D
Thanks in advance.
I can think of the following tables to use in MySQL:
students
Student information
id (auto_increment)
firstname
lastname
username
password
student_id (I had a student ID but I can't remember if I was given this in yr 7 or yr 10)
year
email
contact_phone
street
suburb
state (ENUM - ACT,NSW,WA,SA,TAS,VIC,NT,QLD)
teachers
Teacher information
id (auto_increment)
firstname
lastname
title (Dr, Mrs, etc)
username
password
email
contact_phone
street
suburb
state (ENUM - ACT,NSW,WA,SA,TAS,VIC,NT,QLD)
subjects
All the different subjects
id (auto_increment)
subject
subject_code (eg 7.HEALTH)
year
locations
Various locations around the school
id (auto_increment)
location (eg BLOCK A, ROOM 2, MUSIC ROOM)
subject_teachers
What subjects each teacher teaches
id (auto_increment)
subject_id
teacher_id
subject_students
Which subjects each student takes
id (auto_increment)
subject_id
student_id
subject_timetable
Main Timetable
id (auto_increment)
subject_id
location_id
teacher_id
alt_teacher_id (eg substitute teacher)
duration
period (number 1-however many periods in a day. 6 if I remember correctly)
week (number 1-2 or even perhaps 1-52)
weekday (number 1-5)
notes (as #Oswald suggested you could add additional notes for when things change)
The notes could be collated and then displayed as footnotes on the timetable.
You will obviously need a table for Subjects, a table for Students and a table for Teachers.
Read up on database normalization. This will tell you (amongst other things):
Do not put the running time into the Subject table as a comma separated list. Instead use a table for the running time and use a foreign key to map entries from that table to Subjects table.
Same goes for mapping teacher to courses.
Same goes for mapping students to courses.
That Running Time table would also be suitable for holding the location of a course during a specific running time.
Additionally, if you record temporary changes in the database, you are dependent on people changing the relevant information at a specific time. To get around this, you might want to consider a table Lessons, where you record
Running time
Week number
Course
Instructor
Location
Other fields that might be specific to that particular lesson.
This will allow you to schedule changes in advance (Mr. McCachney is sick for the next two weeks, Room 101 is closed for redecoration for a month, etc.)

Categories