SQL consolidate data and turn them into columns - mysql

So here's what my data table looks like:
TeamNum Round Points1 Points2
1 1 5 21
2 1 10 20
3 1 9 29
1 2 6 22
2 2 11 21
3 2 10 30
1 3 80 50
I also have a second table with this:
TeamNum TeamName
1 goteam1
2 goteam2
3 goteam4-1
I want SQL to take it and turn it into this:
Team Round1 Round2 Round3 TeamName
1 (points1+points2 of round1) (same but for r2) (same but for r3) goteam1
2 (points1+points2 of round1) (same but for r2) (same but for r3) goteam2
3 (points1+points2 of round1) (same but for r2) (same but for r3) goteam4-1
And a sample output from the tables above would be:
Team Round1 Round2 Round3 TeamName
1 26 28 130 goteam1
2 30 32 0 goteam2
3 38 40 0 goteam4-1
The actual data has a bunch of "points1" and "points2" columns, but there are only 3 rounds.
I am very new to SQL and this is all I have right now:
select
`data`.`round`,
`data`.`teamNumber`,
sum(`Points1`) + sum(`Points2`) as score
from `data` join `teams` ON `teams`.`teamNumber` = `data`.`teamNumber`
group by `data`.`teamNumber` , `round`
order by `data`.`teamNumber`, `data`.`round`
But it doesn't return anything at all. If I remove the join statement, it shows everything like I want, but doesn't consolidate Round1, 2, and 3 as columns, they are each separate rows. Can you guys help me out? Thanks!

Use conditional aggregation
SELECT t.teamnumber, t.teamname,
SUM(CASE WHEN d.round = 1 THEN d.points1 + d.points2 ELSE 0 END) round1,
SUM(CASE WHEN d.round = 2 THEN d.points1 + d.points2 ELSE 0 END) round2,
SUM(CASE WHEN d.round = 3 THEN d.points1 + d.points2 ELSE 0 END) round3
FROM data d JOIN teams t
ON d.teamnumber = t.teamnumber
GROUP BY t.teamnumber, t.teamname
Output:
| TEAMNUMBER | TEAMNAME | ROUND1 | ROUND2 | ROUND3 |
|------------|-----------|--------|--------|--------|
| 1 | goteam1 | 26 | 28 | 130 |
| 2 | goteam2 | 30 | 32 | 0 |
| 3 | goteam4-1 | 38 | 40 | 0 |
Here is SQLFiddle demo

No need to aggregate:
SELECT
t.teamnumber,
COALESCE(r1.points1 + r1.points2, 0) AS round1,
COALESCE(r2.points1 + r2.points2, 0) AS round2,
COALESCE(r3.points1 + r3.points2, 0) AS round3,
t.teamname
FROM teams t
LEFT JOIN data r1 ON r1.teamnumber = t.teamnumber AND r1.round = 1
LEFT JOIN data r2 ON r2.teamnumber = t.teamnumber AND r2.round = 2
LEFT JOIN data r3 ON r3.teamnumber = t.teamnumber AND r3.round = 3

Something like this:
select teams.teamNumber,
SUM(CASE WHEN Round=1 THEN `Points1`+`Points2` ELSE 0 END)as Round1,
SUM(CASE WHEN Round=2 THEN `Points1`+`Points2` ELSE 0 END)as Round2,
SUM(CASE WHEN Round=3 THEN `Points1`+`Points2` ELSE 0 END)as Round3,
teams.teamName
from `data` join `teams` ON `teams`.`teamNumber` = `data`.`teamNumber`
group by teamnumber , teamname
order by `data`.`teamNumber`, `data`.`round`

Related

Inner Selection, Sum of colunms with conditions order by Region

After selection I get my new clear table like
SELECT a.sta_name, a.product, a.product_id, a.date, a.active, a.region_id, a.brand, a.brand_id from
(SELECT DISTINCT sta_name, product, product_id, date, active, region_id, brand, brand_id FROM `sv_ziyaret`
WHERE brand_id=2 and date between "2021-07-00" and "2021-07-31" order by region_id) a
so I get my values DISTINCT
sta_name | product | product_id | active | region_id | brand | brand_id| date |
3M A 1 1 1 A1 1 2021-07-02
2M A 1 0 1 A1 1 2021-07-02
5M B 2 0 1 A1 1 2021-07-05
4M B 2 0 2 A1 1 2021-07-06
M A 2 1 2 A1 1 2021-07-10
2M C 3 1 4 A1 1 2021-07-12
3M B 2 1 4 A1 1 2021-07-15
sta_name never repeats with same region_id, products do. What I try to get is
product_id | product | active_on | active_off | region_id
1 A 12 2 1
1 A 7 9 2
2 B 6 10 1
2 B 16 5 2
3 C 10 5 4
My main purpose is to be able to calculate percentage of product's existance in each region. In instance A product has %80 on sale on shalves at region A.
Manualy I am able to get each products result as
SELECT
product, product_id, region_id,
SUM(CASE WHEN sv_ziyaret.active = 1 THEN 1 ELSE 0 END) var,
SUM(CASE WHEN sv_ziyaret.active = 0 THEN 1 ELSE 0 END) yok
FROM
`sv_ziyaret`
WHERE
product_id=37 and date between "2021-07-00" and "2021-07-31" and region_id=7 order by region_id
but this is not a good solution I need it to be able to get each product by giving its brand_id only.
Hope to get a hand realy would same my weak
You are very close to the general solution. You just need GROUP BY AND LAST_DAY().
SELECT
product, product_id, region_id, LAST_DAY(date) month_ending,
SUM(CASE WHEN sv_ziyaret.active = 1 THEN 1 ELSE 0 END) var,
SUM(CASE WHEN sv_ziyaret.active = 0 THEN 1 ELSE 0 END) yok
FROM
sv_ziyaret
WHERE
GROUP BY product, product_id, region_id, LAST_DAY(date)
ORDER BY region_id, LAST_DAY(date), product_id;

MySQL which query statement should be used?

I have a dataset like this as shown below, for example row 1, 0 purchase is made for the item priced at $3, 3 purchases are made for item priced at $30. I would need to write a query to provide the summary of how many passes purchased, by categorising the prices into price range of "0-10", "11-20", "21-30", "31-40". I assume case when should be used but I am unsure of how. Please help.
+-----------------+-----------------+--------------------------+--------------------------+
| price_category1 | price_category2 | purchase_count_category1 | purchase_count_category2 |
+-----------------+-----------------+--------------------------+--------------------------+
| 3 | 30 | 0 | 3 |
| 20 | 6 | 1 | 4 |
| 25 | 11 | 4 | 0 |
| 17 | 12 | 0 | 1 |
+-----------------+-----------------+--------------------------+--------------------------+
+------+-------+-------+-------+
| 0-10 | 11-20 | 21-30 | 31-40 |
+------+-------+-------+-------+
| 4 | 2 | 7 | 0 |
+------+-------+-------+-------+
You can try below.
Working Solution
WITH MAIN
AS (SELECT 3 AS price_category1,
30 AS price_category2,
0 purchase_count_category1,
3 AS purchase_count_category2
FROM DUAL
UNION ALL
SELECT 20 AS price_category1,
6 AS price_category2,
1 purchase_count_category1,
4 AS purchase_count_category2
FROM DUAL
UNION ALL
SELECT 25 AS price_category1,
11 AS price_category2,
4 purchase_count_category1,
0 AS purchase_count_category2
FROM DUAL
UNION ALL
SELECT 17 AS price_category1,
12 AS price_category2,
0 purchase_count_category1,
1 AS purchase_count_category2
FROM DUAL),
M2
AS (SELECT price_category1 CAT, purchase_count_category1 CNT FROM MAIN
UNION
SELECT price_category2, purchase_count_category2 FROM MAIN)
SELECT CASE
WHEN CAT >= 0 AND CAT < 11 THEN '0-10'
WHEN CAT >= 11 AND CAT < 21 THEN '11-20'
WHEN CAT >= 21 AND CAT < 31 THEN '21-30'
END
CAT,
SUM (CNT) SUMM
FROM M2
GROUP BY CASE
WHEN CAT >= 0 AND CAT < 11 THEN '0-10'
WHEN CAT >= 11 AND CAT < 21 THEN '11-20'
WHEN CAT >= 21 AND CAT < 31 THEN '21-30'
END
SELECT SUM(CASE WHEN price_category1 BETWEEN 0 AND 10
THEN purchase_count_category1
END) + SUM(CASE WHEN price_category2 BETWEEN 0 AND 10
THEN purchase_count_category2
END) AS `0-10`,
SUM(CASE WHEN price_category1 BETWEEN 11 AND 20
THEN purchase_count_category1
END) + SUM(CASE WHEN price_category2 BETWEEN 11 AND 20
THEN purchase_count_category2
END) AS `11-20`,
SUM(CASE WHEN price_category1 BETWEEN 21 AND 30
THEN purchase_count_category1
END) + SUM(CASE WHEN price_category2 BETWEEN 21 AND 30
THEN purchase_count_category2
END) AS `21-30`
FROM source_table
or
SELECT SUM(CASE WHEN cat BETWEEN 0 AND 10
THEN cnt
END ) AS `0-10`,
SUM(CASE WHEN cat BETWEEN 11 AND 20
THEN cnt
END ) AS `11-20`,
SUM(CASE WHEN cat BETWEEN 21 AND 30
THEN cnt
END ) AS `21-30`
FROM ( SELECT price_category1 cat, purchase_count_category1 cnt
FROM source_table
UNION ALL
SELECT price_category2, purchase_count_category2
FROM source_table ) src
PS. This solution gives "horizontal" output - one row with all needed statistic. If you need "vertical" output then use the solution provided by ismetguzelgun.
Pay attention - my solution is not extendable (if you need to alter the ranges amount or borders you must alter the query text) whereas alternative solution can be extended easily after converting hardcoded ranges borders to according CTE or (the best) additional criteria table.

How to update the same row with condition in MySql?

Here's data
KeyID | Queue | Pay
65 1 0
60 2 0
58 3 1
57 4 1
55 5 0
54 6 0
53 7 1
50 8 1
if the data like this , I need a single MySql query to update it to be like below data table which update only Queue column.
KeyID | Queue | Pay
65 0 0
60 0 0
58 1 1
57 2 1
55 0 0
54 0 0
53 3 1
50 4 1
I have try this
update tabl1
set Queue = case when Pay = 0 then Queue=Queue-1 else Queue
But Queue number not look like this.
Please suggest.
Thank you in advance
We can try joining to a subquery which computes the sequence:
UPDATE yourTable k1
INNER JOIN
(
SELECT KeyID, rn
FROM
(
SELECT t1.KeyID,
(SELECT SUM(t2.Pay = 1) FROM yourTable t2
WHERE t2.KeyID >= t1.KeyID) rn
FROM yourTable t1
) t
) k2
ON k1.KeyID = k2.KeyID
SET
Queue = CASE WHEN Pay = 0 THEN 0 ELSE k2.rn END;
To see how the above logic is working, here is what the intermediate join table looks like:
KeyID | Queue | Pay | rn
65 | 1 | 0 | 0
60 | 2 | 0 | 0
58 | 3 | 1 | 1
57 | 4 | 1 | 2
55 | 5 | 0 | 2
54 | 6 | 0 | 2
53 | 7 | 1 | 3
50 | 8 | 1 | 4
That is, the innermost correlated subquery generates the queue sequence by counting the number of times Pay is 1.
Note that if you are using MySQL 8+, then there is a much simpler query using analytic functions:
UPDATE yourTable
SET Queue = CASE WHEN Pay = 0
THEN 0
ELSE SUM(Pay = 1) OVER (ORDER BY KeyID DESC) END;

Transpose the results of a MySQL query that outputs ranges

My source table (wplott_wpkl_winner) contains the field "lottery_number" that carries 1 to 6 digit numbers and the corresponding "draw_date".
lottery_number | draw_date
==================================
0024 | 2018-11-10
4456 | 2018-11-10
3895 | 2018-11-10
4557 | 2018-11-10
4225 | 2018-11-10
2896 | 2018-11-10
3354 | 2018-11-10
1895 | 2018-11-10
78466 | 2018-11-10
998556 | 2018-11-10
My current MYSQL query is as below (I am trying to group the data into ranges)
select
count(case when wplott_wpkl_winner.lottery_number between 0 and 999 then 1 end) `0-999`,
count(case when wplott_wpkl_winner.lottery_number between 1000 and 1999 then 1 end) `1000-1999`,
count(case when wplott_wpkl_winner.lottery_number between 2000 and 2999 then 1 end) `2000-2999`,
count(case when wplott_wpkl_winner.lottery_number between 3000 and 3999 then 1 end) `3000-3999`,
count(case when wplott_wpkl_winner.lottery_number between 4000 and 4999 then 1 end) `4000-4999`,
count(case when wplott_wpkl_winner.lottery_number between 5000 and 5999 then 1 end) `5000-5999`,
count(case when wplott_wpkl_winner.lottery_number between 6000 and 6999 then 1 end) `6000-6999`,
count(case when wplott_wpkl_winner.lottery_number between 7000 and 7999 then 1 end) `7000-7999`,
count(case when wplott_wpkl_winner.lottery_number between 8000 and 8999 then 1 end) `8000-8999`,
count(case when wplott_wpkl_winner.lottery_number between 9000 and 9999 then 1 end) `9000-9999`
from wplott_wpkl_winner
where CHAR_LENGTH(wplott_wpkl_winner.lottery_number) = 4 AND wplott_wpkl_winner.draw_date > '2013-06-30'
It provides the below output
0-999 | 1000-1999 | 2000-2999 | 3000-3999 | 4000- 4999 .... etc
=====================================================================
1 | 1 | 1 | 2 | 3
However, I would like to get the output in the below format.
Range | Count
=======================
0-999 | 1
1000-1999 | 1
2000-2999 | 1
3000-3999 | 2
4000-4999 | 3
.
.
.
Any help is highly appreciated. I did search in SO for a similar answer but none of the answers helped my particular case.
Thanks in advance!
One approach uses a series of unions:
SELECT
`range`,
count
FROM
(
SELECT 1 AS pos, '0-999' AS `range`, COUNT(*) AS count
FROM wplott_wpkl_winner
WHERE draw_date > '2013-06-30' AND lottery_number BETWEEN 0 AND 999
UNION ALL
SELECT 2, '1000-1999', COUNT(*)
FROM wplott_wpkl_winner
WHERE draw_date > '2013-06-30' AND lottery_number BETWEEN 1000 AND 1999
UNION ALL
... -- fill in remaining ranges here
) t
ORDER BY pos;
Note that I introduce a computed column pos so that we may maintain the desired ordering of the ranges in the final output. Also, I removed the check on the CHAR_LENGTH of the lottery_number, since the conditional sums already handle this logic.

multiple records per row query

I have a table (in mysql) like this:
TABLE1
Id Name Age
---------------
1 John 22
2 Mary 17
3 Peter 21
4 Agnes 34
5 Steve 14
6 Bart 26
7 Bob 32
8 Vince 18
...
What I am looking for is a SELECT statement, where I can get 4 records in a row. I mean, the result of the select statement would be:
Id1 Name1 Age1 Id2 Name2 Age2 Id3 Name3 Age3 Id4 Name4 Age4
-----------------------------------------------------------
1 John 22 2 Mary 17 3 Peter 21 4 Agnes 34
5 Steve 14 6 Bart 26 7 Bob 32 8 Vince 18
...
I guess it would be like a pivot...
Is this possible? If it is, then how can I achieve it?
I need to populate a report by showing 4 records on a row, so I would like to be able to do it from a datasource that returns this exact structure. So on first band/row there will be
rec1,rec2,rec3,rec4
then on second row:
rec5,rec6,rec7,rec8
and so on.
My first idea was to merge 4 queries that return every 5th record starting with 1,2,3,4 but I'm not exactly sure...
Can you help?
You can do this with arithmetic on the id and group by:
select (case when id % 4 = 1 then id end) as id1,
(case when id % 4 = 1 then name end) as name1,
(case when id % 4 = 1 then age end) as age1,
(case when id % 4 = 2 then id end) as id2,
(case when id % 4 = 2 then name end) as name2,
(case when id % 4 = 2 then age end) as age2,
(case when id % 4 = 3 then id end) as id3,
(case when id % 4 = 3 then name end) as name3,
(case when id % 4 = 3 then age end) as age3,
(case when id % 4 = 0 then id end) as id4,
(case when id % 4 = 0 then name end) as name4,
(case when id % 4 = 0 then age end) as age4
from t
group by floor((id - 1) / 4);
If the id doesn't increment without gaps, then you can generate one using:
from (select t.*, (#rn := #rn + 1) as seqnum
from t cross join
(select #rn := 0) params
order by id
) t