Mysql - select from multiple tables without producing duplicate data [closed] - php

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 8 years ago.
Improve this question
I have three tables and I would like to select from the tables without producing duplicates.
The table are as follows:
Customers
id | name | lastName
---------------------------------------
1 | john | doe
2 | helen | keller
Orders
The userID column is a foreign key that references John Doe, so John orders 3 items.
id | userID | order
---------------------------------------
1 | 1 | pizza
2 | 1 | pasta
3 | 1 | lasagna
CustomerRating
The userID column is a foreign key that references John Doe, so John leaves 5 reviews.
id | userID | rating | comment
-------------------------------------------------
1 | 1 | 5/5 | was good
2 | 1 | 5/5 | excellent
3 | 1 | 4/5 | great
4 | 1 | 4/5 | great
5 | 1 | 4/5 | great
How would I select from the 3 tables where I can get a return results that look like this?
id | name | lastName | order | rating
-----------------------------------------------------------------
1 | john | doe | pasta | 5/5
| | | pizza | 5/5
| | | lasagna | 4/5
| | | | 4/5
| | | | 4/5
I've tried joining these tables, but since John has left 5 reviews and only ordered 3 times, the id, name,lastName, and order columns gets filled with duplicate data.
Thanks!

I don't have any experience in MySQL but I assume that it works similar to MSSQL.
So the format in which you are expecting the output is not possible. You can rather get the order and rating column values as comma separated
Here is a similar kind of question that might help you
including example based on link
try something like this
SELECT Customers.id, Customers.name, Customers.lastName,
GROUP_CONCAT(Orders.order) OrderedDishes,
GROUP_CONCAT(CustomerRating.rating) RatingsGiven
FROM
..... rest of your query .....

There are ways to discard duplicates (SELECT DISTINCT, UNION, GROUP BY) but it is not clear whether users update existing rating or create new ones. And what you want to see: the last rating or the average one
On the other note - i would change your entire setup:
order table would contain order_id, customer_idand other order related stuff like order_date
products table that would describe each of your dishes and their info like price, description etc
order_products table with fields order_id and prduct_id
if users rate products then your rating table would need at least product_id, customer_id, rate_value. I'd also add ratingDate That way you can get averages or select the last one by Max(ratingDate)

I think you need to add an orderID field to the CustomerRating table else there is no way to relate an item to its rating.

Related

Can SELECT, SELECT COUNT and cross reference tables be handled by just one query?

I have a page that displays a list of projects. With each project is displayed the following data retrieved from a mysqli database:
Title
Subtitle
Description
Part number (1 of x)
The total number of photos associated with that project
A randomly selected photo from the project
A list of tags
Projects are displayed 6 per page using a pagination system
As this is based on an old project of mine, it was originally done with sloppy code (I was just learning and did not know any better) using many queries. Three, in fact, just for items 5-7, and those were contained within a while loop that worked with the pagination system. I'm now quite aware that this is not even close to being the right way to do business.
I am familiar with INNER JOIN and the use of subqueries, but I'm concerned that I may not be able to get all of this data using just one select query for the following reasons:
Items 1-4 are easy enough with a basic SELECT query, BUT...
Item 5 needs a SELECT COUNT AND...
Item 6 needs a basic SELECT query with an ORDER by RAND LIMIT 1 to
select one random photo out of all those associated with each project
(using FilesystemIterator is out of the question, because the photos
table has a column indicating 0 if a photo is inactive and 1 if it is
active)
Item 7 is selected from a cross reference table for the tags and
projects and a table containing the tag ID and names
Given that, I'm not certain if all this can (r even should for that matter) be done with just one query or if it will need more than one query. I have read repeatedly how it is worth a swat on the nose with a newspaper to nest one or more queries inside a while loop. I've even read that multiple queries is, in general, a bad idea.
So I'm stuck. I realize this is likely to sound too general, but I don't have any code that works, just the old code that uses 4 queries to do the job, 3 of which are nested in a while loop.
Database structure below.
Projects table:
+-------------+---------+----------+---------------+------+
| project_id | title | subtitle | description | part |
|---------------------------------------------------------|
| 1 | Chevy | Engine | Modify | 1 |
| 2 | Ford | Trans | Rebuild | 1 |
| 3 | Mopar | Diff | Swap | 1 |
+-------------+---------+----------+---------------+------+
Photos table:
+----------+------------+--------+
| photo_id | project_id | active |
|--------------------------------|
| 1 | 1 | 1 |
| 2 | 1 | 1 |
| 3 | 1 | 1 |
| 4 | 2 | 1 |
| 5 | 2 | 1 |
| 6 | 2 | 1 |
| 7 | 3 | 1 |
| 8 | 3 | 1 |
| 9 | 3 | 1 |
+----------+------------+--------+
Tags table:
+--------+------------------+
| tag_id | tag |
|---------------------------|
| 1 | classic |
| 2 | new car |
| 3 | truck |
| 4 | performance |
| 5 | easy |
| 6 | difficult |
| 7 | hard |
| 8 | oem |
| 9 | aftermarket |
+--------+------------------+
Tag/Project cross-reference table:
+------------+-----------+
| project_id | tag_id |
|------------------------|
| 1 | 1 |
| 1 | 3 |
| 1 | 4 |
| 2 | 2 |
| 2 | 5 |
| 3 | 6 |
| 3 | 9 |
+------------+-----------+
I'm not asking for the code to be written for me, but if what I'm asking makes sense, I'd sincerely appreciate a shove in the right direction. Often times I struggle with both the PHP and MySQLi manuals online, so if there's any way to break this down, then fantastic.
Thank you all so much.
You're able to do subqueries inside your SELECT clause, like this:
SELECT
p.title, p.subtitle, p.description, p.part,
(SELECT COUNT(photo_id) FROM Photos where project_id = p.project_id) as total_photos,
(SELECT photo_id FROM Photos where project_id = p.project_id ORDER BY RAND LIMIT 1) as random_photo
FROM projects as p
Now, for the list of tags, as it returns more than one row, you can't do a subquery and you should do one query for every project. Well, in fact you can if you return all the tags in some kind of concatenation, like a comma separated list: tag1,tag2,tag3... but I don't recommend this one time that you will need to explode the column value. Do it only if you have many many projects and the performance to retrieve the list of tags for each individual project is fairly low. If you really want, you can:
SELECT
p.title, p.subtitle, p.description, p.part,
(SELECT COUNT(photo_id) FROM Photos where project_id = p.project_id) as total_photos,
(SELECT photo_id FROM Photos where project_id = p.project_id ORDER BY RAND LIMIT 1) as random_photo,
(SELECT GROUP_CONCAT(tag SEPARATOR ', ') FROM tags WHERE tag_id in (SELECT tag_id FROM tagproject WHERE project_id = p.project_id)) as tags
FROM projects as p
As you said from item 1 to 4 you already have the solution.
Add to the same query a SQL_CALC_FOUND_ROWS instead of a SELECT COUNT to solve the item 5.
For the item 6 you can use a subquery or maybe a LEFT JOIN limiting to one result.
For the latest item you can also use a subquery joining all the tags in a single result (separated by comma for instance).

Which is the better way to create my mysql table? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
Based on my situation, should I combine all symptoms into one row as my method 1 below or method 2 that create more rows. The reason I don't like method 1 is that I have to use - to separate each symptom, and later I need to use php explode('-') to separate them and use LIKE to match them.
Method 2 will create more rows, and I think I will create more table to separate them.
Method 1:
disease symptoms
HIV pain-cough-hair loss
Flu cought-running nose-fever
cacer lose weight-fever-fatigue
Method 2:
disease symptoms
HIV pain
HIV cough
HIV hair loss
... ...
... ...
Out of your two methods, method 2 would be preferred. As #JNevill notes, storing multiple pieces of data in one column becomes a nightmare when searching or filtering data.
My full recommendation would be to use option 3 however. Take a look at the below design:
Table 1: DISEASES
+------+-----------+
| id | name |
+------+-----------+
| 1 | HIV |
|------|-----------|
| 2 | FLU |
|------|-----------|
| 3 | Cancer |
+------+-----------+
Primary Key:
id
Table 2: SYMPTOMS
+------+-----------+
| id | name |
+------+-----------+
| 1 | pain |
|------|-----------|
| 2 | cough |
|------|-----------|
| 3 | hair-loss |
+------+-----------+
Primary Key:
id
Table 3: DISEASES-SYMPTOMS
+-------------+--------------+
| disease_id | symptom_id |
+--------------+--------------+
| 1 | 1 |
|--------------|--------------|
| 1 | 2 |
|--------------|--------------|
| 1 | 3 |
+--------------+--------------+
Primary Key:
(disease_id, symptom_id)
Foreign Keys:
DISEASES.id -> DISEASES_SYMTPOMS.disease_id
SYMTPOMS.id -> DISEASES_SYMTPOMS.symptom_id
Establish your base tables DISEASES and SYMPTOMS. Then establish a 3rd table representing a JOIN of the first two tables. This normalization of the data will simply the structure of your application and prevent duplication of data since each disease can have multiple symptoms and each symptom can belong to multiple disease.
SAMPLE QUERY (MySQL):
SELECT
d.id,
d.name,
s.name
FROM DISEASES as d
INNER JOIN DISEASES_SYMPTOMS AS ds ON d.id = ds.disease_id
INNER JOIN SYMPTOMS AS s ON ds.symptom_id = s.id;
SAMPLE QUERY RESULT:
+------+----------------+----------------+
| id | disease_name | symptom_name |
+------+----------------+----------------+
| 1 | HIV | pain |
|------|----------------|----------------|
| 1 | HIV | cough |
|------|----------------|----------------|
| 1 | HIV | hair-loss |
+------+----------------+----------------+
It depends how normalized you want your database to be. The more normalized approach would be to create a symptoms table that houses all symptoms, a disease table that houses all diseases, and another table with links diseases to symptoms probably by disease_id and symptom_id. And the less normalized approach is like your method 1 where you include all the symptoms as a field in the table separated by some delimiter or put into an array if you are using a database that supports arrays.
Create two master tables for disease & symptoms. And then create a third table say .disease_symptom include the two foreign key column say disease_id & symptom_id and refer to the corresponding master table

Looking for a better way to store a table using PHP and MySQL [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I am new to PHP and MySQL and require help with an issue I am facing. I am trying to create a table that is cleaner then the following:
Table example
Item |Part |Quantity
Item1 |123 |2
Item1 |124 |2
Item2 |123 |1
Item2 |125 |3
I can do this with a normal table but I can envision the database having tons of repeat rows with duplicate data. For example I used Item1 multiple times to identify each part.
I was wondering if there was a cleaner way to store this data in my database? I will be using PHP to store the data into MySQL. I am also looking to make the Item column unique but as it stands, can not do this.
I looked into serialize, join as well as an array but I couldn't figure out how to make it all fit so I thought I would ask here. The end results would be a PHP report that says:
Item 1 uses the following parts
Part 123 : Quantity 2
Part 124 : Quantity 2
Item 2 uses the following parts
Part 123: Quantity 1
Part 125: Quantity 3
Any help would be greatly appreciated.
You have a many-to-many relation between your items and your parts.
So you need 3 tables (item, part, and link_item_part).
Your item table will have an id as a primary key. Same goes for your part table. Your link_item_part table will have a compound primary key build from two foreign keys one on item, the other one on part.
-- item table
| id | name |
+----+--------+
| 1 | Item 1 |
| 2 | Item 2 |
-- part table
| id | name |
+----+------+
| 1 | 123 |
| 2 | 124 |
| 3 | 125 |
-- link_item_part
| item_id | part_id | quantity |
+---------+---------+----------+
| 1 | 1 | 2 |
| 1 | 2 | 2 |
| 2 | 1 | 1 |
| 2 | 3 | 3 |
Edit: don't store data in a format that is not native to the database if you want to manipulate them with queries. If you store data in a non-native format, you'll have a hard time to manipulate it, and it will be slow.

count number of rows that have the same combination of two colums

Hi I have 2 table Offense table and User_jobs table
offense table:
crime_id |crime_type |casenumber|
---------+-----------+----------+
1 | 3 |1 |
2 | 3 |1 |
1 | 3 |2 |
12 | AA |2 |
user_jobs table:
casenumber |disposal_status |
-----------+----------------+
1 | yes |
1 | yes |
2 | no |
2 | no |
what i want is to count the number of rows with the same combination say crime_id=1 and crime_type= 3 but these must have a disposal status of yes in the user_jobs table.
i want to do this in mysql. pliz help
sorry but i am new to mysql. i now want to display the real names of those id not the id themselves.
the tables with these IDs are crime_category and Crime_type Crime_catgory
table:
category |crime_id |
-----------+----------------+
theft | 1 |
murder | 2 |
rape | 3 | 2 |
no |
Crime_type table:
Crime_type |id |
---------------+----------------+
administrative | yes |
criminal | yes |
You can do this with a simple inner join and an aggregate function:
select
o.crime_id,
o.crime_type,
count(*)
from
offence o
join user_jobs uj
on o.casenumber=uj.casenumber
where
uj.disposal_status='Yes'
group by
o.crime_id,
o.crime_type
This will pick up distinct combinations of the first two columns joined as they should tot he jobs table and only where the disposal_status is equal to 'Yes'
Edit: You would probably do really well to have a read of this Q&A that I put together for exactly this sort of situation - where I give you the code for it, but would like to explain this is a lot more detail. The Q&A explains why this type of thing (and many many others) work and how they do so:
How can an SQL query return data from multiple tables
Edit 2:
select
o.crime_id,
o.crime_type,
ct.category,
count(*)
from
offence o
join user_jobs uj
on o.casenumber=uj.casenumber
join crime_type ct
on o.crime_type=ct.crime_id
where
uj.disposal_status='Yes'
group by
o.crime_id,
o.crime_type,
ct.category,

MySQL store demographics in multiple tables [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
I have a platform with multiple clients and each has a large set of demographics that I need to store. With this in mind, it seems I could do one of two things in MySQL. Either:
Option #1: Have a large table with everyone's demographics. For example:
Table: clientDemographics
id | clientID | firstName ....
1 | 34 | John ......
2 | 12 | Fred ......
Option #2: Split out each client to having their own table:
Table: client34_demographics
id | firstName ....
1 | John ......
Table: client12_demographics
id | firstName ....
1 | Fred ......
Are there any advantages to splitting the tables out by client (efficiency, security, scalability) or disadvantages? Which of these would be a better method? Thanks!
Your second example is not a good idea (creating a table for each demographic). Instead, I would go with something more "normalized" that contains unique identifiable information in the client table, and then additional meta data (demographics) as a lookup:
Table: Clients
ClientId | FirstName | LastName | Email
-------------------------------------------------
1 | John | Smith | jsmith#email.com
Table: Demographics
DemographicId | Name
-------------------------------------------------
1 | Gender
2 | Nationality
3 | Age
Table: Clients_Demographics
CDId | ClientId | DemographicId | Value
-------------------------------------------------
1 | 1 | 1 | Male
2 | 1 | 2 | American
3 | 1 | 3 | 27
In this way you can easily sort on demographic types, demographic values, clients, etc and all the while saving space in your database, increasing query performance, and keeping your data scalable. By scalable I mean, need to add another Demographic? Just add another row to the Demographics table and then associate a value in the Clients_Demographics table with a Client. If they value is not set (i.e. no row exists) then you know that value can be seen as empty in your forms until they actually set a value.

Categories