MySQL UPDATE with GROUP and ORDER - mysql

I'm trying to make an update on a table so that it can increment the values on 1 column depending on another's order.
Here's how it'd go
ID GROUP_ID ORDER(Desired) ORDER(NOW)
1 1 1 2
2 1 2 3
3 1 3 1
4 2 1 2
5 2 2 1
6 3 1 1
7 3 2 1
8 3 3 2
So what I need is for each ID, to update the ORDER column so it can be consecutive, starting from 1, within each GROUP_ID.
I have found some solutions to similar problems regarding the updates and orders, but none that uses multiple orders for groups within the same table.
Hope I illustrated the problem right. Thanks in advance

You can do it by "ranking" the rows over again. Mysql doesn't support window functions but you can achieve the same results with join and count like this:
UPDATE YourTable t
INNER JOIN(SELECT s.id,s.group_id,count(*) as cnt
FROM YourTable s
INNER JOIN YourTable ss
ON(s.group_id = ss.group_id and s.id >= ss.id)
GROUP BY s.id,s.group_id) tt
ON (t.id = tt.id and t.group_id = tt.group_id)
SET t.order = tt.cnt

Related

Trying to get latest status for related shipment but the results I receive are incorrect

I am currently working on a project while trying to learn MySQL and I would like to join three tables and get the latest status for each related shipment. Here are the tables I'm working with (with example data):
shipments
id
consignee
tracking_number
shipper
weight
import_no
1
JOHN BROWN
TBA99900000121
AMAZON
1
101
2
HELEN SMITH
TBA99900000190
AMAZON
1
102
3
JACK BLACK
TBA99900000123
AMAZON
1
103
4
JOE BROWM
TBA99900000812
AMAZON
1
104
5
JULIA KERR
TBA99900000904
AMAZON
1
105
statuses
id
name
slug
1
At Warehouse
at_warehouse
2
Ready For Pickup
ready_for_pickup
3
Delivered
delivered
shipment_status (pivot table)
id
shipment_id
status_id
1
1
1
2
2
1
3
3
1
4
4
1
5
5
1
6
1
2
7
2
2
8
3
2
9
4
2
10
5
2
all tables do have created_at and updated_at timestamp columns
Example of the results I'm trying to achieve
slug
shipment_id
status_id
ready_for_pickup
1
2
ready_for_pickup
2
2
ready_for_pickup
3
2
ready_for_pickup
4
2
ready_for_pickup
5
2
Here's the query I wrote to try to achieve what I'm looking for based on examples and research I did during the past couple of days. I find that sometimes there is sometimes a mismatch with the latest status that relates to the shipment
SELECT
statuses.slug AS slug,
MAX(shipments.id) AS shipment_id,
statuses.id AS status_id,
FROM
`shipments`
INNER JOIN `shipment_status` ON `shipment_status`.`shipment_id` = `shipments`.`id`
INNER JOIN `statuses` ON `shipment_status`.`status_id` = `statuses`.`id`
GROUP BY
`shipment_id`
Because we need to reference other fields from the same record that evaluates from the MAX aggregation, you need to do it in two steps, there are other ways, but I find this syntax simpler:
SELECT
shipments.id AS id,
statuses.slug AS slug,
statuses.id AS status_id,
shipment_status.shipment_id as shipment_id
FROM
`shipments`
INNER JOIN `shipment_status` ON `shipment_status`.`shipment_id` = `shipments`.`id`
INNER JOIN `statuses` ON `shipment_status`.`status_id` = `statuses`.`id`
WHERE
shipment_status.id = (
SELECT MAX(shipment_status.id)
FROM `shipment_status`
WHERE shipment_status.shipment_id = shipments.id
)
try it out!
This query makes the assumption that the id field is an identity column, so the MAX(shipment_status.id) represents only the most recent status for the given shipment_id
You can use window functions:
SELECT s.id, st.slug, st.id
FROM shipments s JOIN
(SELECT ss.*,
ROW_NUMBER() OVER (PARTITION BY shipment_id ORDER BY ss.id DESC) as seqnum
FROM shipment_status ss
) ss
ON ss.shipment_id = s.id JOIN
statuses st
ON ss.status_id` = st.id
WHERE ss.seqnum = 1;
Also note the use of table aliases so the query is easier to write and to read.

Mysql select statement contains where clause so unsuitable for insert into

I'm very inexperienced. I've prepared a select statement which gives the information I need to populate a matches table. However it is not suitable because it contains a where clause. Is there a different way to use it, or how can I change it so that it is suitable for INSERT INTO.
The tables are as follows:-
match_order
match_order_id||match_descrip||first_player||second_player
1 1v2 1 2
2 1v3 1 3
3 2v3 2 3
4 1v4 1 4
5 2v4 2 4
6 3v4 3 4
entries
entry_id||round_id||league_id||box_id||box_position
1 1 1 1 1
2 1 1 1 2
3 1 1 1 3
4 1 2 1 4
5 1 2 1 2
6 1 2 1 1
7 1 2 1 1
matches
match_id||round_id||league_id||box_id||match_order_id||player1||player2
I need to insert new rows every month for a new round of matches. League size, box size & positions change each month.
This is the statement which gives the correct rows.
SELECT e.round_id, e.league_id, e.box_id, mo.match_order_id, e.entry_id as player1, e1.entry_id as player2
FROM match_order mo
LEFT JOIN entries e ON mo.first_player = e.box_position
LEFT JOIN entries e1 ON mo.second_player = e1.box_position
WHERE e.round_id = e1.round_id AND e.league_id = e1.league_id AND e.box_id = e1.box_id
ORDER BY round_id, league_id, box_id, match_order_id
Any help & advise would be greatly appreciated.
Thank you
Assuming match_id is an auto-increment column, you have the data for the other columns. You can just add the INSERT statement before your SELECT.
INSERT INTO matches(round_id, leage_id, box_id, match_order_id, player1, player2)
SELECT e.round_id, e.league_id, e.box_id, mo.match_order_id, e.entry_id as player1, e1.entry_id as player2
FROM match_order mo
LEFT JOIN entries e ON mo.first_player = e.box_position
LEFT JOIN entries e1 ON mo.second_player = e1.box_position
WHERE e.round_id = e1.round_id AND e.league_id = e1.league_id AND e.box_id = e1.box_id

mysql row numbering reset every different record values

My question is pretty similar to this one Auto number and reset count for each different column value
except that I can't make it work.
I have the table record:
ID(autoINC) plate_number
1 A
2 A
3 A
4 B
5 B
6 C
7 C
I want to display something like this adding additional field cc:
I have the table record:
ID(autoINC) plate_number count
1 A 1
2 A 2
3 A 3
4 B 1
5 B 2
6 C 1
7 C 2
You can have a correlated subquery which sequentially count the row which can be used as a rownumber.
SELECT A.ID,
A.plate_number,
(
SELECT COUNT(*)
FROM tableName c
WHERE c.plate_number = a.plate_number AND
c.ID <= a.ID) AS RowNumber
FROM TableName a
SQLFiddle Demo

MYSQL denormalized data finding and deleting duplicates

I have example data
ID DAY ORDER TIME PRODUCT
1 1 1 1 1
2 1 1 1 2
3 1 1 1 3
4 1 2 2 1
5 1 2 2 2
6 1 2 2 3
7 1 2 *3* 1
8 1 2 *3* 2
9 1 2 *3* 3
I want to prevent to having mltiple orders in different time at same day. if I set unique index on DAY,ORDER,TIME I will not be able to insert multiple time anyway, but I want to disable multiple different TIME. Is this possible with mysql?
Have can I find all records where there multiple different TIME value in same DAY and ORDER and delete them?
in this case I would like to delete records 7,8 ad 9 with SQL query because it is duplicate ORDER inserted.
I don't want to normalize table I will stick with this database structure.
Thank you very much
You can use delete with a join clause to find the duplicates and delete them:
delete
from t join
(select day, "order", min(time) as tokeeptime
from t
group by day, "order"
) tokeep
on t.day = tokeep.day and t."order" = tokeep."order" and t.time <> tokeeptime;
DELETE a
FROM tableName a
INNER JOIN
(
SELECT a.DAY, a.ORDER, MAX(a.TIME) Time
FROM tableName a
GROUP BY a.DAY, a.ORDER
HAVING COUNT(DISTINCT TIME) > 1
) b ON a.DAY = b.DAY AND
a.Order = b.Order AND
a.Time = b.Time
SQLFiddle Demo

Access Totals Query Not Necessarily Returning First Record

I have a table of data like this:
id user_id A B C
=====================
1 15 1 2 3
2 15 1 2 5
3 20 1 3 9
4 20 1 3 7
I need to remove duplicate user ids and keep the record that sorts lowest when sorting by A then B then C. So using the above table, I set up a temp query (qry_temp) that simply does the sort--first on user_id, then on A, then on B, then on C. It returns the following:
id user_id A B C
====================
1 15 1 2 3
2 15 1 2 5
4 20 1 3 7
3 20 1 3 9
Then I wrote a Totals Query based on qry_temp that just had user_id (Group By) and then id (First), and I assumed this would return the following:
user_id id
===========
15 1
20 4
But it doesn't seem to do that--instead it appears to be just returning the lowest id in a group of duplicate user ids (so I get 1 and 3 instead of 1 and 4). Shouldn't the Totals query use the order of the query it's based upon? Is there a property setting in the query that might impact this or another way to get what I need? If it helps, here is the SQL:
SELECT qry_temp.user_id, First(qry_temp.ID) AS FirstOfID
FROM qry_temp
GROUP BY qry_temp.user_id;
You need a different type of query, for example:
SELECT tmp.id,
tmp.user_id,
tmp.a,
tmp.b,
tmp.c
FROM tmp
WHERE (( ( tmp.id ) IN (SELECT TOP 1 id
FROM tmp t
WHERE t.user_id = tmp.user_id
ORDER BY t.a,
t.b,
t.c,
t.id) ));
Where tmp is the name of your table. First, Last, Min and Max are not dependent on a sort order. In relational databases, sort orders are quite ephemeral.