oracle SQL subquery: using the minimum but getting all columns [duplicate] - sql

This question already has answers here:
Fetch the rows which have the Max value for a column for each distinct value of another column
(35 answers)
Closed 5 years ago.
MIN(A.price) CustomerID TripID travelby
25 x05 66 train
66 x07 21 train
100 x07 12 train
Trying to figure this one out. the above results is from a query of 2 tables. However, I need to modify it so that it gives me the result of min price with all of its 4 columns.
this was my original sql:
(select min(price)
from trips a, customers b
where a.tripid = b.tripid and c.travelmode = 'train')
I can only get the row with 25, but that is only if i request the price column. How would you go about this, but get all columns? Thank you for all input

SELECT *
FROM (
SELECT *
FROM trips a
INNER JOIN customers b
ON ( a.tripid = b.tripid )
WHERE travelby = 'train'
ORDER BY price ASC
)
WHERE ROWNUM = 1;
or
SELECT *
FROM (
SELECT price,
CustomerID,
a.TripID,
travelby,
ROW_NUMBER() OVER ( ORDER BY price ASC ) AS rn
FROM trips a
INNER JOIN customers b
ON ( a.tripid = b.tripid )
WHERE travelby = 'train'
ORDER BY price ASC
)
WHERE rn = 1;
Or:
SELECT MIN( price ) AS price,
MIN( CustomerID ) KEEP ( DENSE_RANK FIRST ORDER BY price, ROWNUM ) AS CustomerID,
MIN( a.TripID ) KEEP ( DENSE_RANK FIRST ORDER BY price, ROWNUM ) AS TripID,
MIN( travelby ) KEEP ( DENSE_RANK FIRST ORDER BY price, ROWNUM ) AS travelby
FROM trips a
INNER JOIN customers b
ON ( a.tripid = b.tripid )
WHERE travelby = 'train'

You can do something like this:
select . . .
from (select . . ., row_number() over (order by price desc) as seqnum
from trips t join
customers c
on c.tripid = t.tripid and ?.travelmode = 'train'
)
where seqnum = 1;
Your version of the query is quite confusing:
Why is it surrounded by parentheses?
What is c.travelmode? You haven't defined the table alias c.
Learn to use proper, explicit JOIN syntax.

Related

Return second from the last oracle sql

SELECT * FROM
(
SELECT DISTINCT(TRUNC(receipt_dstamp))
FROM inventory
WHERE substr(location_id,1,3) = 'GI-'
ORDER BY 1 ASC
)
WHERE ROWNUM <= 5
Output:
Hi all, i've got this subeqery and in this case my oldest date is in row 1, i want to retrive only second from the last(from the top in this case) which is gonna be 01-SEP-21.
I was trying to play with ROWNUM and OVER but without any results, im getting blank output.
Thank you.
Full query:
SELECT TRUNC(receipt_dstamp) as old_putaway_date, COUNT(tag_id) as tag_old_putaway
FROM inventory
WHERE substr(location_id,1,3) = 'GI-'
AND TRUNC(receipt_dstamp) IN (
SELECT * FROM
(
SELECT DISTINCT(TRUNC(receipt_dstamp))
FROM inventory
WHERE substr(location_id,1,3) = 'GI-'
ORDER BY 1 ASC
)
WHERE ROWNUM = 1
)
GROUP BY TRUNC(receipt_dstamp);
You should be able to simplify the entire query to:
SELECT old_putaway_date,
COUNT(tag_id) as tag_old_putaway
FROM (
SELECT TRUNC(receipt_dstamp) as old_putaway_date,
tag_id,
DENSE_RANK() OVER (ORDER BY TRUNC(receipt_dstamp)) AS rnk
FROM inventory
WHERE substr(location_id,1,3) = 'GI-'
)
WHERE rnk = 3
GROUP BY
old_putaway_date;
You can use dense_rank() :
SELECT * FROM (
SELECT L.*,DENSE_RANK()
OVER (PARTITION BY L.TAG_OLD_PUTAWAY ORDER BY L.OLD_PUTAWAY_DATE DESC) RNK
FROM
(
SELECT TRUNC(receipt_dstamp) as old_putaway_date, COUNT(tag_id) as tag_old_putaway
FROM inventory
WHERE substr(location_id,1,3) = 'GI-'
AND TRUNC(receipt_dstamp) IN (
SELECT * FROM
(
SELECT DISTINCT(TRUNC(receipt_dstamp))
FROM inventory
WHERE substr(location_id,1,3) = 'GI-'
ORDER BY 1 ASC
)
WHERE ROWNUM = 1
)
GROUP BY TRUNC(receipt_dstamp)
) L
) WHERE RNK = 2
You are using an old Oracle syntax that is not standard compliant in the regard that it relies on a subquery result order. (Sub)query results are unordered data sets by definition, but Oracle lets this pass in order to make their ROWNUM work with it.
Oracle now supports the standard SQL FETCH clause, which you should use instead.
SELECT DISTINCT TRUNC(receipt_dstamp) AS receipt_date
FROM inventory
WHERE SUBSTR(location_id, 1, 3) = 'GI-'
ORDER BY receipt_date
OFFSET 2 ROWS
FETCH NEXT 1 ROW ONLY;
https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6

SELECT DISTINCT UNIQUE

I have a table of products and i need to extract from each idproduct the last 3 unique records IDFornecedor, ie
image1
Result:
image2
Code:
WITH x AS (SELECT dbo.ItensDocumentos.Referencia, dbo.Documentos.Data, dbo.FacturasFornecedor.IDFornecedor, dbo.ItensDocumentos.IDProduto, dbo.Fornecedores.Nome, dbo.Documentos.BaseIncidenciaIva,
dbo.ItensDocumentos.Quantidade, dbo.ItensDocumentos.TotalIliquido / dbo.ItensDocumentos.Quantidade AS Valor
FROM dbo.ItensDocumentos INNER JOIN
dbo.Documentos ON dbo.ItensDocumentos.IDDocumento = dbo.Documentos.IDDocumento INNER JOIN
dbo.FacturasFornecedor ON dbo.Documentos.IDDocumento = dbo.FacturasFornecedor.IDDocumento INNER JOIN
dbo.Fornecedores ON dbo.FacturasFornecedor.IDFornecedor = dbo.Fornecedores.IDFornecedor
WHERE (dbo.ItensDocumentos.TotalIliquido / dbo.ItensDocumentos.Quantidade <> 0) AND dbo.Fornecedores.IDFornecedor<> 2 ),
Y AS (SELECT * FROM X),
Z AS (SELECT IDProduto,Data,Valor,IDFornecedor,Referencia,Nome,ROW_NUMBER() OVER (PARTITION BY IDProduto ORDER BY MAX(Data) DESC) AS Seq
from y
GROUP BY IDProduto,Data,Valor,IDFornecedor,Referencia,Nome)
SELECT IDProduto,Data,Valor,IDFornecedor,Referencia,Nome,Seq,PorDefeito = 0,PrazoREposicao = 0 from z WHERE Seq <= 3 order by Referencia asc
If you want the last three distinct suppliers per product, one option uses aggregation and row_number() (if your database supports window functions):
select *
from (
select
idProduto,
idFornecedor,
max(data) maxData,
row_number() over(partition by idProduto order by max(data) desc
from mytable
group by idProduto, idFornecedor
) t
where rn <= 3
order by idProduto, idFornecedor, rn desc

SQL Server different select statement on same table and different result

I have a products table that contains date-of-create, price, rate,....... and multiple columns I need one select statement that returns the 10 newest records, 10 lowest prices and the top rated products as separated result of each other something like
(select top 10 from products Order By Date ASC ) as newest_list
(select top 10 from products Order By price DESC ) as price_list
(select top 10 from products Order By Rate ASC ) as rateList_list
where ( newest_list price_list rateList_list) are different table result
Which better way to approach that result. Thanks.
You basically want union all . . . and a subquery:
select *
from ((select top 10 'newest' as which, p.*
from products p
Order By Date ASC
) union all
(select top 10 'priciest', p.*
from products p
Order By price DESC
) union all
(select top 10 'ratiest', p.*
from products p
Order By Rate ASC
)
) p
If you don't want duplicates, you can use union or window functions:
select p.*
from (select p.*,
row_number() over (order by date desc) as seqnum_d,
row_number() over (order by price desc) as seqnum_p,
row_number() over (order by rate asc) as seqnum_r
from p
) p
where seqnum_d <= 10 or seqnum_p <= 10 or seqnum_r <= 10;

MSSQL - OVER, ROW_NUMBER() and ORDER BY error

I'm trying to make a query that outputs a list with the company data and the number of Products and Discounts of each Company and order by product_count.
Also i need to limit the output to groups of 30 rows
SELECT * FROM (
SELECT *, (
SELECT COUNT(*) FROM Products WHERE Product_Comp_id = Comp_id
) as product_count, (
SELECT COUNT(*) FROM Discount WHERE Disc_Comp_id = Comp_id
) as discount_count , ROW_NUMBER() OVER (
ORDER BY product_count ASC
) AS RowNum FROM Company
) AS finalTable WHERE finalTable.RowNum BETWEEN 0 AND 30
But i get this error
Invalid column name 'product_count'.
Table Structure
Products
|-Product_id
|-Product_Name
|-Product_Description
|-Product_Comp_id
Discount
|-Disc_id
|-Disc_Name
|-Disc_Comp_id
|-Disc_Ammount
Company
|-Comp_id
|-Comp_Name
|-Comp_Address
You need an additional level of subquery to give you product_count.
SELECT * FROM (
SELECT * , ROW_NUMBER() OVER (ORDER BY product_count ASC) AS RowNum
FROM
(
SELECT *, (SELECT COUNT(*) FROM Products WHERE Product_Comp_id = Comp_id) as product_count,
(SELECT COUNT(*) FROM Discount WHERE Disc_Comp_id = Comp_id) as discount_count
FROM Company
) C
) AS finalTable WHERE finalTable.RowNum BETWEEN 0 AND 30

Limit per some field

Suppose we have such an sql query, with joined data from another table.
SELECT
pr.num, pr.resort_id, p.src_mask
FROM
rutraveler.rt_photo_resort AS pr
JOIN rutraveler.rt_photo AS p ON pr.photo_id = p.id
WHERE pr.resort_id = '612' AND p.src_mask is not null
ORDER BY num
LIMIT 30
So far we have to do several queries for several resort_id.
How to change the query so that we have only one query (WHERE resort_id in (612, 333, 111) with result no more than 30 items per each resort_id?
Use ROW_NUMBER to count the rows per resort_id.
SELECT resort_id, num, resort_id, src_mask
FROM
(
SELECT
pr.resort_id, pr.num, pr.resort_id, p.src_mask,
ROW_NUMBER() OVER (PARTITION BY pr.resort_id ORDER BY num) AS rn
FROM
rutraveler.rt_photo_resort AS pr
JOIN rutraveler.rt_photo AS p ON pr.photo_id = p.id
WHERE resort_id in (612, 333, 111) AND p.src_mask is not null
) data
WHERE rn <= 30
ORDER BY resort_id, num;
you can use CTE with ROW_NUMBER() and PARTITION BY
WITH Results_CTE AS
(
SELECT
pr.num, pr.resort_id, p.src_mask,ROW_NUMBER() over ( PARTITION BY pr.resort_id ORDER BY num) As Row_number
FROM
rutraveler.rt_photo_resort AS pr
JOIN rutraveler.rt_photo AS p ON pr.photo_id = p.id
WHERE pr.resort_id IN (A,B,C) AND p.src_mask is not null
)
SELECT *
FROM Results_CTE
WHERE Row_number <= 30