Group column values together in one cell - mysql

I need to write an SQL select statement that groups together values from one column into one cell.
e.g.
table name: Customer_Hobbies
+------------+------------+-----------+
| CustomerId | Age | Hobby |
+------------+------------+-----------+
| 123 | 17 | Golf |
| 123 | 17 | Football |
| 324 | 14 | Rugby |
| 627 | 28 | Football |
+------------+------------+-----------+
should return...
+------------+------------+----------------+
| CustomerId | Age | Hobbies |
+------------+------------+----------------+
| 123 | 17 | Golf,Football |
| 324 | 14 | Rugby |
| 627 | 28 | Football |
+------------+------------+----------------+
Is this possible?
N.B. I know the data's not laid out in a particularly sensible way, but I can't change that.

You want group_concat():
select customerId, age, group_concat(hobby) as hobbies
from t
group by customerId, age

Related

MySQL - Is there a better way to structure one of my table to reduce the amount of columns?

I have a (3x3) table on my website which gives the users the option to unlock a car slot, purchase a car and upgrade the car level.
In total I end up with 9 slots, all 9 slots can have different values (car_unlocked (bool), car_level (int), car_type (int)).
my current table : (user_cars)
id (AUTO_INCR) | user_id | car_slot_unlocked01 | car_level01 | car_type01 | car_slot_unlocked02 | car_level02 | car_type02 | car_slot_unlocked03 | car_level03 | car_type03 | car_slot_unlocked04 | car_level04 | car_type04 …
And so on until 9. I end up with 29 columns. And then I retrieve the values with the user_id on my website. Values are unique to every user.
How would I go about reducing the columns amount, because if I was to add more rows (4x4) or (5x5) to my website table I would end up with alot more columns in my database.
Do I create different db table and join it if that is even an option?
Thank you in advance.
Maybe you can give an ID to the cars so you don't need the repeating columns... something like:
id | user_id | car_id | car_slow_unlocked | car_level | car_type
-----------------------------------------------------------------
1 | 001 | 01 | 1 | 3 | 3
2 | 001 | 02 | 0 | 5 | 2
3 | 001 | 03 | 0 | 5 | 3
4 | 001 | 04 | 1 | 6 | 1
5 | 001 | 05 | 1 | 1 | 1
6 | 001 | 06 | 0 | 5 | 2
7 | 001 | 07 | 0 | 5 | 3
8 | 001 | 08 | 1 | 6 | 1
9 | 001 | 09 | 1 | 1 | 1
10 | 002 | 01 | 1 | 5 | 3
11 | 002 | 02 | 0 | 3 | 1
12 | 002 | 03 | 1 | 1 | 1
... and so on
Seems like you need to have a think about your data model. I don't quite understand your business but start with identifying the entities and their attributes outside of any presentation concerns.
e.g.
CarInstance (ID, type, unlocked)
CarType(ID, CarID, Level)
User(ID, name)
UserToCar(userID,carID)
I doubt those are right but that's the kind of thing you need to be aiming for. You can then generate your table from that.

How to identify entries that have not changed over time?

I am trying to identify names that have not had a total score change over a period of time, and what that period of time was.
Example Table:
+----------+--------+-------+
| Date | Name | Score |
+----------+--------+-------+
| 1/1/2016 | Frank | 55 |
| 1/1/2016 | John | 80 |
| 1/2/2016 | Frank | 60 |
| 1/2/2016 | John | 85 |
| 1/3/2016 | Frank | 60 |
| 1/3/2016 | John | 100 |
| 1/4/2016 | Frank | 60 |
| 1/4/2016 | John | 120 |
| 1/5/2016 | Frank | 60 |
| 1/5/2016 | John | 120 |
+----------+--------+-------+
Expected Output:
+-------+------+
| Name | Days |
+-------+------+
| Frank | 4 |
| John | 2 |
+-------+------+
I have been trying to puzzle out how to do this with no success. I have no code to show since none of it has even been close to successful and would only serve to clutter up the question.
How can I go about doing this?
You need to group the data with the score, and then calculate the first and last day that the user has that score, check this:
SELECT DATEDIFF(last_day, first_day) + 1 AS days, name, score,
first_day, last_day
FROM (
SELECT
max(date_score) as last_day,
min(date_score) as first_day,
score,
name
FROM members
GROUP by score
) AS score
The Date diff function return the difference between two DATE's, we add one to represent that the score last one day.
Check here for a working example link

Remove duplicates SQL while ignoring key and selecting max of specified column

I have the following sample data:
| key_id | name | name_id | data_id |
+--------+-------+---------+---------+
| 1 | jim | 23 | 098 |
| 2 | joe | 24 | 098 |
| 3 | john | 25 | 098 |
| 4 | jack | 26 | 098 |
| 5 | jim | 23 | 091 |
| 6 | jim | 23 | 090 |
I have tried this query:
INSERT INTO temp_table
SELECT
DISTINCT #key_id,
name,
name_id,
#data_id FROM table1,
I am trying to dedupe a table by all fields in a row.
My desired output:
| key_id | name | name_id | data_id |
+--------+-------+---------+---------+
| 1 | jim | 23 | 098 |
| 2 | joe | 24 | 098 |
| 3 | john | 25 | 098 |
| 4 | jack | 26 | 098 |
What I'm actually getting:
| key_id | name | name_id | data_id |
+--------+-------+---------+----------+
| 1 | jim | 23 | NULL |
| 2 | joe | 24 | NULL |
| 3 | john | 25 | NULL |
| 4 | jack | 26 | NULL |
I am able to dedupe the table, but I am setting the 'data_Id' value to NULL by attempting to override the field with '#'
Is there anyway to select distinct on all fields and while keeping the value for 'data_id'? I will take the highest or MAX data_id # if possible.
If you only want one row returned for a specific value (in this case, name), one option you have is to group by that value. This seems like a good approach because you also said you wanted the largest data_id for each name, so I would suggest grouping and using the MAX() aggregate function like this:
SELECT name, name_id, MAX(data_id) AS data_id
FROM myTable
GROUP BY name, name_id;
The only thing you should be aware of is the possibility that a name occurs multiple times under different name_ids. If that is possible in your table, you could group by the name_id too, which is what I did.
Since you stated you're not interested in the key_id but only the name, I just excluded it from the query altogether to get this:
| name | name_id | data_id |
+-------+---------+---------+
| jim | 23 | 098 |
| joe | 24 | 098 |
| john | 25 | 098 |
| jack | 26 | 098 |
Here is the SQL Fiddle example.
RENAME TABLE myTable to Old_mytable,
myTable2 to myTable
INSERT INTO myTable
SELECT *
FROM Old_myTable
GROUP BY name, name_id;
This groups my tables by the values I want to dedupe while still keeping structure and ignoring the 'Data_id' column

What does group by do exactly ?

From an example taken from here , I'm trying to understand what does GROUP BY do exactly :
Given this employee table :
+-------+----------+--------+------------+
| Empid | Empname | Salary | DOB |
+-------+----------+--------+------------+
| 1 | Habib | 2014 | 2004-12-02 |
| 2 | Karan | 4021 | 2003-04-11 |
| 3 | Samia | 22 | 2008-02-23 |
| 4 | Hui Ling | 25 | 2008-10-15 |
| 5 | Yumie | 29 | 1999-01-26 |
+-------+----------+--------+------------+
After executing mysql> select * from employee group by empname;
We get :
+-------+----------+--------+------------+
| Empid | Empname | Salary | DOB |
+-------+----------+--------+------------+
| 1 | Habib | 2014 | 2004-12-02 |
| 4 | Hui Ling | 25 | 2008-10-15 |
| 2 | Karan | 4021 | 2003-04-11 |
| 3 | Samia | 22 | 2008-02-23 |
| 5 | Yumie | 29 | 1999-01-26 |
+-------+----------+--------+------------+
So , does that mean that GROUP BY just sorts a table by key ?
Thanks
GROUP BY enables summaries. Specifically, it controls the use of summary functions like COUNT(), SUM(), AVG(), MIN(), MAX() etc. There isn't much to summarize in your example.
But, suppose you had a Deptname column. Then you could issue this query and get the average salary by Deptname.
SELECT AVG(Salary) Average,
Deptname
FROM Employee
GROUP BY Deptname
ORDER BY Deptname
If you want your result set put in a certain order, use ORDER BY.

MYSQL, Duplicating records but changing a column's value

I'm trying to write an SQL statement that duplicates all rows WHERE employee = 16(i.e.), but the new rows would have a different employee value.
Table before INSERT:
| employee | property_name | property_value |
|:--------:|:--------------|:---------------|
| 16 | Salary | 28,000 |
| 16 | Department | 12 |
| 17 | Salary | 38,000 |
| 17 | Department | 8 |
Desired outcome after INSERT:
| employee | property_name | property_value |
|:--------:|:--------------|:---------------|
| 16 | Salary | 28,000 |
| 16 | Department | 12 |
| 17 | Salary | 38,000 |
| 17 | Department | 8 |
| 18 | Salary | 28,000 |
| 18 | Department | 12 |
I've seen some threads that use variables. Could I set and reference a variable somehow that would replace values from an insert/select?
The answer to this thread looks like it would work. But I'd rather not create and drop tables like that.
insert into YourTable (employee,property_name, property_value)
select 18, property_name, property_value from YourTable where employee = 16