How to find the top n quantities within a table - sql

Suppose in the table mentioned below, I wanted to select the top 3 quantities and if there are duplicates, I want them too and the required table is mentioned below too.
For this requirement, I tried something like the SQL below.
select name, quantity
from employee
order by name,quantity DESC
FETCH FIRST 3 ROWS WITH TIES;
But I'm not able to get any meaningful output. BTW I'm using postgres.
All I need is employee info along with quantities with 3 max quantities along with ties if any.
NAME | Quantity
---------
AAA 500
AAA 500
AAA 400
AAA 300
AAA 200
AAA 100
Required Table:
NAME | Quantity
--------------
AAA 500
AAA 500
AAA 400
AAA 300
```

This can be achieved by using dense_rank.
select "NAME"
,"Quantity"
from (
select *
,dense_rank() over(order by "Quantity" desc) as dr
from t
) t
where dr <= 3
NAME
Quantity
AAA
500
AAA
500
AAA
400
AAA
300
Fiddle

Related

How do I return a key value when a specific column value is NOT present?

Here's a simplified example of my SALESORDERLINES table:
ORDER
LINE
ITEM
100
1
ITEMA
100
2
ITEMB
100
3
FEE
101
1
ITEMA
101
2
FEE
102
1
ITEMC
102
2
ITEMD
102
3
ITEME
103
1
ITEMA
103
2
FEE
104
1
ITEMB
104
2
ITEMC
The key values for the table are ORDER and LINE.
The last line item of each order is supposed to be item "FEE", but occasionally order entry forgets to include it. I'm trying to find every instance where they failed to include the fee on the order.
So for the example data above, I would want to return order numbers 102 and 104 only.
Any ideas?
Just a guess since you don't specify what resultset you desire. And surely there is another table that you did not include that represents "orders" - perhaps named SALESORDERS?
Assuming that, then I suggest:
select ord."ORDER" -- a terrible idea to use reserved words as names
from dbo.SALESORDERS as ord
where not exists (select * from dbo.SALESORDERLINES as ordlines
where ord."ORDER" = ordlines."ORDER" and ordlines.ITEM = 'FEE')
order by ...;
Certainly there are other ways. EXCEPT comes to mind.
Try this :
SELECT ORDER
FROM TableA
WHERE ORDER NOT IN (
SELECT ORDER
FROM TableA
WHERE ITEM = 'FEE'
GROUP BY ORDER)
GROUP BY ORDER

How to get latest records based on two columns of max

I have a table called Inventory with the below columns
item warehouse date sequence number value
111 100 2019-09-25 12:29:41.000 1 10
111 100 2019-09-26 12:29:41.000 1 20
222 200 2019-09-21 16:07:10.000 1 5
222 200 2019-09-21 16:07:10.000 2 10
333 300 2020-01-19 12:05:23.000 1 4
333 300 2020-01-20 12:05:23.000 1 5
Expected Output:
item warehouse date sequence number value
111 100 2019-09-26 12:29:41.000 1 20
222 200 2019-09-21 16:07:10.000 2 10
333 300 2020-01-20 12:05:23.000 1 5
Based on item and warehouse, i need to pick latest date and latest sequence number of value.
I tried with below code
select item,warehouse,sequencenumber,sum(value),max(date) as date1
from Inventory t1
where
t1.date IN (select max(date) from Inventory t2
where t1.warehouse=t2.warehouse
and t1.item = t2.item
group by t2.item,t2.warehouse)
group by t1.item,t1.warehouse,t1.sequencenumber
Its working for latest date but not for latest sequence number.
Can you please suggest how to write a query to get my expected output.
You can use row_number() for this:
select *
from (
select
t.*,
row_number() over(
partition by item, warehouse
order by date desc, sequence_number desc, value desc
) rn
from mytable t
) t
where rn = 1

Concatenating data from one row into the results from another

I have a SQL Server database of orders I'm struggling with. For a normal order a single table provides the following results:
Orders:
ID Customer Shipdate Order ID
-----------------------------------------------------------------
1 Tom 2015-01-01 100
2 Bob 2014-03-20 200
At some point they needed orders that were placed by more than one customer. So they created a row for each customer and split the record over multiple rows.
Orders:
ID Customer Shipdate Order ID
-----------------------------------------------------------------
1 Tom 2015-01-01 100
2 Bob 2014-03-20 200
3 John
4 Dan
5 2014-05-10 300
So there is another table I can join on to make sense of this which relates the three rows which are actually one order.
Joint.Orders:
ID Related ID
-----------------------------------------------------------------
5 3
5 4
I'm a little new to SQL and while I can join on the other table and filter to only get the data relating to Order ID 300, but what I'd really like is to concatenate the customers, but after searching for a while I can't see how to do this. What'd I'd really like to achieve is this as an output:
ID Customer Shipdate Order ID
----------------------------------------------------------------
1 Tom 2015-01-01 100
2 Bob 2014-03-20 200
5 John, Dan 2014-05-10 300
You should consider changing the schema first. The below query might help you get a feel of how it can be done with your current design.
Select * From Orders Where IsNull(Customer, '') <> ''
Union All
Select ID,
Customer = (Select Customer + ',' From Orders OI Where OI.ID (Select RelatedID from JointOrders JO Where JO.ID = O.ID)
,ShipDate, OrderID
From Orders O Where IsNull(O.Customer, '') = ''

Grand Sum with distinct in SQL Server

I have a table in which has duplicate values. by eliminating these values I want sum of distinct values. but without group by.
My table
--------------------------------------
ID City collection
---------------------------------------
1 xyz 5000
2 xyz 5000
3 abc 2000
4 pqr 3000
5 xyz 5000
6 pqr 3000
7 abc 2000
-----------------------------------
I want result of whole collection column but eliminate city name
ex. Result = 10000
not like
xyz 15000
abc 4000
pqr 6000
or not like 25000
but result should be 10000 by eliminated
Get the Distinct combinations of City and Collection first and then do the SUM
select SUM(Collection) as Collection
from
(
select distinct City, Collection
from table
) data
select sum(collection) as output
from
(
select collection, row_number() over(partition by city order by collection) as RN
from yourtable
) as inside
where RN=1
If you just want the sum of the distinct values of the collections column without the city name (I assume this is what you want from your statement "but eliminate city name") then simply run this:
SELECT SUM(DISTINCT [collection]) FROM tableName
This will return the value 10000 like you are after.

Problems with group by and order by

Hi I am a newbie to the world of sql but struggling to get some of the basics to work.
I have a set of data that looks like this:
Table name: Sample
PROJECT WORK ORDER AMOUNT
-----------------------------------------
111 a 100
222 b 200
111 c 300
444 d 400
111 e 500
666 f 600
I want it to end up looking like this:
Table name: Sample
PROJECT WORK ORDER AMOUNT PROJECT AMOUNT
--------------------------------------------------------
111 e 500 900
111 c 300 900
111 a 100 900
666 f 600 600
444 d 400 600
222 b 200 200
Sorted by project with the greatest TOTAL amount
Group by does not work for me as it groups all projects into one, so I can't see the 3 work order lines for "Project 111"
PROJECT WORK ORDER AMOUNT
-----------------------------------------
111 a 900
222 b 200
444 d 400
666 f 600
Order by does not work as I can't get it sort it out on the basis of the greatest project value
Table name: Sample
PROJECT WORK ORDER AMOUNT
-----------------------------------------
666 f 600
111 e 500
444 d 400
111 c 300
222 b 200
111 a 100
My alternative idea was if I could create another column "Project Amount" that calculates the projects total based on values in "Project" column and I can then easily sort it by Project Amount instead to achieve the desired format
Table name: Sample
PROJECT WORK ORDER AMOUNT PROJECT AMOUNT
--------------------------------------------------------
111 e 500 900
111 c 300 900
111 a 100 900
666 f 600 600
444 d 400 600
222 b 200 200
But I am struggling how to get column "Project Amount" to calculate all the projects total value and present them on any rows that appear with the same project number.
Any advise?
select *
, sum(amount) over (partition by project) as ProjAmount
, row_number() over
from YourTable
order by
ProjAmount desc
Example at SQL Fiddle.
To select only the top two projects with the highest amounts, you could use dense_rank:
select *
from (
select *
, dense_rank() over (order by ProjAmount desc) as dr
from (
select *
, sum(amount) over (partition by project) as ProjAmount
from YourTable
) WithProjAmount
) WithDenseRank
where dr < 3
order by
ProjAmount desc
Example at SQL Fiddle.
A version with plain SQL subquery
SELECT s.*,
(SELECT SUM(Amount) FROM Sample WHERE Project = s.Project) ProjectAmount
FROM Sample s
ORDER BY ProjectAmount DESC
SQLFiddle
SELECT a.project ,
a.work ,
a.amount ,
b.proj_amount
FROM project A
JOIN ( SELECT SUM(amount) proj_amount ,
project
FROM project
WHERE project = project
GROUP BY project
) b ON a.project = b.project
ORDER BY proj_amount DESC ,
amount DESC