Convert MySQL table from vertical to horizontal based on id column - mysql

I have a table like below
id | main_id | image
1 | 10 | 52343.jpg
2 | 10 | 52344.jpg
3 | 10 | 52345.jpg
4 | 11 | 52346.jpg
5 | 11 | 52347.jpg
6 | 11 | 52348.jpg
7 | 11 | 52349.jpg
8 | 12 | 52350.jpg
9 | 12 | 52351.jpg
i want output like this :
id | main_id | image1
1 | 10 | 52343.jpg, 52344.jpg, 52345.jpg
2 | 11 | 52346.jpg, 52347.jpg, 52348.jpg, 52349.jpg
3 | 12 | 52350.jpg, 52351.jpg
Just all images with same main_id to be in one row.

use group_concat()
select main_id,group_concat(image)
from tablename
group by main_id

Related

Get Percentages of Tables with Group by

I am working on a prediction game for a local league.
A Match is defined by its SPIELTAG (playday) and its MATCH_NR.
A prediction has a Match and a result (ERGA, ERGB)
I have a Table like in this fiddle https://www.db-fiddle.com/f/o4NXPFfzod39LpMaTzqz3r/0
I got the output to count each result per gameday and per match.
| SPIELTAG | MATCH_NR | ERGA | ERGB | AMOUNT |
| -------- | -------- | ---- | ---- | ------ |
| 4 | 1 | 7 | 1 | 1 |
| 4 | 1 | 7 | 2 | 2 |
| 4 | 1 | 7 | 3 | 5 |
| 4 | 1 | 7 | 4 | 1 |
| 4 | 2 | 1 | 7 | 1 |
| 4 | 2 | 2 | 7 | 6 |
| 4 | 2 | 3 | 7 | 3 |
What i am trying to achieve is, next to the amount column something like
| SPIELTAG | MATCH_NR | ERGA | ERGB | AMOUNT | PERC |
| -------- | -------- | ---- | ---- | ------ | ---- |
| 4 | 1 | 7 | 1 | 1 | 11.1%| => 1 / 9
| 4 | 1 | 7 | 2 | 2 | 22.2%| => 2 / 9
| 4 | 1 | 7 | 3 | 5 | 55.5%| => 5 / 9
| 4 | 1 | 7 | 4 | 1 | 11.1%| => 1 / 9
| 4 | 2 | 1 | 7 | 1 | 11.1%| => 1 / 9
| 4 | 2 | 2 | 7 | 5 | 55.5%| => 5 / 9
| 4 | 2 | 3 | 7 | 3 | 33.3%| => 3 / 9
Where PERC is the percentage of picks per playday SPIELTAG. Basically how often is the Result, the tuple of (ERGA, ERGB) predicted for each match SPIELTAG, MATCH_NR.
I found a post where i can get the percentage over all picks but not restricted on the gameday,match tuple.
An Example:
Match 1 (Spieltag 4, Match 1) has 9 Predictions.
1x: 7-1
2x: 7-2
5x: 7-3
1x: 7-4
__
9x -> ALL_COUNTS_PER_MATCH
So PERC should be something like 'AMOUNT' / ALL_COUNTS_PER_MATCH.
I think you need another group by:
SELECT `t`.`SPIELTAG` AS `SPIELTAG`,
`t`.`MATCH_NR` AS `MATCH_NR`,
`t`.`TEAM_A` AS `ERGA`,
`t`.`TEAM_B` AS `ERGB`,
count(0) AS `AMOUNT`,
COUNT(0) / MAX(A.TOTAL_AMOUNT) -- MIN would also work
FROM `TIPPSPIEL_TIPP` `t`
JOIN (
-- Calculate the row count by each different spieltag & match_nr combination
SELECT `t`.`SPIELTAG`,
`t`.`MATCH_NR`,
count(0) AS `TOTAL_AMOUNT`
FROM `TIPPSPIEL_TIPP` `t`
GROUP BY `t`.`SPIELTAG`, `t`.`MATCH_NR`
) A USING (SPIELTAG, MATCH_NR)
GROUP BY `t`.`SPIELTAG`, `t`.`MATCH_NR`, `t`.`TEAM_A`, `t`.`TEAM_B`
;
https://www.db-fiddle.com/f/o4NXPFfzod39LpMaTzqz3r/3
Check this, but will work in Mysql 8, not lower versions
https://www.db-fiddle.com/f/o4NXPFfzod39LpMaTzqz3r/4
SELECT DISTINCT `t`.`SPIELTAG` AS `SPIELTAG`,
`t`.`MATCH_NR` AS `MATCH_NR`,
`t`.`TEAM_A` AS `ERGA`,
`t`.`TEAM_B` AS `ERGB`,
COUNT(0) OVER (PARTITION BY `t`.`SPIELTAG`,
`t`.`MATCH_NR`,
`t`.`TEAM_A`,
`t`.`TEAM_B`) AS AMOUNT,
COUNT(0) OVER (PARTITION BY `t`.`SPIELTAG`,
`t`.`MATCH_NR`,
`t`.`TEAM_A`,
`t`.`TEAM_B`) / COUNT(CONCAT(SPIELTAG, MATCH_NR)) OVER (PARTITION BY `t`.`SPIELTAG`,
`t`.`MATCH_NR`) AS match_count
FROM `TIPPSPIEL_TIPP` `t`

Filtering Column based on values on Another table

I'am tying to get the specific columns whose name starts with some patterns.
table_1
abcA| abcB | abcC | xyD | mnE
1 | 2 | 3 | 4 | 5
6 | 7 | 8 | 9 | 10
11 | 12 | 13 | 14 | 15
From the above table i'am in need of the Output Like
abcA | abcB | abcC
1 | 2 | 3
6 | 7 | 8
11 | 12 | 13
The columns should be selected DYNAMICALLY by filtering like any column name starts with abc should me selected.
I Tried this Query
"select column_name from information_schema.columns
where table_name='table_1' and column_name like 'abc%';"
It gives a another table only with column names
column_name
abcA
abcB
abcC
But I want to get the values of that Column names.
Thanks
This is poor table design, and it is fairly difficult to write code which can select a dynamic column name. Here is the design I would suggest to you:
ID | name | pos
1 | abcA | 1
2 | abcB | 1
3 | abcC | 1
4 | xyD | 1
5 | mnE | 1
6 | abcA | 2
7 | abcB | 2
8 | abcC | 2
9 | xyD | 2
10 | mnE | 2
11 | abcA | 3
12 | abcB | 3
13 | abcC | 3
14 | xyD | 3
15 | mnE | 3
With this design in place, you only need a very simple query:
SELECT pos, GROUP_CONCAT(ID) AS ids
FROM yourTable
WHERE name LIKE 'abc%'
GROUP BY pos;

How to get this specific user rankings query in mysql?

I've got tbl_items in my user database that I want to sort user rankings on a particular item with certain id (514). I have test data on my dev environment with this set of data:
mysql> select * from tbl_items where classid=514;
+---------+---------+----------+
| ownerId | classId | quantity |
+---------+---------+----------+
| 1 | 514 | 3 |
| 2 | 514 | 5 |
| 3 | 514 | 11 |
| 4 | 514 | 46 |
| 5 | 514 | 57 |
| 6 | 514 | 6 |
| 7 | 514 | 3 |
| 8 | 514 | 27 |
| 10 | 514 | 2 |
| 11 | 514 | 73 |
| 12 | 514 | 18 |
| 13 | 514 | 31 |
+---------+---------+----------+
12 rows in set (0.00 sec)
so far so good :) I wrote the following query:
set #row=0;
select a.*, #row:=#row+1 as rank
from (select a.ownerid,a.quantity from tbl_items a
where a.classid=514) a order by quantity desc;
+---------+----------+------+
| ownerid | quantity | rank |
+---------+----------+------+
| 11 | 73 | 1 |
| 5 | 57 | 2 |
| 4 | 46 | 3 |
| 13 | 31 | 4 |
| 8 | 27 | 5 |
| 12 | 18 | 6 |
| 3 | 11 | 7 |
| 6 | 6 | 8 |
| 2 | 5 | 9 |
| 7 | 3 | 10 |
| 1 | 3 | 11 |
| 10 | 2 | 12 |
+---------+----------+------+
12 rows in set (0.00 sec)
that ranks correctly the users. However in a table with lots of records, I need to do the following:
1) be able to get small portion of the list, around where the user ranking actually resides, something that would get me the surrounding records, preserving the overall rank:
I tried to do these things with setting a user variable to the ranking of the current user and by using offset and limit, but couldn't preserve the overall ranking.
This should get me something like the following (for instance ownerId=2 and surroundings limit 5:
+---------+----------+------+
| ownerid | quantity | rank |
+---------+----------+------+
| 3 | 11 | 7 |
| 6 | 6 | 8 |
| 2 | 5 | 9 | --> ownerId=2
| 7 | 3 | 10 |
| 1 | 3 | 11 |
+---------+----------+------+
5 rows in set (0.00 sec)
2) I'd also need another query (preferably single query) that gets me the top 3 places + the ranking of particular user with certain id, preferably with a single query, no matter if he's among the top 3 places or not. I couldn't get this as well
It would look like the following (for instance ownerId=2 again):
+---------+----------+------+
| ownerid | quantity | rank |
+---------+----------+------+
| 11 | 73 | 1 |
| 5 | 57 | 2 |
| 4 | 46 | 3 |
| 2 | 5 | 9 | --> ownerId=2
+---------+----------+------+
4 rows in set (0.00 sec)
Also I'm in a bit of a concern about the performance of the queries on a table with millions of records...
Hope someone helps :)
1) 5 entries around a given id.
set #row=0;
set #rk2=-1;
set #id=2;
select b.* from (
select a.*, #row:=#row+1 as rank, if(a.ownerid=#id, #rk2:=#row, -1) as rank2
from (
select a.ownerid,a.quantity
from tbl_items a
where a.classid=514) a
order by quantity desc) b
where b.rank > #rk2 - 3
limit 5;
Though you'll get an extra column rank2: you probably want to filter it out by explicit list of columns instead of b.*. Maybe it's possible whith a having clause rather than an extra nesting.
2) 3 top ranked entries + 1 specific id
select b.* from (
select a.*, #row:=#row+1 as rank
from (
select a.ownerid,a.quantity
from tbl_items a
where a.classid=514) a
order by quantity desc) b
where b.rank < 4 or b.ownerid=#id

How should I write this MySQL query containing multiple Left Joins

I have a query consisting of multiple joins and I am wondering whether it can be re-written to improve performance.
I have 2 tables as follows (I have removed non-important columns for this example):
slots
------------------------------------------
| id | name | slot_1 | slot_2 | slot_3 |
------------------------------------------
| 1 | Bob | 1 | 2 | 3 |
| 2 | Jim | 4 | 3 | 3 |
| 3 | Alf | 1 | 2 | 5 |
------------------------------------------
(There are 25 slots in total, each in it's own column)
slot_details
-----------------------------------
| id | stat_1 | stat_2 | stat_3 |
-----------------------------------
| 1 | 1 | 5 | 6 |
| 2 | 4 | 31 | 23 |
| 3 | 6 | 5 | 7 |
| 4 | 7 | 4 | 9 |
| 5 | 2 | 3 | 5 |
-----------------------------------
(There are 10 stats in total)
The query is as follows:
SELECT
slots.name,
slot_1_details.stat_1 AS slot_1_stat_1,
slot_1_details.stat_2 AS slot_1_stat_2,
slot_1_details.stat_3 AS slot_1_stat_3,
slot_2_details.stat_1 AS slot_2_stat_1,
slot_2_details.stat_2 AS slot_2_stat_2,
slot_2_details.stat_3 AS slot_2_stat_3,
slot_3_details.stat_1 AS slot_3_stat_1,
slot_3_details.stat_2 AS slot_3_stat_2,
slot_3_details.stat_3 AS slot_3_stat_3
FROM
slots
LEFT JOIN
slot_details AS slot_1_details
ON (
slot_1_details.id = slots.slot_1
)
LEFT JOIN
slot_details AS slot_2_details
ON (
slot_2_details.id = slots.slot_2
)
LEFT JOIN
slot_details AS slot_3_details
ON (
slot_3_details.id = slots.slot_3
)
WHERE (
slots.id = 1
)
The expected outcome of this query would be as follows:
| name | slot_1_stat_1 | slot_1_stat_2 | slot_1_stat_3 | slot_2_stat_1 | slot_2_stat_2 | slot_2_stat_3 | slot_3_stat_1 | slot_3_stat_2 | slot_3_stat_3 |
|bob | 1 | 5 | 6 | 4 | 31 | 23 | 6 | 5 | 7 |
Unfortunately I am not in a situation where I can change the tables.
Thank you for the help!
maybe
SELECT * FROM slots s LEFT JOIN slot_details sd ON s.id=sd.id
but i'm not sure because the query you posted is very confusing.
what are the keys of those tables?

select random value from each type

I have two tables, rating:
+-----------+-----------+-------------+----------+
| rating_id | entity_id | rating_code | position |
+-----------+-----------+-------------+----------+
| 1 | 1 | Quality | 0 |
| 2 | 1 | Value | 0 |
| 3 | 1 | Price | 0 |
+-----------+-----------+-------------+----------+
And rating_option
+-----------+-----------+------+-------+----------+
| option_id | rating_id | code | value | position |
+-----------+-----------+------+-------+----------+
| 1 | 1 | 1 | 1 | 1 |
| 2 | 1 | 2 | 2 | 2 |
| 3 | 1 | 3 | 3 | 3 |
| 4 | 1 | 4 | 4 | 4 |
| 5 | 1 | 5 | 5 | 5 |
| 6 | 2 | 1 | 1 | 1 |
| 7 | 2 | 2 | 2 | 2 |
| 8 | 2 | 3 | 3 | 3 |
| 9 | 2 | 4 | 4 | 4 |
| 10 | 2 | 5 | 5 | 5 |
| 11 | 3 | 1 | 1 | 1 |
| 12 | 3 | 2 | 2 | 2 |
| 13 | 3 | 3 | 3 | 3 |
| 14 | 3 | 4 | 4 | 4 |
| 15 | 3 | 5 | 5 | 5 |
+-----------+-----------+------+-------+----------+
I need a SQL query (not application level, must stay in the database) which will select a set of ratings randomly. A sample result would look like this, but would pick a random value for each rating_id on subsequent calls:
+-----------+-----------+------+-------+----------+
| option_id | rating_id | code | value | position |
+-----------+-----------+------+-------+----------+
| 1 | 1 | 1 | 1 | 1 |
| 8 | 2 | 3 | 3 | 3 |
| 15 | 3 | 5 | 5 | 5 |
+-----------+-----------+------+-------+----------+
I'm totally stuck on the random part, and grouping by rating_id has been a crap shoot so far. Any MySQL ninjas want to take a stab?
Thanks,
Joe
EDIT: I've tried rand() in a bunch of combinations, and I'm sure that it will be necessary to create the randomness of the result, but I cannot figure out how to return one random row for each of the rows in rating. I cannot use order by rand() limit 1 because I need three rows, and order by rand() limit 3 won't give me one of each rating_id, which is the ultimate goal. I need a combination of rand() and either subqueries or joins so that I can ensure one of each rating_id.
Alright, a little messy, but seems to do the job. Someone may know what they're doing better than I do that can clean this up:
SELECT random.rating_id, random.rand_option_id, r3.code, r3.value, r3.position
FROM
(SELECT r.rating_id,
(SELECT r2.option_id
FROM rating_option r2
WHERE r2.rating_id = r.rating_id
ORDER BY RAND() LIMIT 1) AS 'rand_option_id'
FROM rating_option r
GROUP BY r.rating_id
) random
LEFT JOIN rating_option AS r3 ON r3.option_id = rand_option_id
Results (varies every time, of course):
+-----------+----------------+------+-------+----------+
| rating_id | rand_option_id | code | value | position |
+-----------+----------------+------+-------+----------+
| 1 | 4 | 4 | 4 | 4 |
| 2 | 6 | 1 | 1 | 1 |
| 3 | 13 | 3 | 3 | 3 |
+-----------+----------------+------+-------+----------+
You could use the rand() function to do sorting in a select on the rating table.
For example:
select rating_id from rating order by rand() limit 1
As clarified in your comments, and the other posts above
select * from rating_option order by rand()
will return all records in a random order... However, if you want only X number, then inclue that as the limit as noted by others
select * from rating_option order by rand() limit 5 (or whatever number)
Have you looked into the rand() function?
SELECT column FROM table
ORDER BY RAND()
LIMIT 1
http://www.petefreitag.com/item/466.cfm
http://dev.mysql.com/doc/refman/5.0/en/mathematical-functions.html#function_rand
Sample code
select *
from rating_option
group by rating_id
order by rand()