I'm trying to find the most expensive order within my table, and I've achieved this, but I'd like to know how to just return this one particular row. Right now it turns all rows with the most expensive order at the top. I'm not quite sure how to return just the most expensive order. I've grouped the orders by the order number (order_numb). I've tried using IN and a self join but I can't seem to get it to work.
My table
My current query that returns the correct result, just it returns all rows
SELECT order_numb, sum(cost_each) as totalSum
FROM order_lines
GROUP BY order_numb
ORDER BY totalSum DESC
What I'm trying to achieve
I'm trying to retrieve the most expensive order by itself.
I'm using Oracle as my database.
Use ROWNUM to filter the first row (most expensive order) of the result set:
SELECT t.*
FROM (
SELECT order_numb, sum(cost_each) as totalSum
FROM order_lines
GROUP BY order_numb
ORDER BY totalSum DESC
) t
WHERE ROWNUM <= 1
Related
i am having table having 23 records , I am trying to get total count of record and last record also in single query. something like that
select count(*) ,(m order by createdDate) from music m ;
is there any way to pull this out only last record as well as total count in PostgreSQL.
This can be done using window functions
select *
from (
select m.*,
row_number() over (order by createddate desc) as rn,
count(*) over () as total_count
from music
) t
where rn = 1;
Another option would be to use a scalar sub-query and combine it with a limit clause:
select *,
(select count(*) from order_test.orders) as total_count
from music
order by createddate desc
limit 1;
Depending on the indexes, your memory configuration and the table definition might be faster then the two window functions.
No, it's not not possible to do what is being asked, sql does not function that way, the second you ask for a count () sql changes the level of your data to an aggregation. The only way to do what you are asking is to do a count() and order by in a separate query.
Another solution using windowing functions and no subquery:
SELECT DISTINCT count(*) OVER w, last_value(m) OVER w
FROM music m
WINDOW w AS (ORDER BY date DESC RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING);
The point here is that last_value applies on partitions defined by windows and not on groups defined by GROUP BY.
I did not perform any test but I suspect my solution to be the less effective amongst the three already posted. But it is also the closest to your example query so far.
I am using SQL 2012 and trying to identify rows where the SourceDataID column has two unique entries in the PartyCode column, and I'm having difficulties.
SELECT PartyCode, SourceDataID, count (*) as CNT
FROM CustomerOrderLocation (nolock)
GROUP BY PartyCode, SourceDataID
HAVING (Count(PartyCode)>1)
ORDER BY PartyCode
Results are returning as such:
W3333 948_O 31
(party code/sourcedataid/CNT)
This is showing me the total entries where the Partycode and the SourceDataID are listed together in the table. However, I need it to show a count of any instances where W333 lists 948_O as the SourceDataID more than once.
I'm not having luck structuring the query to pull the results I am looking to get. How can I do this?
A CTE coupled with the PARTITION BY function is helpful in finding duplicates of this manner. Code below:
WITH CTE AS(
SELECT PartyCode, SourceDataID,
ROW_NUMBER()OVER(PARTITION BY SourceDataID ORDER BY SourceDataID) RN
FROM CustomerOrderLocation (NOLOCK))
SELECT * FROM CTE WHERE RN > 1
This should return every duplicate PartyCode attached to a SourceDataID.
If you want to see the entire result, change the last SELECT statement to:
SELECT * FROM CTE ORDER BY PartyCode, RN
Thanks for the help everyone. I did not do the best job of describing the issue but this is the query I ended up creating to get my result set.
;with cte1 (sourcedataid, partycode) as (select sourcedataid, partycode from customerorderparty (nolock) group by PartyCode, SourceDataID)
select count(sourcedataid), sourcedataid from cte1 group by sourcedataid having count(sourcedataid) >1
I'm trying to select the estimated hours of a row with the lowest date from a table.
SELECT prev_est_hrs
FROM ( SELECT MIN(change_date), prev_est_hrs
FROM task_history
WHERE task_id = 5
GROUP BY prev_est_hrs
);
However this is returning two rows, why? I thought MIN was supposed to return the lowest only?
Help much appreciated.
You have a GROUP BY clause. The MIN will return the minimum value in each group.
Also, you are only returning the group by value from the outer SELECT.
Mitch is right. One way to get the prev_est_hrs for the record with the earliest change_date, which seems to be what you're trying to find, is with an analytic function:
SELECT prev_est_hrs
FROM (
SELECT prev_est_hrs, ROW_NUMBER() OVER (ORDER BY change_date) AS rn
FROM task_history
WHERE task_id = 5
)
WHERE rn = 1;
You need to consider what should happen if you have two rows with the same date. This would pick one of them at random. If there is some other criteria you could use to break the tie you could add that to the order by clause. If you wanted all matching rows in that case you could use rank() instead; look at dense_rank() as well, they all have their place.
Use this query to do that:
SELECT max(prev_est_hrs) keep (dense_rank first order by change_date)
FROM task_history
WHERE task_id = 5;
I want to update the top 10 values of a column in table. I have three columns; id, account and accountrank. To get the top 10 values I can use the following:
SELECT * FROM accountrecords
ORDER BY account DESC
LIMIT 10;
What I would like to do is to set the value in accountrank to be a series of 1 - 10, based on the magnitude of account. Is this possible to do in PostgreSQL?
WITH cte AS (
SELECT id, row_number() OVER (ORDER BY account DESC NULLS LAST) AS rn
FROM accountrecords
ORDER BY account DESC NULLS LAST
LIMIT 10
)
UPDATE accountrecords a
SET accountrank = cte.rn
FROM cte
WHERE cte.id = a.id;
Joining in a table expression is typically faster than correlated subqueries. It is also shorter.
With the window function row_number() distinct numbers are guaranteed. Use rank() (or possibly dense_rank()) if you want rows with equal values for account to share the same number.
Only if there can be NULL values in account, you need to append NULLS LAST for descending sort order, or NULL values sort on top:
Sort by column ASC, but NULL values first?
If there can be concurrent write access, the above query is subject to a race condition. Consider:
Atomic UPDATE .. SELECT in Postgres
Postgres UPDATE … LIMIT 1
However, if that was the case, the whole concept of hard-coding the top ten would be a dubious approach to begin with.
Use a CTE instead of a plain subquery to enforce the LIMIT reliably. See links above.
Sure, you can use your select statement in a subquery. Generating the rank-order isn't trivial, but here's at least one way to do it. I haven't tested this, but off the top of my head:
update accountrecords
set accountrank =
(select count(*) + 1 from accountrecords r where r.account > account)
where id in (select id from accountrecords order by account desc limit 10);
This has the quirk that if two records have the same value for account, then they will get the same rank. You could consider that a feature... :-)
In SQL 2005/2008 database we have table BatchMaster. Columns:
RecordId bigint - autoincremental id, BatchNumber bigint - unique non-clustered index, BatchDate). We have sproc that returns paginated data from this table. That sproc works fine for most of the clients, but at one SQL server instance we have problem with records order.
In general, at sproc we do
select * from
(
select row_number() over (order by bm.BatchDate desc, bm.BatchNumber desc) as Row,
*
from dbo.BatchMaster bm with (nolock)
)
where Row between #StartingRow and #EndgingRow
So, as you can notice from the script above we want return records sorted by BatchDate and BatchNumber. That's not gonna happen for one of our client:
Records are in wrong order. Also, notice first column (Row), it is not in ascending order.
Can someone explain why so?
Assuming you want the lowest BatchNumber for a given BatchDate with the smallest Row number and that you want orderer by the Row, try this:
select * from
(
select row_number() over (order by bm.BatchDate desc, bm.BatchNumber asc) as Row,
*
from dbo.BatchMaster bm with (nolock)
)
where Row between #StartingRow and #EndgingRow
order by Row
Your code doesn't actually sort the results, it only sets 'Row' based on the order of BatchDate and Batchnumber and appears to be doing that correctly. You need to add ORDER BY Row to your statement.
Change your query to include a sort in the outermost query
select * from
(
select row_number() over (order by bm.BatchDate desc, bm.BatchNumber desc) as Row,
*
from dbo.BatchMaster bm with (nolock)
)
where Row between #StartingRow and #EndgingRow
order by Row
The ORDER BY clause in your ROW_NUMBER ranking function only applies to calculating the value of that ranking function, it does not actually order the results.
If you would like the records returned in a certain order you will need specify that in your query: ORDER BY [Row]