How to group MySQL query by multiple criterias? - mysql

Here's what I'm trying to achieve. I have this table:
Table 'Receipts':
Fruit |Receipt| Name
| No |
--------|-------|-------
Apple | 534 | Mike
Apple | 422 | Mike
Apple | 355 | Mike
Peach | 646 | Robert
Banana | 412 | Alex
Banana | 124 | Alex
Banana | 067 | Sam
Banana | 975 | Sam
Banana | 645 | Sam
And I want to display each unique combination, so each item every person has:
Apple | Mike
Peach | Robert
Banana | Alex
Banana | Sam
I can only manage to either group things by fruit or by name, no idea how I could get this done.
Can anybody help?

SELECT Fruit, Name FROM tableName
GROUP BY Fruit, Name
Or if you want to have a unique combination, you can even do it as
SELECT Fruit, Name
FROM mytable
GROUP BY concat(Fruit,'-', Name) //group the data based on unique word formed

Related

How can I return each record associated with State and City while returning State and City name only once? (MySql)

I'm not really sure how to ask this and I've been search-engining for awhile and haven't come up with anything useful.
Say I have the following three tables People, Cities and States:
PeopleID | Name | Age | CityIDFK
--------------------------------------------
1 | John | 24 | 20
2 | Jim | 28 | 21
3 | Joan | 49 | 10
4 | Mike | 37 | 10
5 | Bruce | 26 | 2
6 | Peter | 22 | 20
7 | Oprah | 27 | 3
7 | Jake | 21 | 1
CityIDPK | City | StateIDFK
---------------------------------------
1 | Seattle | 1
2 | Gotham | 2
3 | Oakland | 4
10 | Boise | 5
20 | Austin | 6
21 | Tyler | 6
StateIDPK | StateName
----------------------------
1 | Washington
2 | New York
3 | Oregon
4 | California
5 | Idaho
6 | Texas
How can I achieve the following output:
StateName | City | Name
---------------------------------------
California | Oakland | Oprah
Idaho | Boise | Mike
| | Joan
New York | Gotham | Bruce
Washington | Seattle | Jake
Texas | Austin | John
| | Peter
| Tyler | Jim
I'm not sure if the above output is possible or not, I would probably just do something like this:
SELECT StateName, City, Name FROM People
INNER JOIN Cities
ON Cities.CityIDPK = People.CityIDFK
INNER JOIN States
ON States.StateIDPK = Cities.StateIDFK
But that would return the StateName and City for every person, instead of just once.
StateName | City | Name
---------------------------------------
California | Oakland | Oprah
Idaho | Boise | Mike
Idaho | Boise | Joan
New York | Gotham | Bruce
Washington | Seattle | Jake
Texas | Austin | John
Texas | Austin | Peter
Texas | Tyler | Jim
If the output I want to achieve is possible, would someone show me an example of how to write the query, or point me in the right direction?
I agree with Tim, this should be handled in your presentation layer.
But you can do it if you're using MySQL 8 by taking advantage of window functions. We can use row_number() to determine the first row per state and per city, then use a case to only display the name for the first row.
SELECT
case row_number() over states_w
when 1 then states.name
else '' end as StateName,
case row_number() over cities_w
when 1 then cities.name
else '' end as CityName,
people.name as Name
FROM People
INNER JOIN Cities ON Cities.id = People.City_id
INNER JOIN States ON States.id = Cities.state_id
window states_w as (partition by states.id),
cities_w as (partition by cities.id);
If you're using MySQL before 8... upgrade. If you can't upgrade, it can be emulated.

Selecting rows except some others

ID | fruit | who | days_ago |
----------------------------------
1 | orange | Adam | 2 |
2 | banana | Adam | 3 |
3 | apple | Adam | 4 |
4 | kiwi | Adam | 2 |
6 | banana | Jimmy | 3 |
7 | apple | Jimmy | 5 |
8 | grapes | Jimmy | 1 |
9 | orange | Carol | 2 |
10 | grapes | Carol | 6 |
11 | lemon | Carol | 3 |
And my problem is:
The table contained information about who bought what fruit and when (when is an extra information I just need to keep).
I need to select all the fruits that Adam didn't buy.
ID | fruit | who | days_ago |
----------------------------------
8 | grapes | Jimmy | 1 |
10 | grapes | Carol | 6 |
11 | lemon | Carol | 3 |
And if Jimmy bought them, I don't want to know if Carol bought them too.
And my result should be this:
ID | fruit | who | days_ago |
----------------------------------
8 | grapes | Jimmy | 1 |
11 | lemon | Carol | 3 |
When I GROUP BY fruit, I lose information about who and days_ago (I don't understand how they're chosen).
And when I select unique fruits and drop all that Adam bought, I lose grapes which both Jimmy and Carol bought.
This isn't the actual table I'm working on. Just a simplification of what I'm struggling with.
Any ideas?
If you want the fruits that Adam didn't buy, you can use a subquery for this. Have the subquery select the fruits he did buy, and then have the main query say "not those".
SELECT *
FROM fruits
WHERE fruit NOT IN(
SELECT fruit
FROM fruits
WHERE who = "Adam"
)
DEMO: http://sqlfiddle.com/#!9/3974d/1
When you use GROUP BY, you are combining multiple rows into one. The other rows' data isn't gone, just hidden. Try using GROUP_CONCAT to see the list of who fields.
SELECT ID, fruit,
GROUP_CONCAT(who) as who,
GROUP_CONCAT(days_ago) AS days_ago
FROM fruits
WHERE fruit NOT IN(
SELECT fruit
FROM fruits
WHERE who = "Adam"
)
GROUP BY fruit
DEMO: http://sqlfiddle.com/#!9/3974d/3

MySQL, select multiple rows as one based on foreign key

i have the following 2 tables.
| ID | NAME | AGE |
|----|------|-----|
| 0 | John | 30 |
| 1 | Nick | 35 |
| 2 | Mike | 30 |
| USERID | FRUIT |
|--------|------------|
| 0 | apple |
| 0 | orange |
| 1 | banana |
| 1 | tomato |
| 1 | grape |
| 1 | watermelon |
| 2 | pear |
| 2 | cherry |
I'm using this query in order to get what fruit every user with age<34 likes.
SELECT users.name, fruit FROM users,fruits WHERE users.id=fruits.userid AND users.age<34;
Result:
| NAME | FRUIT |
|------|--------|
| John | apple |
| John | orange |
| Mike | pear |
| Mike | cherry |
sqlfiddle
Is there a way to have only one row returned for every user with the fruits on one or multiple columns?
Desired result:
| NAME | FRUIT |
|------|---------------|
| John | apple,orange |
| Mike | pear,cherry |
or
| NAME | FRUIT | FRUIT |
|------|--------|--------|
| John | apple | orange |
| Mike | pear | cherry |
I tried using GROUP_CONCAT() but i didn't get the result i expected, any help would be great.
Thanks in advance for your time.
SELECT users.name, group_concat( fruit )
FROM users,fruits
WHERE users.id=fruits.userid AND users.age<34
group by user.name
Try This(The STUFF function):
CREATE TABLE #Test(
Name VARCHAR(100),
FRUIT VARCHAR(100)
)
INSERT INTO #Test VALUES
('John', 'apple'),
('John', 'orange'),
('Mike', 'pear'),
('Mike', 'cherry')
SELECT Name,
STUFF((SELECT ', ' + FRUIT
FROM #Test t1
WHERE t1.Name = t2.Name
FOR XML PATH(''), TYPE).value('.','VARCHAR(MAX)'),1,2,'') AS 'Fruits'
FROM #Test t2
Group by Name
Drop Table #Test
This outputs:
Name Fruits
John apple, orange
Mike pear, cherry

Displaying the content of two mysql tables together

Trying to figure out how to display the content of two mysql tables when one table has multiple matching rows, eg. so that the tables below display the results:
London - Harry Smith, Oliver Jones, Jack Taylor
Manchester - Charlie Williams, Jacob Brown
Table One Table two
+-----------------------------+ +----------------------------------+
| id | branchid | store | | branchid | firstname | employee |
+-----------------------------+ +----------------------------------+
| 1 | 1 | London | | 1 | Harry | Smith |
| 2 | 2 | Manchester | | 1 | Oliver | Jones |
+-----------------------------+ | 1 | Jack | Taylor |
| 2 | Charlie | Williams |
| 2 | Jacob | Brown |
+----------------------------------+
Many thanks.
GROUP_CONCAT will do the job, although we first need to CONCAT as well to put firstname and lastname together:
SELECT b.store, GROUP_CONCAT(CONCAT(e.firstname, ' ', e.employee)) AS Employees
FROM TableOne b INNER JOIN TableTwo e on b.branch = e.branchid
GROUP BY b.store;
SqlFiddle here
Result:
Store Employees
London Harry Smith,Jack Taylor,Oliver Jones
Manchester Jacob Brown,Charlie Williams`

Making opposite of select in MySQL query

I have been struggling with getting an opposite search in MySQL.
Here is a sample database:
+-------+--------+
| name | fruits |
+-------+--------+
| Jimmy | pear |
| Jimmy | apple |
| Jimmy | peach |
| Becky | pear |
| Garry | apple |
| Garry | pear |
+-------+--------+
What I'm trying to get is names of all people that did not eat apple. When I do query searching for WHERE fruits NOT LIKE "%apple%" I get not only Becky (which is the only one who did not eat it), but also two fields of Jimmy and one of Garry, because there were other occurrences where they ate something else.
How should I write a query?
this is one possible approach
select name where name not in (select name where fruits like '%apple%')