SQL max function with another condition not working - sql

This works perfectly until an order comes in where the stationID is not =2. My logic would be that sql searches where both conditions meet and display those results and not look where timeplaced is max then if stationid does not =2 display nothing which is what its doing.
SELECT OrderNo
FROM Orders
WHERE TimePlaced = (SELECT max(TimePlaced) FROM Orders)
AND StationID=2

Add your condition into the inner select too
SELECT OrderNo
FROM Orders
WHERE TimePlaced =
(
SELECT max(TimePlaced)
FROM Orders
WHERE StationID=2
)
AND StationID=2
But if you do not want to add the condition twice, then just "link" the inner select with the outer:
SELECT OrderNo
FROM Orders O
WHERE TimePlaced =
(
SELECT max(TimePlaced)
FROM Orders
WHERE StationID=O.StationID
)
AND StationID=2
Another way you could try would be with using a CTE and ROW_NUMBER:
;WITH OrdersCTE AS
(
SELECT *,
ROW_NUMBER() OVER(PARTITION BY StationID ORDER BY TimePlaced Desc) AS rn
FROM Orders
)
SELECT *
FROM OrdersCTE
WHERE rn = 1
AND StationID = 2

Related

Using rownum in sub query on oracle 11

I have query like this.It is working properly on oracle 12.
select * from customers where customerId IN (select custId from Orders where
orderStatus = 'S' and orderCity = 'Amsterdam' and ORDER BY custId DESC FETCH FIRST 10 ROWS ONLY)
But I am using oracle 11.That query is not working on oracle 11.Therefore I changed my query like that
select * from customers where customerId IN (select custId from Orders where
orderStatus = 'S' and orderCity = 'Amsterdam' and ORDER BY custId DESC rownum <= 10)
It gives missing right paranthesis
How can I solve this problem.Do you have any idea?Actually I use a variable instead on 10 number.
Syntax is a bit different - you need an extra subquery so it would need to be more like ...
where customerId IN (select * from (select custId from Orders where orderStatus = 'S' and orderCity = 'Amsterdam' and ORDER BY custId DESC) where rownum <=10)
You wouldn't need the extra subquery if you didn't have the order by clause
For ref see https://docs.oracle.com/cd/B19306_01/server.102/b14200/pseudocolumns009.htm#:~:text=For%20each%20row%20returned%20by,has%202%2C%20and%20so%20on.
I would phrase this with exists and row_number():
select c.*
from customers
where exists (
select 1
from (
select custId, row_number() over(order by custid desc) rn
from orders
where orderStatus = 'S' and orderCity = 'Amsterdam'
) o
where o.rn <= 10 and o.cusid = c.customerid
)
row_number() ranks orders by descending customer id in the subquery. Then, we filter on the first 10 rows, and use exists to filter the corresponding rows in the outer query.

Select every second record then determine earliest date

I have table that looks like the following
I have to select every second record per PatientID that would give the following result (my last query returns this result)
I then have to select the record with the oldest date which would be the following (this is the end result I want)
What I have done so far: I have a CTE that gets all the data I need
WITH cte
AS
(
SELECT visit.PatientTreatmentVisitID, mat.PatientMatchID,pat.PatientID,visit.RegimenDate AS VisitDate,
ROW_NUMBER() OVER(PARTITION BY mat.PatientMatchID, pat.PatientID ORDER BY visit.VisitDate ASC) AS RowNumber
FROM tblPatient pat INNER JOIN tblPatientMatch mat ON mat.PatientID = pat.PatientID
LEFT JOIN tblPatientTreatmentVisit visit ON visit.PatientID = pat.PatientID
)
I then write a query against the CTE but so far I can only return the second row for each patientID
SELECT *
FROM
(
SELECT PatientTreatmentVisitID,PatientMatchID,PatientID, VisitDate, RowNumber FROM cte
) as X
WHERE RowNumber = 2
How do I return the record with the oldest date only? Is there perhaps a MIN() function that I could be including somewhere?
If I follow you correctly, you can just order your existing resultset and retain the top row only.
In standard SQL, you would write this using a FETCH clause:
SELECT *
FROM (
SELECT
visit.PatientTreatmentVisitID,
mat.PatientMatchID,
pat.PatientID,
visit.RegimenDate AS VisitDate,
ROW_NUMBER() OVER(PARTITION BY mat.PatientMatchID, pat.PatientID ORDER BY visit.VisitDate ASC) AS rn
FROM tblPatient pat
INNER JOIN tblPatientMatch mat ON mat.PatientID = pat.PatientID
LEFT JOIN tblPatientTreatmentVisit visit ON visit.PatientID = pat.PatientID
) t
WHERE rn = 2
ORDER BY VisitDate
OFFSET 0 ROWS FETCH FIRST 1 ROW ONLY
This syntax is supported in Postgres, Oracle, SQL Server (and possibly other databases).
If you need to get oldest date from all selected dates (every second row for each patient ID) then you can try window function Min:
SELECT * FROM
(
SELECT *, MIN(VisitDate) OVER (Order By VisitDate) MinDate
FROM
(
SELECT PatientTreatmentVisitID,PatientMatchID,PatientID, VisitDate,
RowNumber FROM cte
) as X
WHERE RowNumber = 2
) Y
WHERE VisitDate=MinDate
Or you can use SELECT TOP statement. The SELECT TOP clause allows you to limit the number of rows returned in a query result set:
SELECT TOP 1 PatientTreatmentVisitID,PatientMatchID,PatientID, VisitDate FROM
(
SELECT *
FROM
(
SELECT PatientTreatmentVisitID,PatientMatchID,PatientID, VisitDate,
RowNumber FROM cte
) as X
WHERE RowNumber = 2
) Y
ORDER BY VisitDate
For simplicity add order desc on date column and use TOP to get the first row only
SELECT TOP 1 *
FROM
(
SELECT PatientTreatmentVisitID,PatientMatchID,PatientID, VisitDate, RowNumber FROM cte
) as X
WHERE RowNumber = 2
order by VisitDate desc

Filter the table with latest date having duplicate OrderId

I have following table:
I need to filter out the rows for which start date is latest corresponding to its order id .With reference to given table row no 2 and 3 should be the output.
As row 1 and row 2 has same order id and order date but start date is later than first row. And same goes with row number 3 and 4 hence I need to take out row no 3 . I am trying to write the query in SQL server. Any help is appreciated.Please let me know if you need more details.Apologies for poor English
You can do this easily with a ROW_NUMBER() windowed function:
;With Cte As
(
Select *,
Row_Number() Over (Partition By OrderId Order By StartDate Desc) RN
From YourTable
)
Select *
From Cte
Where RN = 1
But I question the StartDate datatype. It looks like these are being stored as VARCHAR. If that is the case, you need to CONVERT the value to a DATETIME:
;With Cte As
(
Select *,
Row_Number() Over (Partition By OrderId
Order By Convert(DateTime, StartDate) Desc) RN
From YourTable
)
Select *
From Cte
Where RN = 1
Another way using a derived table.
select
t.*
from
YourTable t
inner join
(select OrderId, max(StartDate) dt
from YourTable
group by OrderId) t2 on t2.dt = t.StartDate and t2.OrderId = t.OrderId

Want result with out using subquery?

SELECT
ROW_NUMBER()over(partition by tblProductTemplateHdr.product_ID
order by tblProductTemplateHdr.product_ID, tblProcessSequence.sl_No) AS rno,
tblProductTemplateHdr.product_ID
,tblProductProcessHdr.process_ID
,tblProcessSequence.sl_No
FROM
Production.tblProcessSequence
INNER JOIN
Production.tblProductProcessHdr ON tblProductProcessHdr.product_Process_ID = tblProcessSequence.product_Process_ID AND tblProductProcessHdr.isQC_Need = 1
INNER JOIN
Production.tblProductTemplateHdr ON tblProductTemplateHdr.product_Temp_ID = tblProductProcessHdr.product_Temp_ID
I want the row with maximum sl_No in each product_Id without using a subquery, this the result obtained by running this query want to apply filtering on same query
You need to a) rewrite your query just a little, and b) I'd recommend using table aliases to make your query more readable.
Try this:
;WITH ProductData AS
(
SELECT
ROW_NUMBER() OVER (PARTITION BY pth.Product_ID
ORDER BY pth.Product_ID, ps.sl_No DESC) AS rno,
tph.product_ID,
tph.process_ID,
ps.sl_No
FROM
Production.tblProcessSequence ps
INNER JOIN
Production.tblProductProcessHdr pph ON tph.product_Process_ID = ps.product_Process_ID
AND pph.isQC_Need = 1
INNER JOIN
Production.tblProductTemplateHdr tph ON tph.product_Temp_ID = pph.product_Temp_ID
)
SELECT *
FROM
ProductData
WHERE
rno = 1
The ROW_NUMBER() function partitions your data by Product_ID and within each partition, it orders the rows by sl_No DESC - so the highest value of sl_No gets the rno = 1 value (all others get higher numbers, in each partition)
You can use another windowed function:
MAX(tblProcessSequence.sl_No) OVER(PARTITION BY tblProductTemplateHdr.product_ID)
ADDENDUM
Just to give the full query in context in case the above was not clear:
SELECT ROW_NUMBER() OVER (PARTITION BY tempHdr.Product_ID ORDER BY Seq.sl_No DESC) AS rno,
tempHdr.product_ID,
procHdr.process_ID,
Seq.sl_No,
MAX(Seq.sl_No) OVER(PARTITION BY tblProductTemplateHdr.Product_ID) AS Max_SL_No
FROM Production.tblProcessSequence Seq
INNER JOIN Production.tblProductProcessHdr procHdr
ON Seq.product_Process_ID = tblProductProcessHdr.product_Process_ID
AND procHdr.isQC_Need = 1
INNER JOIN Production.tblProductTemplateHdr tempHdr
ON tempHdr.product_Temp_ID = procHdr.product_Temp_ID

SQL Query, SELECT Top 2 by Foreign Key Order By Date

I need a SQL query that returns the top 2 Plans by PlanDate per ClientID. This is all on one table where PlanID is the PrimaryID, ClientID is a foreignID.
This is what I have so far -->
SELECT *
FROM [dbo].[tblPlan]
WHERE [PlanID] IN (SELECT TOP (2) PlanID FROM [dbo].[tblPlan] ORDER BY [PlanDate] DESC)
This, obviously, only returns 2 records where I actually need up to 2 records per ClientID.
This can be done using ROW_NUMBER:
SELECT PlanId, ClientId, PlanDate FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY ClientId ORDER BY PlanDate DESC) rn, *
FROM [dbo].[tblPlan]
) AS T1
WHERE rn <=2
Add any other columns you need to the select to get those too.
Edit, Dec 2011. Corrected CROSS APPLY solution
Try both to see what is best
SELECT *
FROM
( -- distinct ClientID values
SELECT DISTINCT ClientID
FROM [dbo].[tblPlan]
) P1
CROSS APPLY
( -- top 2 per ClientID
SELECT TOP (2) P2.PlanID
FROM [dbo].[tblPlan] P2
WHERE P1.ClientID = P2.ClientID
ORDER BY P2.[PlanDate] DESC
) foo
Or
;WITH cTE AS (
SELECT
*,
ROW_NUMBER () OVER (PARTITION BY clientid ORDER BY [PlanDate] DESC) AS Ranking
FROM
[dbo].[tblPlan]
)
SELECT * FROM cTE WHERE Ranking <= 2