OK so I have looked theough the other solutions an no help. So here is what I am trying to do.
I need to select the row with multiple columns where the value in one column is the max value.
here is sample data
orderfileid item number item cost warehouse
1 1234 3.45 ATL
1 2345 1.67 DFW
3 2345 2.45 NYY
3 678 2.4 ORD
2 1234 1.67 DFW
I need to select the entire row where the orderfileid is the max for each unique item number
the returned dataset should look like
orderfileid item number item cost warehouse
2 1234 1.67 DFW
3 2345 2.45 NYY
3 6789 2.4 ORD
I think i tried every combination of select max(orderfileid) i can think of
Any help would be appriciated.
thanks
You need to find your MAX values in a subquery, then use those results to join to your main table to retrieve the columns.
SELECT t.OrderFileId, t.ItemNumber, t.ItemCost, t.Warehouse
FROM YourTable t
INNER JOIN (SELECT ItemNumber, MAX(OrderFileId) AS MaxOrderId
FROM YourTable
GROUP BY ItemNumber) q
ON t.ItemNumber = q.ItemNumber
AND t.OrderFileId = q.MaxOrderId
select
t.*
from
table t
inner join (
select itemnumber, max(orderfileid) maxof
from table
group by itemnumber
) m on t.itemnumber = m.itemnumber
and t.orderfileid = m.maxof
I wouldn't even use Max. Just combine GROUP BY and ORDER BY
SELECT * FROM orders GROUP BY item_number ORDER BY orderfileid DESC
then for minimum just change to ASC
Try
SELECT * FROM `TABLE` WHERE orderfileid=(select max(orderfileid) from TABLE)
you can refer to a similar problem on how to group things using partitioning and picking one per partition in mysql
Deleting Rows: No Single Member Has More Than x Records
this is something similar to doing rank over in Oracle. my previous post was for oracle. my bad..
I think what you are looking for is the "Having" clause. Take a look at this.
select orderfileid, max(itemnumber), itemcost, warehouse from MyTable group by orderfileid having max(itemnumber) ;
Related
There is a table with the name '**work**' that contains data as shown below:
Id Name a_Column work_datetime
-----------------------------------------
1 A A_1 1592110166
2 A A_2 1592110166
3 A A_3 1592110164
4 B B_1 1582111665
5 B B_2 1592110166
6 C C_1 1592110166
If I run a query which group by A and max(work_datetime), then there could be 2 selections for group with Name='A' but i need only one of them with a_Column='A_1' such that final desired output is as follows:-
Id Name a_Column work_datetime
-----------------------------------------
1 A A_1 1592110166
5 B B_2 1592110166
6 C C_1 1592110166
Handling duplicate records at the group by is something which mysql doesn't seem to support!
Any way i can achieve the required result?
A simple option that works on all versions of MySQL is to filter with a subquery:
select w.*
from work w
where w.id = (
select id
from work w1
where w1.name = w.name
order by work_datetime desc, a_column
limit 1
)
For each name, this brings the row with the latest work_datetime; ties are broken by picking the row with the smallest a_column (which is how I understood your requirement).
For performance, you want an index on (work_datetime, a_column, id).
Since version 8 you can use row_number() to assign a number to each row numbering the position of the row in the descending order of the time repeating for each name. Do that in a derived table and then just select the rows where this number is 1 from it.
SELECT x.id,
x.name,
x.a_column,
x.work_datetime
FROM (SELECT w.id,
w.name,
w.a_column,
w.work_datetime,
row_number() OVER (PARTITION BY w.name
ORDER BY w.work_datetime) rn
FROM work w) x
WHERE x.rn = 1;
With row_number() there are no duplicates. Should there be two rows with the same name and time one of it is chosen randomly. If you want to retain the duplicates you can replace row_number() with rank().
I just start to learn MYSQL and meet a problem like this
So the table is like this:
id name moneySpent
1 Alex 3
2 Alex 1
3 Bill 4
4 Alex 2
5 Alex 1
6 Chris 5
7 Chris 3
Lets say I wanna know the Average money spent per person. I try to do that by using SUM() GROUP BY and AVG() but I got stuck at AVG()
SELECT name, sum(moneySpent) AS total FROM table GROUP BY name;
then this will return
name total
Alex 7
Bill 4
Chris 8
Then how can I get a (7+4+8)/3 using AVG()?
You can get average per person using:
SELECT AVG(total) AS AVERAGE
FROM (SELECT name, sum(moneySpent) AS total
FROM table GROUP BY name) A
;
Output:
AVERAGE
6,3333
You can use inner query to get sum and outer query to derive average from sum as below.
SELECT Avg(sum1) FROM (
SELECT Sum(amount) AS sum1
FROM table1
GROUP BY NAME
) T1
It will generate below output.
AVERAGE_AMOUNT_SPENT
------------------
6.3333
which is what you want to be the output i.e. (7+4+8)/3 = 6.333
You can check demo here
So there are 2 ways to do this, first is use a new table to store the SELECT result. It is much more esay but may take more space.
Second is by jarlh, It comes to me that I do not need to GROUP BY the whole table, I can just add all moneySpent up and divided by distinct name count.
Thanks people!
select avg(total) as average from (SELECT name, sum(moneySpent) AS total FROM table GROUP BY name);
You can use this query to get your desired output
OUTPUT:
AVERAGE
6.3333333333333333
I got a question in my homework for SQL about selecting the maximum values from the same table that have different class "Letters"
For example:
ID Student Group Avg(value)
-------------------------------------
1 stud1 A 9
2 stud2 A 9.5
3 stud3 B 8
4 stud4 B 8.5
What my query should do, is to show stud2 and stud4.The maximum from their respective groups.
I managed to do it in the end, but it took a lot of characters so I thought that maybe there's a shorter way to do. Any ideas? I used to first search the id or the stud that has max avg(value) from group A, intersecting with the id of the stud that has max avg(value) from B and then putting everything into one big select and then using those intersected IDs into another query that requested to show some different things about those IDs. But as I said, it looked far too long and thought that maybe there's an shorter way.
Try this (I renamed group to grp and avg to avg_val as those are reserved keywords):
select t1.*
from your_table t1
inner join (
select grp, max(avg_val) avg_val
from your_table
group by grp
) t2 on t1.grp = t2.grp
and t1.avg_val = t2.avg_val;
It finds maximum avg value per group and joins it with original table to get the corresponding students.
Please note that if there are multiple students with same avg as the max value of the that group, all of those students will be returned.
Apologies in advance if this has an answer elsewhere - I did look hard but couldn't find one.
I've got a table called 'item' which is a bit like this:
itemid applicationid value
1 1 3.00
2 2 1.00
3 2 2.00
4 3 4.00
5 3 1.00
i.e. an application can have multiple items. There are more columns but never mind.
I would like to list the items and their values against the total application value (so that I can work out the item value as a proportion of the application).
So I've got a query a bit like this:
SELECT i.itemid, i2.applicationid, i.value, i2.totalvalue
FROM item i
JOIN (SELECT sum(value) AS totalvalue FROM item GROUP BY applicationid) i2
ON i.applicationid = i2.applicationid
WHERE <some criteria that returns a hundred or so items>;
to give me
itemid applicationid value totalvalue
1 1 3.00 3.00
2 2 1.00 3.00
3 2 2.00 3.00
4 3 4.00 5.00
5 3 1.00 5.00
This works, but with 100k rows in the item table it is very, very slow. I am told by my profiler that the problem is having a subquery that is doing a full index scan.
I wondered if a self-join with a GROUP BY would be quicker, but it groups the whole lot not just the second table. I.e.
SELECT i.itemid, i2.applicationid, i.value, sum(i2.value)
FROM item i
JOIN item i2 ON i2.applicationid = i.applicationid
WHERE <some criteria that returns a hundred or so items>
GROUP BY i2.applicationid;
I only get 1 row per applicationid, not 1 row per itemid.
Is there any way to rewrite my original query that will make it quicker?
Many thanks.
Your query has no join condition to the subquery, so it is not syntactically correct. Have you tried this query:
SELECT i.itemid, i2.applicationid, i.value, i2.totalvalue
FROM item i JOIN
(SELECT applicationid, sum(value) AS totalvalue
FROM item
GROUP BY applicationid
) i2
on i.applicationid = i2.applicationid
WHERE <some criteria that returns a hundred or so items>;
In some databases, this might run faster as a correlated subquery, particularly if you have an index on applicationid:
SELECT i.itemid, i.applicationid, i.value,
(select sum(value) from item i2 where i.applicationid = i2.applicationid
) as totalvalue
FROM item i JOIN
(SELECT applicationid, sum(value) AS totalvalue
FROM item
GROUP BY applicationid
) i2
on i.applicationid = i2.applicationid
WHERE <some criteria that returns a hundred or so items>;
Also, it could be your WHERE criteria that is slowing things down, once again, depending on the database.
You can try using windowing functions to see if the optimizers uses them well. I would guess that it will use the same execution plan, but it is worth a quick try. This is the code for SQL Server, and it should be similar for Oracle.
SELECT i.itemid, i.applicationid, i.value,
sum(value) Over (Partition by i.applicationid) as totalvalue
FROM item i
WHERE <some criteria that returns a hundred or so items>;
Here is a simplified version of my table:
group price spec
a 1 .
a 2 ..
b 1 ...
b 2
c .
. .
. .
I'd like to produce a result like this: (I'll refer to this as result_table)
price_a |spec_a |price_b |spec_b |price_c ...|total_cost
1 |. |1 |.. |... |
(min) (min) =1+1+...
Basically I want to:
select the rows containing the min price within each group
combine columns into a single row
I know this can be done using several queries and/or combined with some non-sql processing on the results, but I suspect that there maybe better solutions.
The reason that I want to do task 2 (combine columns into a single row)
is because I want to do something like the following with the result_table:
select *,
(result_table.total_cost + table1.price + table.2.price) as total_combined_cost
from result_table
right join table1
right join table2
This may be too much to ask for, so here is some other thoughts on the problem:
Instead of trying to combine multiple rows(task 2), store them in a temporary table
(which would be easier to calculate the total_cost using sum)
Feel free to drop any thoughts, don't have to be complete answer, I feel it's brilliant enough if you have an elegant way to do task 1 !
==Edited/Added 6 Feb 2012==
The goal of my program is to identify best combinations of items with minimal cost (and preferably possess higher utilitarian value at the same time).
Consider #ypercube's comment about large number of groups, temporary table seems to be the only feasible solution. And it is also pointed out there is no pivoting function in MySQL (although it can be implemented, it's not necessary to perform such operation).
Okay, after study #Johan's answer, I'm thinking about something like this for task 1:
select * from
(
select * from
result_table
order by price asc
) as ordered_table
group by group
;
Although looks dodgy, it seems to work.
==Edited/Added 7 Feb 2012==
Since there could be more than one combination may produce the same min value, I have modified my answer :
select result_table.* from
(
select * from
(
select * from
result_table
order by price asc
) as ordered_table
group by group
) as single_min_table
inner join result_table
on result_table.group = single_min_table.group
and result_table.price = single_min_table.price
;
However, I have just realised that there is another problem I need to deal with:
I can not ignore all the spec, since there is a provider property, items from different providers may or may not be able to be assembled together, so to be safe (and to simplify my problem) I decide to combine items from the same provider only, so the problem becomes:
For example if I have an initial table like this(with only 2 groups and 2 providers):
id group price spec provider
1 a 1 . x
2 a 2 .. y
3 a 3 ... y
4 b 1 ... y
5 b 2 x
6 b 3 z
I need to combine
id group price spec provider
1 a 1 . x
5 b 2 x
and
2 a 2 .. y
4 b 1 ... y
record (id 6) can be eliminated from the choices since it dose not have all the groups available.
So it's not necessarily to select only the min of each group, rather it's to select one from each group so that for each provider I have a minimal combined cost.
You cannot pivot in MySQL, but you can group results together.
The GROUP_CONCAT function will give you a result like this:
column A column B column c column d
groups specs prices sum(price)
a,b,c some,list,xyz 1,5,7 13
Here's a sample query:
(The query assumes you have a primary (or unique) key called id defined on the target table).
SELECT
GROUP_CONCAT(a.`group`) as groups
,GROUP_CONCAT(a.spec) as specs
,GROUP_CONCAT(a.min_price) as prices
,SUM(a.min_prices) as total_of_min_prices
FROM
( SELECT price, spec, `group` FROM table1
WHERE id IN
(SELECT MIN(id) as id FROM table1 GROUP BY `group` HAVING price = MIN(price))
) AS a
See: http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html
Producing the total_cost only:
SELECT SUM(min_price) AS total_cost
FROM
( SELECT MIN(price) AS min_price
FROM TableX
GROUP BY `group`
) AS grp
If a result set with the minimum prices returned in row (not in column) per group is fine, then your problem is of the gretaest-n-per-group type. There are various methods to solve it. Here's one:
SELECT tg.grp
tm.price AS min_price
tm.spec
FROM
( SELECT DISTINCT `group` AS grp
FROM TableX
) AS tg
JOIN
TableX AS tm
ON
tm.PK = --- the Primary Key of the table
( SELECT tmin.PK
FROM TableX AS tmin
WHERE tmin.`group` = tg.grp
ORDER BY tmin.price ASC
LIMIT 1
)