MySQL change last row of rollup - mysql

I am running a query for a report and am using rollup to get a total. One of my columns have a text field that is duplicating at the end. For example:
SELECT * FROM transactions;
transNum | itemid | description | qty
---------------------------------------
01 | 01 | DESC1 | 14
02 | 01 | DESC1 | 05
03 | 01 | DESC1 | 01
04 | 02 | DESC2 | 02
05 | 02 | DESC2 | 01
06 | 02 | DESC2 | 02
07 | 03 | DESC3 | 05
08 | 03 | DESC3 | 06
09 | 03 | DESC3 | 01
SELECT itemid,description,qty FROM transactions GROUP BY id WITH ROLLUP;
itemid | description | qty
----------------------------
01 | DESC1 | 20
02 | DESC2 | 05
03 | DESC3 | 12
| DESC3 | 37
This is a rough example, my actual data consists of multiple tables.
Now, I understand that the DESC3 is getting duplicated because I am not grouping by the description field, but is there any function that can get around this?
Other database engines have a GROUPING function, which is basically what I need but in MySQL.
Thank you for any help

OK, then try this:
SELECT a.itemid, b.description, a.total
FROM
(
SELECT itemid, sum(qty) as total
FROM transactions
GROUP BY itemid WITH ROLLUP
) as a
LEFT JOIN item b ON a.itemid=b.itemid
Assuming you have a table named item with item descriptions keyed on itemid.

From the docs, there's no way of altering the content of the last row.
The result set comes with a NULL value in the 1st column of the rollup row so that you can identify it in your application.
Here's a SQL Fiddle to play with it: http://sqlfiddle.com/#!8/d611d/8
As you see it does repeat the previous description in the rollup row.

use: case when itemid is null then Total

Related

MySQL MAX value with 2 conditions

I'm trying to update SQL table with results of students contest. For that contest I've 2 tables: participants (name, class, school, etc.) and results (participant_id, results and subject). Now I need to give each participant a status - 1st place, 2nd place or 3d place based on their results.
The tricky part is the rules of that contest. Each participant must get this status in their respective school and class. So I must have winners in each school and each class. It's quite simple to update table with 2nd and 3d place as they counted as result >= 50 and result < 50. But the 1st place must be the highest score in this school and in this class.
I tried a lot of combinations with MAX() statement but with no success. No matter what I try I can't make it show maximum value based on 2 conditions (max in school, max in class). I need something like =MAXIFS() in Excel, but don't know how to do it in SQL.
UPD. Examples
Table participants
| id | name | class | school |
------------------------------
| 01 | John | 10 | 312 |
| 02 | Jack | 10 | 312 |
| 03 | Mary | 11 | 144 |
| 04 | Dany | 11 | 312 |
| 05 | Mark | 7 | 144 |
Table results
| id | participant_id | subject | score |
-----------------------------------------
| 01 | 03 | 4 | 55 |
| 02 | 01 | 4 | 75 |
| 03 | 04 | 4 | 60 |
| 04 | 05 | 4 | 45 |
| 05 | 02 | 4 | 90 |
And the result I need must look like this:
| id | participant_id | subject | score | status |
-----------------------------------------------------
| 01 | 03 | 4 | 55 | 1st place |
| 02 | 01 | 4 | 75 | 2nd place |
| 03 | 04 | 4 | 60 | 3rd place |
| 04 | 05 | 4 | 45 | 3rd place |
| 05 | 02 | 4 | 90 | 1st place |
Basically, 1st place is MAX in each school and class, 2nd is less than MAX and >= 50 and 3rd is just less than 50.
Can't show everything I tried because it's all variations of the same query. Something like that:
SELECT
id, participant_id, subject, score,
(CASE
WHEN score >= 50 THEN '2nd place'
WHEN score < 50 THEN '3rd place'
WHEN score = MAX(score) THEN '1st place'
END) AS 'status'
FROM results
INNER JOIN participants ON results.participant_id = participants.id
GROUP BY participant_id
I've also tried with subqueries, but it's obviously not helping - different subqueries even give different number of rows or resulting 'status' doesn't match the score and other information.
The next query can be used as solution:
SELECT
participants.*,
results.*,
(CASE
WHEN score = max_score THEN '1st place'
WHEN score >= 50 THEN '2nd place'
WHEN score < 50 THEN '3rd place'
END) AS 'status'
FROM participants
JOIN results ON results.participant_id = participants.id
JOIN (
SELECT
class, school, max(score) max_score
FROM results
INNER JOIN participants ON results.participant_id = participants.id
GROUP BY class, school
) max_results ON
max_results.class = participants.class AND
max_results.school = participants.school;
And here the fiddle: SQLize.online

How to delete duplicate data from MySQL except latest data

I want to delete records from mysql table
I have table like this
I am checking here if (date, url, price, hotelName) is same then remove except one
id | hotelName | price | url | date |
-------------------------------------------------
1 | abcd | 20$ | abcd.com | 21 jan 2019 |
2 | abcd | 24$ | abcd.com | 22 jan 2019 |
3 | wzyz | 10$ | wzyz.com | 21 jan 2019 |
4 | abcd | 20$ | abcd.com | 21 jan 2019 |
5 | wzyz | 15$ | wzyz.com | 22 jan 2019 |
6 | wzyz | 15$ | wzyz.com | 22 jan 2019 |
In this table you can see duplicate records is id [1,4] and [5,6]
I want to delete duplicate records from this table except latest data
After deleting this table should look like
id | hotelName | price | url | date |
-------------------------------------------------
2 | abcd | 24$ | abcd.com | 22 jan 2019 |
3 | wzyz | 10$ | wzyz.com | 21 jan 2019 |
4 | abcd | 20$ | abcd.com | 21 jan 2019 |
6 | wzyz | 15$ | wzyz.com | 22 jan 2019 |
If your table is not too big, this is a short and straight-forward syntax :
DELETE t1
FROM
mytable t1
CROSS JOIN t2
WHERE
t1.id < t2.id
AND t1.hotelName = t2.hotelName
AND t1.date = t2.date
AND t1.url = t2.url
AND t1.price = t2.price
Anoter solution, less resource-consuming :
DELETE FROM mytable
WHERE id NOT IN (
SELECT MAX(t.id) FROM mytable t GROUP BY t.hotelName, t.date, t.url, t.price
)
I strongly recommend group by and join for this purpose:
delete t join
(select date, url, price, hotelName, max(id) as max_id
from t
group by date, url, price, hotelName
) tt
using (date, url, price, hotelName)
where t.id < tt.max_id;
I assume by latest, you mean "keep the one with the largest id".
If you have a large amount of data, delete can be expensive. In that case. create temporary table/truncate/insert might have better performance.

mysql monthly sales comparison

I have 1 table:
id | year | quarter | month | brand | sku | total_unit_sales
-----------------------------------------------------------------
1 | 2010 | 1 | Jan | Toyota | 123 | 156
2 | 2010 | 1 | Jan | Toyota | 124 | 77
3 | 2010 | 1 | Jan | Toyota | 125 | 325
4 | 2010 | 1 | Feb | Toyota | 123 | 184
5 | 2010 | 1 | Feb | Toyota | 124 | 98
6 | 2010 | 1 | Feb | Toyota | 125 | 219
7 | 2010 | 1 | Mar | Toyota | 123 | 178
8 | 2010 | 1 | Mar | Toyota | 124 | 101
9 | 2010 | 1 | Mar | Toyota | 125 | 215
10 | 2010 | 1 | Apr | Toyota | 123 | 216
11 | 2010 | 1 | Apr | Toyota | 124 | 115
12 | 2010 | 1 | Apr | Toyota | 125 | 278
I need to create delta indexes (the percentage of variation one time period to other period) on sales by brand, month, year. Those indexes are average variation in the last 12 months, variation in current quarter, last month vs previous month.
I once achieved this in a multi stage way, creating many summarizing tables and then generating the desired report. However this was a manual customized process. Now I need a fully automated way where the data source is updated and the report generated.
I' ve been working on a self join, however the results are less than desirable, having in mind that can compare previous price versus newest price by self joining the table with:
left join on a.id=b.id+1
This is prone to error due to the fact that some months do not gahter sales data of some specific sku, not sold on that month.
I appreciate your help. Thanks in advance. mysql ver 5.5+
Your join approach sounds like a valid way to proceed. You can improve the quality of your figures by using an outer join, and IFNULL() to generate sensible values.

query for balance due and due date for entity

I am trying to get a list of guests who have not yet fully paid their total charges (those who still have a balance).
I want to display like so:
1231231(reservation id) - John Doe(guest name) 2013-11-17(date due) 153.14(balance due)
without the ( ) of course.
I have tinkered but still can't find a query that is satisfactory.
Here is a link to the SQLFiddle.
If I haven't provided enough info, kindly let me know.
Are you looking for something like this?
SELECT r.id,
CONCAT(g.fname, ' ', g.lname) guest_name,
r.arrival date_due,
r.total_price - COALESCE(p.payment_amt, 0) balance_due
FROM reservations r JOIN guests g
ON r.guest = g.id LEFT JOIN
(
SELECT reservation, SUM(payment_amt) payment_amt
FROM payments
GROUP BY reservation
) p
ON r.id = p.reservation
HAVING balance_due > 0
Sample output (based on provided sample data):
| ID | GUEST_NAME | DATE_DUE | BALANCE_DUE |
|---------|------------|---------------------------------|-------------|
| 1000023 | John Doe | November, 09 2013 00:00:00+0000 | 40.5 |
| 1000022 | John Doe | November, 09 2013 00:00:00+0000 | 40.5 |
| 1000018 | John Doe | November, 01 2013 00:00:00+0000 | 54 |
| 1000019 | John Doe | November, 08 2013 00:00:00+0000 | 54 |
| 1000020 | Mary Jane | November, 08 2013 00:00:00+0000 | 54 |
| 1000021 | Mary Jane | November, 08 2013 00:00:00+0000 | 54 |
Here is SQLFiddle demo

Select flat data into table format

I have a table with a schema similar to the following
id | year | month | amount ...
x | 2011 | 12 | 312
x | 2011 | 12 | 213
x | 2012 | 1 | 123
x | 2012 | 1 | 123
x | 2012 | 2 | 123
...
I want to know if it would be possible (via mysql) to output something like
year | 1 | 2 | 3 | ....
2011 | 321 | 231 | ...
2012 | 246 | 123 | ...
So doing a group by year, month, sum(amount) and output one "row" per year with the individual months as the columns.
Thanks
You would want to use a pivot table of sorts. If you are only dealing with months something like the below SQL should work for you. I only did the first three months but the rest are the same.
SELECT year, SUM(IF(month=1,amount,0)) As '1', SUM(IF(month=2,amount,0)) As '2', SUM(IF(month=3,amount,0)) As '3' FROM mytable GROUP BY year