MySQL: Performance Querying Multiple Columns With a Single Row - mysql

My tables simplified something like this..
Table Categories
cat_id | cat_name
-------------------
1 | Baseball
2 | Hockey
3 | Football
Table Day
day_id | day_name
--------------------
1 | Friday
2 | Saturday
3 | Sunday
Table Day_Categories
day_id | cat_id
-------------------
1 | 1
1 | 2
2 | 2
2 | 3
3 | 1
3 | 2
3 | 3
And I want my resulting data to look something like this...
"Friday","Baseball, Hockey"
"Saturday","Hockey, Football"
"Sunday", "Baseball, Hockey, Football"
It doesn't necessary need to be in three row format. I just need the same resulting data.
From a performance prospective with lots of data what's likely the best way to achieve this result?

Please try this one
SELECT day_name, GROUP_CONCAT ( cat_name ) as categories
FROM Days as d
LEFT JOIN Days_Categories as dnc ON d.day_id = dnc.day_id
LEFT JOIN Categories as c ON c.cat_id = dnc.cat_id
GROUP BY ( dnc.day_id)

Related

How can I determine a score result based on the goal count in mysql?

Maybe this question is super specific but I can't really find a way to do it.
A bit of background. I'm studying, and In order to learn this I'm playing around counting stats from our Wednesday football matches with my friends.
Now in order to make data as normalized as possible and calculate everything programmatically, I have a table called matches and a table called goals.
Matches
+----+------------+
| id | date |
+----+------------+
| 1 | 05-01-2022 |
+----+------------+
| 2 | 12-01-2022 |
+----+------------+
Goals
+----+--------------+
| id | match | team |
+----+--------------+
| 1 | 1 | A |
+----+--------------+
| 2 | 1 | B |
+----+--------------+
| 3 | 1 | B |
+----+--------------+
| 4 | 2 | A |
+----+--------------+
| 5 | 2 | A |
+----+--------------+
So my objective here is to count the goals for each team in each match, compare both values to determine the winner and come up with a result like this:
Results
+-------+------------+
| match | result |
+-------+------------+
| 1 | B |
+-------+------------+
| 2 | A |
+-------+------------+
I'm currently doing this fairly straightforward using laravel on my app, but I'm trying to get it done through SQL queries only.
I also know that this would be much easier, if i simply added a goals_team_a, goals_team_b, result columns to my Matches table. If this is the actual correct solution is super easy to add, I just though at some point goals may differ from the score because of a typo or something and this is the way to be extra sure. Probably an overkill
The current structure of matches and goals is definitely flawed. If a given match id has no goals scored by either side there is no record of who played. By simply adding home and away teams to the match you have a more meaningful match entity and it becomes simple to query for the result.
Matches
id
kick_off
home_team_id
away_team_id
1
2022-01-05 10:00:00
1
2
2
2022-01-12 14:30:00
2
1
Teams
id
name
1
A
2
B
Additionally, if your goals table is as simple as suggested, it serves no purpose but I suspect this was simplification for the sake of providing an example. Assuming there is a player and time goal scored as part of the goal table, it has obvious value.
Goals
id
match_id
team_id
player_id
time_scored
1
1
1
1
10:01:23
2
1
2
2
10:17:38
3
1
2
2
11:02:44
4
2
1
1
15:42:53
5
2
1
1
15:47:18
With the teams identified in the match you can then use something like -
select m.id as match_id,
case
when count(distinct hg.id) > count(distinct ag.id) then ht.name
when count(distinct hg.id) < count(distinct ag.id) then at.name
else 'draw'
end as `result`
from matches m
join teams ht on m.home_team_id = ht.id
join teams at on m.away_team_id = at.id
left join goals hg on m.home_team_id = hg.team_id and m.id = hg.match_id
left join goals ag on m.away_team_id = ag.team_id and m.id = ag.match_id
group by m.id
to get -
match
result
1
B
2
A
Here's a db<>fiddle to play around with.

I am not sure what is wrong with my MySQL GROUP_CONCAT query...can you solve it for me please?

I have a MySQL problem which i can't figure out the solution.
I have 2 tables
Table 1-[Book] table
book id | categories | title |
1 | 1,3,5 | Book 1 |
2 | 2,4 | Book 2 |
3 | 1,4 | Book 3 |
Table 2-[Category] table
category id | category name
1 | Technology
2 | Accounting
3 | Science
4 | Math
5 | Chemistry
I need the result to show up like this
RESULT
book id | categories | title | category name
1 | 1,3,5 | Book 1 | Technology,Science,Chemistry
2 | 2,4 | Book 2 | Accounting,Math
3 | 1,4 | Book 3 | Technology,Math
I tried the below query but i'm not sure what's wrong with it.
SELECT DISTINCT t1.*,(SELECT GROUP_CONCAT(t2.categoryName) FROM `tbl_category` t2 WHERE t2.id IN (t1.categories)) catColumn FROM tbl_books t1 ORDER BY t1.id DESC
If I execute the below query, it is returning the correct values that I need:
SELECT GROUP_CONCAT(categoryName) FROM `tbl_category` t2 WHERE t2.id IN (1,3,5)
RESULT:
Technology,Science,Chemistry
Your first effort should go into fixing your schema. You should have a separate table to store the book/category relations, with each tuple in a separate table row. Storing delimited lists in a database table is bad design, and should be always be avoided: see this famous SO question for more details.
For your current set up though, I would recommend a correlated subquery with find_in_set():
select
b.*,
(
select group_concat(c.category_name)
from category c
where find_in_set(c.id, b.categories)
) category_names
from book b
To echo others, the first thing I would do is make a minor change to your table structure and de-couple books from categories, like this:
TABLE BOOK
book id | title |
1 | Book 1 |
2 | Book 2 |
3 | Book 3 |
TABLE CATEGORY
category id | category name
1 | Technology
2 | Accounting
3 | Science
4 | Math
5 | Chemistry
TABLE BOOK_CATEGORY
id | book_id | category_id
1 | 1 | 1
2 | 1 | 3
3 | 1 | 5
4 | 2 | 2
5 | 2 | 4
6 | 3 | 1
7 | 3 | 4
Finally, to achieve your desired result, execute the following query:
SELECT
b.book_id,
group_concat(bc.category_id order by bc.category_id) AS category_id,
b.title,
group_concat(c.category_name) AS category_name
FROM
book b
INNER JOIN
book_category bc ON b.book_id = bc.book_id
INNER JOIN
category c ON c.category_id = bc.category_id
GROUP BY
book_id;

mysql sum and count per category append to matching category rows

I am trying to derive a MySQL query that turns this:
product | sold
milk | 6
milk | 4
bread | 3
bread | 2
bread | 2
to this;
product | sold | total order | Total sold
milk | 2 | 2 | 6
milk | 4 | 2 | 6
bread | 3 | 3 | 7
bread | 2 | 3 | 7
bread | 2 | 3 | 7
I've been able to get the queries for sums and counts no problem, but I cannot seem to get it to join as a new column matching the product. Is this even possible? I've tried WITH ROLLUP but it just creates another row, not exactly what I want.
You could join a simple query on this table with an aggregate query on:
SELECT a.product, a.sold, b.total_order, b.total_sold
FROM mytable a
JOIN (SELECT product, COUNT(*) AS total_order, SUM(sold) AS total_sold
FROM mytable
GROUP BY product) b ON a.product = b.product

Selecting items that have same values in the same column

I am facing a conundrum; not sure why -- is it because this late, or I am just stuck. My goal is to create a filter on the webpage, so I am trying to figure this out.
I have a list of products that I store with filters in the reference table product_filter.
The structure:
id | product_id | filter1_id | filter2_id
1 | 1 | 2 | 1 <---
2 | 1 | 4 | 3
3 | 1 | 5 | 1
4 | 2 | 2 | 1 <---
5 | 2 | 3 | 1
6 | 3 | 2 | 1 <---
7 | 3 | 3 | 4
I need to submit a list of products (for example 1,2,3) and get only those filter combinations, that are the same for all selected product id's. So the result needs to be
filter1_id | filter2_id
2 | 1
My problem is that my products might vary and I can't do a ton of self inner joins... so I am stuck... Any advise?
Here is one approach that you could try:
select filter1_id, filter2_id
from product_filter
group by filter1_id, filter2_id
having count(*)=(
select count(distinct product_id)
from product_filter
)
This will only return a list when a combination of filter1_id and filter2_id exists for every product_id. (Fiddle here.) Is that what you are after? Do you don't mention what should be returned if there isn't any combination that exists for all of the given product_id's - an empty result set?
It's not a self-join (or even a ton of them ;) ) but it will still be fairly expensive I imagine.

Sql SUM over products of grouped elements

I have the following data structure:
Table 1(groups):
ID | Group
=============
1 | Sample
2 | Data
Table 2(items):
ID | GroupID | Cost | Amount
==============================
1 | 1 | 1 | 12
2 | 1 | 7 | 15
3 | 1 | 3 | 8
4 | 2 | 2 | 12
And would like the following (query) results:
groups.ID | groups.Name | total
1 | Sample | 141
2 | Data | 24
total is the sum over the products of cost and amount of all items in the group i.e. for group 1: 1*12+7*15+3*8=141
Im guessing I have to something with
SELECT g.ID, g.Group, SUM(Products)
FROM groups AS g, items AS i
WHERE g.ID=i.GroupID
GROUP BY i.GroupID
But don't know what exactly.
Doing iit in clientsoftware with loops is no problem, but I am curious (and certain) that this can be done in (my)Sql
SELECT g.ID as ID, g.Group as Name, SUM(i.Cost * i.Amount) as total
FROM groups g
INNER JOIN items i ON i.GroupID = g.ID
GROUP BY g.Group, g.ID
Having a field named "Group" is quite a bad idea in SQL (reserved keyword)