SQL Nested Queries, Max, Grouping - sql

My table (named Inventory) is the following:
InventoryType,LocationID,InventoryLevel,SafetyStock,MaxLevel,ModifiedAt
Erasors,1,14,3,15,11-2014
Erasors,2,4,10,50,10-2014
Erasors,2,5,10,50,11-2014
Pencils,1,10,5,45,11-2014
Pencils,2,23,15,50,11-2014
Pens,1,9,10,50,11-2014
Pens,2,55,10,50,12-2014
There are three primary keys: InventoryType, LocationID, and ModifiedAt.
Given a specified LocationID, I'd like the query to return all for each distinct InventoryType where the date for each tuple returned is the most recent ModifiedAt date among records for that given inventory type with the specified LocationID. Eg, LocationID = 2 would return:
InventoryType,LocationID,InventoryLevel,SafetyStock,MaxLevel,ModifiedAt
Erasors,2,5,10,50,11-2014
Pencils,2,23,15,50,11-2014
Pens,2,55,10,50,12-2014
My attempt thus far is the following:
SELECT InventoryType, LocationID, InventoryLevel,
SafetyStock, MaxLevel, ModifiedAt
FROM Inventory
WHERE LocationID = 2 AND ModifiedAt IN
(SELECT TOP 1 ModifiedAt
FROM Inventory
WHERE LocationID = 2
ORDER BY ModifiedAt DESC);
My query returns:
InventoryType,LocationID,InventoryLevel,SafetyStock,MaxLevel,ModifiedAt
Pens,2,55,10,50,12-2014
Any help would be appreciated.

You need a correlated subquery. Try this instead:
SELECT InventoryType, LocationID, InventoryLevel, SafetyStock, MaxLevel, ModifiedAt
FROM Inventory as i
WHERE LocationID = 2 AND
ModifiedAt IN (SELECT TOP 1 i2.ModifiedAt
FROM Inventory as i2
WHERE i2.LocationID = 2 AND i2.InventoryType = i.InventoryType
ORDER BY i2.ModifiedAt DESC
);

Use SELECT DISTINCT for selecting distinct InventoryType.
SELECT DISTINCT InventoryType, LocationID,
InventoryLevel, SafetyStock, MaxLevel, ModifiedAt
FROM Inventory
WHERE LocationID = 2
AND ModifiedAt IN
(SELECT TOP 1 ModifiedAt FROM Inventory WHERE LocationID = 2 ORDER BY ModifiedAt DESC)

Related

Only run SQL Query if there are multiple rows

I have a table similar to the below - OrderStatusId is the PK on the table. StatusId is a FK to the Reference Table that contains all the possible statuses. CustomerId is a FK to the Customer Details table
OrderStatusId StatusId CustomerId DateModified
1 1 1 05/09/2017
2 1 1 06/09/2017
3 2 1 07/09/2017
4 1 2 07/09/2017
What I want to do is run this query below to select the most recent Modified Date for that Customer for Status ID = 1. However, I only want to run this query if there is a count greater than 1 for the StatusId = 1 for that customer. So in my sample table above I would expect 06/09/2017 returned for CustomerId 1 but nothing to be returned for CustomerId 2. I tried a Having count(*) > 1 clause but could not get it working correctly.
SELECT TOP(1) os.DateModified AS LastModifiedDateForm
FROM [myTable].[OrderStatus] os WHERE os.CustomerId = 1 AND os.StatusID = 1
ORDER BY os.DateModified DESC
can you just use MAX instead of top 1? or are you returning more columns?
SELECT MAX(os.DateModified) AS LastModifiedDateForm
FROM [myTable].[OrderStatus] os
WHERE os.CustomerId = 1
AND os.StatusID = 1
GROUP BY CustomerId,
StatusId
HAVING COUNT(*) > 1
Maybe you are after the maximum date per customer, only if they have more than one date?
select max(os.DateModified) AS LastModifiedDateForm
from [myTable].[OrderStatus] os
group by os.CustomerId
having count(1) > 1
This will only give you data for customer with id 1, in the current situation, or every other customer id that has more than 1 row for some other sample data.
another approach using ROW_NUMBER()
with firstonly as (
select CustomerId, DateModified, ROW_NUMBER() over (partiton by CustomerId order by DateModified desc) rownumDesc, ROW_NUMBER() over (partiton by CustomerId order by DateModified) rownumAsc
FROM [myTable].[OrderStatus] os WHERE os.CustomerId = 1 AND os.StatusID = 1
)
select *
from firstonly
where rownumDesc = 1
and rownumAsc != 1
;
works for all customers at once

display max on one columns with multiple columns in output

How can I display maximum OrderId for a CustomerId with many columns?
I have a table with following columns:
CustomerId, OrderId, Status, OrderType, CustomerType
A customer with Same customer id could have many order ids(1,2,3..) I want to be able to display the max Order id with the rest of the customers in a sql view. how can I achieve this?
Sample Data:
CustomerId OrderId OrderType
145042 1 A
110204 1 C
145042 2 D
162438 1 B
110204 2 B
103603 1 C
115559 1 D
115559 2 A
110204 3 A
I'd use a common table expression and ROW_NUMBER:
;With Ordered as (
select *,
ROW_NUMBER() OVER (PARTITION BY CustomerID
ORDER BY OrderId desc) as rn
from [Unnamed table from the question]
)
select * from Ordered where rn = 1
select * from table_name
where orderid in
(select max(orderid) from table_name group by customerid)
One way to do this is with not exists:
select t.*
from table t
where not exists (select 1
from table t2
where t2.CustomerId = t.CustomerId and
t2.OrderId > t.OrderId
);
This is saying: "get me all rows from t where there is no higher order id for the customer."

SQL Group By Question

I have a table which tracks views of products.
TrackId ProductId CreatedOn
1 1 01/01/2011
2 4 01/01/2011
3 4 01/01/2011
4 10 01/01/2011
What I want to do is return a dataset which doesn't have two ProductIds next to each other. I.E from the above data set I would want to return:
TrackId ProductId CreatedOn
1 1 01/01/2011
2 4 01/01/2011
4 10 01/01/2011
I can't use distinct as far as I am aware as this is row based?
Help appreciated.
Generate a row number sequence per ProductID, take the first
;WITH cte AS
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY ProductID ORDER BY TrackID) AS rn
FROM
MyProductTable
)
SELECT
TrackId ProductId CreatedOn
FROM
cte
WHERE
rn = 1
Edit:
If you want to use an aggregate, you need a separate subquery first to ensure consistent results. A straight MIN won't work.
This is based on my comment to the question
"not having productid in two adjacent rows. Adjacent is defined by next/previous Trackid"
SELECT
M.*
FROM
myProductTable M
JOIN
( --gets the lowest TrackID for a ProductID
SELECT ProductID, MIN(TrackID) AS MinTrackID
FROM myProductTable
GROUP BY ProductID
) M2 ON M.ProductID= M2.ProductID AND M.TrackID= M2.MinTrackID
select min(TrackId), ProductId, CreatedOn
from YourTable
group by ProductId, CreatedOn;
You can GroupBy on the TrackID and ProductID and do a Min of the CreatedOn if the date is not important.
SELECT TrackID ,ProductID ,MIN(CreatedOn)
FROM [table]
GROUP BY TrackID ,ProductID
If the date is the same you can group by all three
SELECT TrackID ,ProductID ,CreatedOn
FROM [table]
GROUP BY TrackID ,ProductID ,CreatedOn

Getting more details out of a SQL subquery

I have a SQL Query giving me a list of double records in my database.
select periodid, itemid from periodscore
group by periodid, itemid
having count(*) > 1
This works as expected, but now I would like to retrieve additional fields of these records (such as date last updated etc). So I tried:
select * from periodscore where periodscoreid in
(select periodscoreid from periodscore
group by periodid, itemid
having count(*) > 1)
Of course this doesn't work and gives me the error:
Column 'periodscore.PeriodScoreID' is
invalid in the select list because it
is not contained in either an
aggregate function or the GROUP BY
clause.
How can I retrieve the extra fields in this query?
select ps.*
from periodscore ps
inner join (
select periodid, itemid
from periodscore
group by periodid, itemid
having count(*) > 1
) psm on ps.periodid = psm.periodid and ps.itemid = psm.itemid
select p1.* from periodscore p1 JOIN
(select periodid, itemid from periodscore
group by periodid, itemid
having count(*) > 1) p2
ON (p1.periodId = p2.periodId
AND p1.itemid = p2.itemid)
if periodid or item have null values then
select p1.* from periodscore p1 JOIN
(select periodid, itemid from periodscore
group by periodid, itemid
having count(*) > 1) p2
ON (IFNULL(p1.periodId,0) = IFNULL(p2.periodId,0))
AND IFNULL(p1.itemid,0) = IFNULL(p2.itemid,0))

How can I select the entire row when using max

I have a table with the following columns:
SignatureID
PatientID
PatientVisitID
TreatAuthDate
HIPAADate
DrugTestDate
Now I have the following Select statement:
SELECT *
FROM tblSignature
WHERE PatientID = 12345
This select statement returns 8 rows. What I need to accomplish is getting the MAX TreatAuthDate - and with that MAX TreatAuthDate I need the PatientVisitID. Then I need the same type of information for the HipaaDate and DrugTestDate. How can I do this?
SELECT TOP 1 *
FROM tblSignature
WHERE PatientID = 12345
ORDER BY
TreatAuthDate DESC
To get three last results for different definitions of "last", use this:
SELECT *
FROM (
SELECT TOP 1 'LastThreatAuth' AS which, ts.*
FROM tblSignature ts
WHERE PatientID = 12345
ORDER BY
TreatAuthDate DESC
) SrcTreatAuth
UNION ALL
SELECT *
FROM (
SELECT TOP 1 'LastHIPAA' AS which, ts.*
FROM tblSignature ts
WHERE PatientID = 12345
ORDER BY
HIPAADate DESC
) SrcHIPAA
UNION ALL
SELECT *
FROM (
SELECT TOP 1 'LastDrugTest' AS which, ts.*
FROM tblSignature ts
WHERE PatientID = 12345
ORDER BY
DrugTestDate DESC
) SrcDrugTest
SELECT patientid, max(Treatauthdate), max (HippaDAte) , max (DrugTestDate)
FROM tblSignature
WHERE PatientID = 12345
group by patientid
Note you can't ask for signatureid in this case as you would not filter any records out (I'm making the assumption signatureid is your PK). Further to get the max of each date per patient, it is likely they are each on a differnt row of the table so would not have the same signatureid.
To get the visit date for each type might be more difficult as each may be a separate visit.
try something like
select a.patientid, Treatvisitdate, Treatauthdate,Hippavisitdate, HippaDate, DrugTestvisitdate,
DrugTestDate
(SELECT patientid, patientvisitdate as Treatvisitdate, max(Treatauthdate) as Treatauthdate
FROM tblSignature
WHERE PatientID = 12345
group by patientid,patientvisitdate)a
join
(SELECT patientid, patientvisitdate as Hippavisitdate, max(HippaDate) as HippaDate
FROM tblSignature
WHERE PatientID = 12345
group by patientid,patientvisitdate) b on a.patientid = b.patientid
join
(SELECT patientid, patientvisitdate as DrugTestvisitdate, max(DrugTestDate) as DrugTestDate
FROM tblSignature
WHERE PatientID = 12345
group by patientid,patientvisitdate) c on a.patientid = c.patientid
YOu might need left joins if some of the dates might not be in there.