This is my first time making my own mysql database, and I was hoping for some pointers. I've looked through previous questions and found that it IS possible to search multiple tables at once... so that expanded my posibilities.
What I am trying to do, is have a searchable / filterable listing of Snowmobile clubs on a PHP page.
These clubs should be listable by state, county or searchable for by name / other contained info.
I'd also like them to be alphabetized in the results, despite the order of entry.
Currently my mind was in the place of, have a table for NY, PA etc
With Columns for County(varchar), Clubname(varchar), Street address (long text) , phone (varchar) email (varchar) website address (varchar)
Should I really be making multiple tables for each county, such as NY.ALBANY , NY.MADISON
Are the field formats I have chosen the sensible ones?
Should Address be broken into subcomponents... such as street1, street2, city, state, zip.
Eventually, I think I'd like a column "trailsopen" with a yes or no, and change the tr background to green or red based on input.
Hope this makes sense...
Here is how I would setup your db:
state
id (tinyint) //primary key auto incremented unsigned
short (varchar(2)) // stores NY, PA
long (varchar(20)) // Stores New York, Pennsylvania
county
id (int) //primary key auto incremented unsigned
state_id (tinyint) //points to state.id
name (varchar(50))
club_county
id (int) //primary key auto incremented unsigned
county_id (int) //points to county.id
club_id (int) //points to club.id
club
id (int) //primary key auto incremented unsigned
name (varchar(100))
address (varchar(100)
city (varchar(25))
zip (int)
etc...
From my perspective, it seems like 1 table will be enough for your needs. MySQL is so robust that there are many ways to do just about anything. I recommend downloading and using MySQL Workbench, which makes creating tables, changing tables, and writing queries easier and quicker than embedding them in a webpage.
Download MySQL Workbench -> http://dev.mysql.com/downloads/workbench/
You will also need to learn a lot about the MySQL queries. I think you can put all the info that you need in one table, and the trick is which query you use to display the information.
For example, assume you only have 1 table, with all states together. You can display just the snow mobile clubs from NY state with a query like this:
select * from my_table where state = "NY";
If you want to display the result alphabetic by Club Name, then you would use something like this:
select * from my_table where state = "NY" order by clubname;
There is A LOT of documentation online. So I would suggest doing quite a few hours of research and playing with MySQL Workbench.
The purpose of Stack Overflow is to answer more specific questions that have to do with specific code or queries. So once you have built a program, and get stumped on something, you can ask the specific question here. Good luck!
U can a create a single table with composite key constraint. Like..
I have 3 department in a company and each have multiple num of sub department.so I can create a database like this..
Dept_id || sub_dept_id || Name || Sal || Address || Phone
..where Dept_id and sub_dept_id will jointly represent the primary key and beholds its uniqueness.
But remember if ur database is going to be too large,then think before u doing this step,u might need need clustering or index for that scenario.
While writing SQL query,its good practise to divide a main module in num of sub module. So u can break the Adress.
As per your yes/no.... use integer feild and plan it in a way that if its YES,it'll store 1 else 0(zero)...
You shouldn't make individual tables for the individual counties. What you should do instead is create a table for states, a table for counties, and a table for addresses.
The result could look something like this:
state (id, code, name),
county (id, stateID, name),
club (id, countyID, name, streetAddress, etc...)
The process used to determine what to break up and when is called "database normalisation" - there's actually algorithms that do this for you. The wiki page on that is a good place to start: http://en.wikipedia.org/wiki/Database_normalization
One long text for the street address is fine, btw, as are varchars for the other fields.
Should I really be making multiple tables for each county, such as NY.ALBANY , NY.MADISON
It depends, but in your described case an alternative might be to have one database table with all the snowmobile clubs, and one table for all the states/counties. In the clubs table you could have an id field as foreign key which links the entry to a specific state/county entry.
To get all the info together you'd just have to do a JOIN-operation on the tables (please refer to mysql documentation).
Are the field formats I have chosen the sensible ones?
They would work..
Should Address be broken into subcomponents... such as street1, street2, city, state, zip?
Essentially the question here is if you need it broken down into subcomponents, either now or in the future? If it is broken down, you have the data separated which makes further processing (eg generation of serial letters, automated lookups..) potentially simpler, but that depends on your processing; if you don't need it separated why make life more complicated?
so many answers already.. agreed.
Related
For a forum, i want to enable the users to send messages to each other to.
In order to do this, I made a table called Contacts, within this table I have 5 collumns: The user_id, a collumn for storing Friends, one for storing Family, one for storing Business and one for other contacts. These last four should all contain an array, which holds the user_id's of that type of contact. The reason I chose for this design is because I don't want to type an awful lot or limit the users on the amount of friends, like friend1, friend2 etc.
My question is: Is this correct how I do it? If not, what should be improved?And what type of MYSQL field should Friends, Family, Business and Other be?
What you should do instead of that is have a map table between your Contacts table and any related tables (User, Friends, Family, Business). The purpose would purely be to create a link between your Contact and your User(s) etc, without having to do what you're talking about and use arrays compacted into a varchar etc field.
Structured data approach gives you a much more flexible application.
E.g. UserContacts table purely contains its own primary key (id), a foreign key for Users and a foreign key for Contacts. You do this for each type, allowing you to easily insert, or modify maps between any number of users and contacts whenever you like without potentially damaging other data - and without complicated logic to break up something like this: 1,2,3,4,5 or 1|2|3|4|5:
id, user_id, contact_id
So then when you come to use this structure, you'll do something like this:
SELECT
Contacts.*
-- , Users.* -- if you want the user information
FROM UserContacts
LEFT JOIN Contacts ON (UserContacts.contact_id = Contacts.id)
LEFT JOIN Users ON (Users.id = UserContacts.user_id)
Use the serialize() and unserialize() functions.
See this question on how to store an array in MySQL:
Save PHP array to MySQL?
However, it's not recommended that you do this. I would make a separate table that stores all the 'connections' between two users. For example, if say John adds Ali, there would be a record dedicated to Ali and John. To find the friends of a user, simply query the records that have Ali or John in them. But that's my personal way of doing things.
I recommend that you query the users friends using PHP/MySQL all the time you need them. This could save considerable amount of space and would not take up so much speed.
serialize the array before storing and unserialize after retrieving.
$friends_for_db = serialize($friends_array);
// store $friends_for_db into db
And for retrieving:
// read $friends_for_db from db
$friends_array = unserialize($friends_for_db);
However, it should be wiser to follow other answers about setting up an appropriate many-to-many design.
Nevertheless, I needed this kind of design for a minor situation which a complete solution would not be necessary (e.g. easy storing/retrieving some multi-select list value which I'll never query nor use, other than displaying to user)
Description:
I am building a rating system with mysql/php. I am confused as to how I would set up the database.
Here is my article setup:
Article table:
id | user_id | title | body | date_posted
This is my assumed rating table:
Rating table:
id | article_id | score | ? user_id ?
Problem:
I don't know if I should place the user_id in the rating table. My plan is to use a query like this:
SELECT ... WHERE user_id = 1 AND article_id = 10
But I know that it's redundant data as it stores the user_id twice. Should I figure out a JOIN on the tables or is the structure good as is?
It depends. I'm assuming that the articles are unique to individual users? In that case, I could retain the user_id in your rating table and then just alter your query to:
SELECT ... WHERE article_id = 10
or
SELECT ... WHERE user_id = 1
Depending on what info you're trying to pull.
You're not "storing the user_id twice" so much as using the user_id to link the article to unique data associated to the user in another table. You're taking the right approach, except in your query.
I don't see anything wrong with this approach. The user id being stored twice is not particularly relevant since one is regarding a rating entry and the other, i assume, is related to the article owner.
The benefit of this way is you can prevent multiple scores being recorded for each user by making article_id and user_id unique and use replace into to manage scoring.
There are many things to elaborate on this depending on whether or not this rating system needs to be intelligent to prevent gaming, etc. How large the user base is, etc.
I bet for any normal person, this setup would not be detrimental to even a relatively large scale system.
... semi irrelevant:
Just FYI, depending on the importance and gaming aspects of this score, you could use STDDEV() to fetch an average factoring the standard deviation on the score column...
SELECT STDDEV(`score`) FROM `rating` WHERE `article_id` = {article_id}
That would factor outliers supposing you cared whether or not it looked like people were ganging up on a particular article to shoot it down or praise it without valid cause.
you should not, due to 3rd normal form, you need to keep the independence.
"The third normal form (3NF) is a normal form used in database normalization. 3NF was originally defined by E.F. Codd in 1971.[1] Codd's definition states that a table is in 3NF if and only if both of the following conditions hold:
The relation R (table) is in second normal form (2NF)
Every non-prime attribute of R is non-transitively dependent (i.e. directly dependent) on every superkey of R."
Source here: http://en.wikipedia.org/wiki/Third_normal_form
First normal Form: http://en.wikipedia.org/wiki/First_normal_form
Second normal Form: http://en.wikipedia.org/wiki/Second_normal_form
you should take a look to normalization and E/R model it will help you a lot.
normalization in wikipedia: http://en.wikipedia.org/wiki/Database_normalization
One simple question and I couldn't find any answers to id :
Should name be in 2 different DB columns ( name / surname ) or in 1 column ( name + surname ) ?
In all the projects I had they were in 2 different columns, but now I have to start a new project and I was wantering how it better to store it. I mean, the 2 different columns gave me a bit of trouble and sometimes slowed performance down. Please note this very important thing :
A very important part of the public part of the site will be an advanced search and it WILL search for the full name in about 200k records.
So, what do you suggest ? 2 columns or 1 ? I am inclined twords the 1 column solution because I cannot find any advantages in using 2, but maybe I am wrong ?
EDIT
Thank you for the answers. The only reason for this question was for the performance issue, I need all the extra boost I can get.
The point of a relational database is to relate data. If you store a full name (e.g. John Smith) in a single field, you lose the ability to easily separate out the first and last names.
If you store them in separate fields, you can VERY easily rejoin them into a single full name, but it's quite difficult to reliably pull a name apart into separate first + last name components.
Two columns is much more flexible. Eg.
Do you ever want to sort by surname?
Do you ever want to address the person formally (eg: Dear Mr Cosmin)?
Will you ever want to search by surname and not forename, or vice versa?
200K records is a trivial amount in any properly designed database.
You may find this an interesting read on the subject of names
With two columns, you can sort by surname without having to do expensive substring operations in your select statement. It is easy to do a CONCAT to get the full name in situations that call for it, but harder to parse the last name out of names such as "John Doe-Smith" or "John Doe III".
Using 2 columns helps you in:
easy sorting data by surname
communication with user by name (eg. "Hello Michael" used on many websites etc.)
displaying a lot of data in multiple columns (you can display only surname when you have no space on screen)
Names stored in format "Surname Name" is still easy to sort, but may be seen as inelegant in some countries.
In my opinion, I'd rather designed it as two different colmns because you can have various ways to handle the record. About performance issue, add an index on two columns to make faster searching.
There are times when you want to search for John Doe and wanting that even it is reverse Doe John but still matches to John Doe. That's one advantage of having separate fields on the name.
Sample design of schema,
CREATE TABLE PersonList
(
ID INT AUTO_INCREMENT,
FirstName VARCHAR(25),
LastName VARCHAR(25),
-- other fields here,
CONSTRAINT tb_pk PRIMARY (ID),
CONSTRAINT tb_uq UNIQUE (FirstName, LastName)
)
I need to generate a unique random code to store in a database with a user id.
What I'm trying to do is create a php script that first generates a random string of a given length, then checks a database to see if that string already exists, if so, generate a new random string.
The database will be organized by email address or some other field like customer_id. Each user can have say up to 5 devices associated with their account.
As a test I've created two MYSQL tables, one called users: email, firstname, lastname
the other called udevices. Udevices has 6 fields, one for the email address and 5 for the devices: email, dev1, dev2, dev3, dev4, dev5
all fields in both tables are VARCHAR
It occurs to me that another way to organize this is to have just two fields - email and device and then for each device just add another record to devices. Not sure which is most efficient.
So what i'm looking for is how to write a SELECT statement that will query the database for a given email address and a device string.
So, to boil the question down:
Can someone give me an example of a SELECT statement as described above? Is this even possible? Web searches on the topic bring up people talking about having to loop through each db record. Is that the only way, and if so, can someone give me an example of a PHP script that can loop through each record to check if a string already exists in a database?
You need a minimum of two tables, but most probably three if you need device descriptions, etc... I would go with three tables if I were you.
users: user_id | email | name | surname
devices: device_id | device_name | ...
user_devices: user_id | device_id
On users and devices the user_id and device_id must be the primary keys. On user_devices user_id and device_id must be the compound primary key.
Then the query to select all the devices of a user would be:
SELECT d.* FROM devices d
INNER JOIN user_devices ud
ON d.device_id = ud.device_id
AND ud.user_id = 123;
As far as the unique random code, you must tell us what its content will be (i.e. where will the uniqueness be based upon). If you have that, you can easily use one of the hashing functions such as md5(), etc... to generate the random string.
EDIT
If you do not need to verify the value of the random string, then you can generate one with the base_convert and microtime. The odds of duplicates are down to the microsecond. That is, if both visitors will request the code on that same microsecond they will get the same string, which is hardly ever the case, but still possible.
$string = base_convert(microtime(true), 10, 36);
it really depends on your final design, whether the udevices have static number of devices (as your current solution) or dynamic one (that 'another way' you stated). you don't need postprocessing via PHP, SQL alone can query it.
So what i'm looking for is how to write a SELECT statement that will query the database for a given email address and a device string
hey, isn't it too basic? read up your SQL book
Is that the only way, and if so, can someone give me an example of a PHP script that can loop through each record to check if a string already exists in a database?
what for? just SELECT and count the result. if it's > 0, then it exists. otherwise it doesn't.
A table with thing1, thing2, thing3 is clearly a repeating group, and should be normalized out. So your idea of having email/device is the right direction, however, using email address as the key is a bad idea. You are better off making a numeric auto_increment key for both tables, and having user_id be a foreign key in the device table that links them together, so that 1 user can have many devices associated with that user.
You can then query this table easily using select count(*) as countof from devices where device = '$devicename'. However, you can easily insure that your devices are unique by using something like:
$device = md5($email . uniqueid());
I working on a food database, every food has a list of properties (fats, energy, vitamins, etc.)
These props are composed by 50 different columns of proteins, fat, carbohydrates, vitamins, elements, etc.. (they are a lot)
the number of columns could increase in the future, but not too much, 80 for extreme case
Each column needs an individual reference to one bibliography of a whole list from another table (needed to check if the value is reliable or not).
Consider the ids, should contain a number, a NULL val, or 0 for one specific exception reference (will point to another table)
I've though some solution, but they are very different eachothers, and I'm a rookie with db, so I have no idea about the best solution.
consider value_1 as proteins, value_2 as carbohydrates, etc..
The best (I hope) 2 alternatives I thought are:
(1) create one varchar(255?) column, with all 50 ids, so something like this:
column energy (7.00)
column carbohydrates (89.95)
column fats (63.12)
column value_bil_ids (165862,14861,816486) ## as a varchar
etc...
In this case, I can split it with "," to an array and check the ids, but I'm still worried about coding praticity... this could save too many columns, but I don't know how much could be pratical in order to scalability too.
Principally, I thought this option usual for query optimization (I hope!)
(2) Simply using an additional id column for every value, so:
column energy (7.00)
column energy_bibl_id (165862)
column carbohydrates (89.95)
column carbohydrates_bibl_id (14861)
column fats (63.12)
column fats_bibl_id (816486)
etc...
It seems to be a weightful number of columns, but much clear then first, especially for the relation of any value column and his ID.
(3) Create a relational table behind values and bibliographies, so
table values
energy
carbohydrates
fats
value_id --> point to table values_and_bibliographies val_bib_id
table values_and_bibliographies
val_bib_id
energy_id --> point to table bibliographies biblio_id
carbohydrates_id --> point to table bibliographies biblio_id
fats_id --> point to table bibliographies biblio_id
table bibliographies
biblio_id
biblio_name
biblio_year
I don't know if these are the best solutions, and I shall be grateful if someone will help me to bring light on it!
You need to normalize that table. What you are doing is madness and will cause you to loose hair. They are called relational databases so you can do what you want without adding of columns. You want to structure it so you add rows.
Please use real names and we can whip a schema out.
edit Good edit. #3 is getting close to a sane design. But you are still very unclear about what a bibliography is doing in a food schema! I think this is what you want. You can have a food and its components linked to a bibliography. I assume bibliography is like a recipe?
FOODS
id name
1 broccoli
2 chicken
COMPONENTS
id name
1 carbs
2 fat
3 energy
BIBLIOGRAPHIES
id name year
1 chicken soup 1995
FOOD_COMPONENTS links foods to their components
id food_id component_id bib_id value
1 1 1 1 25 grams
2 1 2 1 13 onces
So to get data you use a join.
SELECT * from FOOD_COMPONENTS fc
INNER JOIN COMPONENTS c on fc.component_id = c.id
INNER JOIN FOODS f on fc.foods_id = f.id
INNER JOIN BIBLIOGRAPHIES b on fc.bib_id = b.id
WHERE
b.name = 'Chicken Soup'
You seriously need to consider redesiging your database structure - it isn't recommended to keep adding columns to a table when you want to store additional data that relates to it.
In a relational database you can relate tables to one another through the use of foreign keys. Since you want to store a bunch of values that relate to your data, create a new table (called values or whatever), and then use the id from your original table as a foreign key in your new table.
Such a design that you have proposed will make writing queries a major headache, not to mention the abundance of null values you will have in your table assuming you don't need to fill every column..
Here's one approach you could take to allow you to add attributes all day long without changing your schema:
Table: Food - each row is a food you're describing
Id
Name
Description
...
Table: Attribute - each row is a numerical attribute that a food can have
Id
Name
MinValue
MaxValue
Unit (probably a 'repeating group', so should technically be in its own table)
Table: Bibliography - i don't know what this is, but you do
Id
...
Table: FoodAttribute - one record for each instance of a food having an attribute
Food
Attribute
Bibliography
Value
So you might have the following records
Food #1 = Cheeseburger
Attribute #1 = Fat (Unit = Grams)
Bibliography #1 = whatever relates to cheeseburgers and fat
Then, if a cheeseburger has 30 grams of fat, there would be an entry in the FoodAttribute table with 1 in the Food column, 1 in the Attribute column, a 1 in the Bibliography column, and 30 in the Value column.
(Note, you may need some other mechanisms to deal with non-numeric attributes.)
Read about Data Modeling and Database Normalization for more info on how to approach these types of problems...
Appending more columns to a table isn't recommended nor popular in the DB world, except with a NoSQL system.
Elaborate your intentions please :)
Why, for the love of $deity, are you doing this by columns? That way lies madness!
Decompose this table into rows, then put a column on each row. Without knowing more about what this is for and why it is like it is, it's hard to say more.
I re-read your question a number of times and I believe you are in fact attempting a relational schema and your concern is with the number of columns (you mention possibly 80) associated with a table. I assure you that 80 columns on a table is fine from a computational perspective. Your database can handle it. From a coding perspective, it may be high.
Proposed (1) Will fail when you want to add a column. You're effectively storing all your columns in a comma delimited single column. Bad.
I don't understand (2). It sounds the same as (3)
(3) is correct in spirit, but your example is muddled and unclear. Whittle your problem down to a simple case with five columsn or something and edit your question or post again.
In short, don't worry about number of columns right now. Low on the priority list.
If you have no need to form queries based on arbitrary key/value pairs you'd like to add to every record, you could in a pinch serialize()/unserialize() an associative array and put that into a single field