SQL MAX in two columns by statistic - sql

I have this query:
DECLARE #startTime DATETIME = DATEADD(MINUTE, -100, GETDATE()) --StartTime
SELECT
COUNT(*) Frecuency, mes.receivedqty AS Qty, ac.item AS Item
FROM
mesReservationReceipts mes (nolock)
INNER JOIN
ACCS_Reservation ac (nolock) ON ac.IDReservation = mes.idReservation
WHERE
ac.item IN (SELECT ac2.item
FROM mesReservationReceipts m2
INNER JOIN ACCS_Reservation ac2 ON ac2.IDReservation = m2.idReservation
WHERE m2.receivedate > #startTime)
GROUP BY
mes.receivedqty, ac.item
I get this result, but only I want the yellow highlighted rows - how can I get those? Please help!:
Note: I tried with MAX(Frequency) but that does not work because it should be grouped by the qty, and its the same case. I put a MAX(Qty), but for example, if the Qty is more than Statistic, add in the table result (and I only want the real statistic qty).

You can write something like this
SELECT * FROM(SELECT Frequency,Receivedqty,Item,
ROW_NUMBER() OVER(Partition by Item ORDER BY Quantity desc) as RowId
FROM (
----your query-----
))as q
Where q.RowId = 1

You can use row_number() to get the highest amount in each column. Then filter:
select item, Frecuency, qty
from (select ac.item as Item, count(*) as Frecuency, mes.receivedqty as Qty,
row_number() over (order by count(*) desc) as seqnum_f,
row_number() over (order by mes.receivedqty desc) as seqnum_r
from mesReservationReceipts mes join
ACCS_Reservation ac
on ac.IDReservation = mes.idReservation
where ac.item in (select ac2.item
from mesReservationReceipts m2 inner join
ACCS_Reservation ac2
on ac2.IDReservation = m2.idReservation
where m2.receivedate > #startTime
)
group by mes.receivedqty, ac.item
) ma
where 1 in (seqnum_f, seqnum_r);
Use rank() if you want duplicates, in the event that the highest values have duplicates.

Related

SQL query to get first and last of a sequence

With the following query ...
select aa.trip_id, aa.arrival_time, aa.departure_time, aa.stop_sequence, aa.stop_id, bb.stop_name
from OeBB_Stop_Times aa
left join OeBB_Stops bb on aa.stop_id = bb.stop_id
I get the following table:
Now I want the first and last line/value from the column stop_sequence referring to column trip_id, so the result should be:
How can I do that?
Thanks
You can do a sub-query to get the min and max and join against that data.
Like this:
select aa.trip_id, aa.arrival_time, aa.departure_time, aa.stop_sequence, aa.stop_id, bb.stop_name
from OeBB_Stop_Times aa
join (
SELECT trip_id, max(stop_sequence) as max_stop, min(stop_sequence) as min_stop
FROM OeBB_Stop_Times
GROUP BY trip_di
) sub on aa.trip_id = sub.trip_id AND (aa.stop_sequence = sub.max_stop or aa.stop_sequence = sub.min_stop)
left join OeBB_Stops bb on aa.stop_id = bb.stop_id
You can use the ROW_NUMBER() window function twice to filter out rows, as in:
select *
from (
select *,
row_number() over(partition by trip_id order by arrival_time) as rn,
row_number() over(partition by trip_id order by arrival_time desc) as rnr
from OeBB_Stop_Times
) x
where rn = 1 or rnr = 1
order by trip_id, arrival_time
You can use row_number():
select s.*
from (select st.trip_id, st.arrival_time, st.departure_time,
st.stop_sequence, st.stop_id, s.stop_name,
row_number() over (partition by st.trip_id order by st.stop_sequence) as seqnum_asc,
row_number() over (partition by st.trip_id order by st.stop_sequence desc) as seqnum_desc
from OeBB_Stop_Times st left join
OeBB_Stops s
on st.stop_id = s.stop_id
) s
where 1 in (seqnum_asc, seqnum_desc);
Note that I fixed the table aliases so they are meaningful rather than arbitrary letters.
Actually, if the stop_sequence is guaranteed to start at 1, this is a bit simpler:
select s.*
from (select st.trip_id, st.arrival_time, st.departure_time,
st.stop_sequence, st.stop_id, s.stop_name,
max(stop_sequence) over (partition by st.trip_id) as max_stop_sequence
from OeBB_Stop_Times st left join
OeBB_Stops s
on st.stop_id = s.stop_id
) s
where stop_sequence in (1, max_stop_sequence);

how to use rank/join and where together

I have used multiple inner joins in my code, and I provided rank, but now I want to select a particular rank. So how to use rank in a where statement?
Here is my code, but now please help me to proceed further:
select [YEAR],
[IDManufacturer],
sum([TotalPrice]),
rank() over (order by sum(totalprice) desc) as sales_rank
from [dbo].[DIM_DATE]
join [dbo].[FACT_TRANSACTIONS]
on [dbo].[FACT_TRANSACTIONS].Date = [dbo].[DIM_DATE].DATE
join [dbo].[DIM_MODEL]
on [dbo].[DIM_MODEL].IDModel=[dbo].[FACT_TRANSACTIONS].IDModel
where [YEAR] in (2009,2010)
group by IDManufacturer,[year]
order by sum([TotalPrice]) desc
Now I want to select only rank 3 and 4. How to do that?
You could either do sub-query or CTE, i would suggest try with 2 methods and look at execution plan pick which performs better:
Sub Query
SELECT * FROM
(select [YEAR],
[IDManufacturer],
sum([TotalPrice]) TotalPrice,
rank() over (order by sum(totalprice) desc) as sales_rank
from [dbo].[DIM_DATE]
join [dbo].[FACT_TRANSACTIONS]
on [dbo].[FACT_TRANSACTIONS].Date = [dbo].[DIM_DATE].DATE
join [dbo].[DIM_MODEL]
on [dbo].[DIM_MODEL].IDModel=[dbo].[FACT_TRANSACTIONS].IDModel
where [YEAR] in (2009,2010)
group by IDManufacturer,[year]
) as SQ
Where sales_rank = 3 or sales_rank = 4
go
Common Table Expression
; with CTE as
(select [YEAR],
[IDManufacturer],
sum([TotalPrice]) TotalPrice,
rank() over (order by sum(totalprice) desc) as sales_rank
from [dbo].[DIM_DATE]
join [dbo].[FACT_TRANSACTIONS]
on [dbo].[FACT_TRANSACTIONS].Date = [dbo].[DIM_DATE].DATE
join [dbo].[DIM_MODEL]
on [dbo].[DIM_MODEL].IDModel=[dbo].[FACT_TRANSACTIONS].IDModel
where [YEAR] in (2009,2010)
group by IDManufacturer,[year]
)
SELECT * FROM CTE WHERE sales_rank = 3 or sales_rank = 4
If you want only rank 3 and 4 then try this:
select * from (
select [YEAR],
[IDManufacturer],
sum([TotalPrice]),
rank() over (order by sum(totalprice) desc) as sales_rank
from [dbo].[DIM_DATE]
join [dbo].[FACT_TRANSACTIONS]
on [dbo].[FACT_TRANSACTIONS].Date = [dbo].[DIM_DATE].DATE
join [dbo].[DIM_MODEL]
on [dbo].[DIM_MODEL].IDModel=[dbo].[FACT_TRANSACTIONS].IDModel
where [YEAR] in (2009,2010)
group by IDManufacturer,[year]
order by sum([TotalPrice]) desc
) t where sales_rank in (3,4)
If you only want the 3rd and 4th values -- and assuming no ties -- then use offset/fetch:
offset 2 rows fetch first 2 rows only
The offset 2 is because offset starts counting at 0 rather than 1.

Get highest value from every group

I have table:
Id, Name, Account, Date, ItemsToSend
I want to group rows by Name and Account
From each group I want to get elements with latest Date
And display element's Name, Account and ItemsToSend
I managed something like this:
select
Name,
Account,
max(Date),
max(CountItemsSend)
from History
where
Date = (
select max(Date)
from History as p
where
p.Account = History.Account
and p.Name = History.Name
)
group by
Name,
Account
I am afraid of max(Date), max(CountItemsSend). I dont think it is ok. After where there is only 1 result for each group, so what is the point of max use there?
A CTE can make this neater.
WITH maxDates as
(
SELECT Name, Account, MAX(Date) as LatestDate
FROM History
GROUP BY Name, Account
)
SELECT h.Name, h.Account, h.Date, h.CountItemsSend
FROM History h
INNER JOIN maxDates m
on m.Name = h.Name and m.Account = h.Account and m.LatestDate = h.Date
Another possible approach is to use ROW_NUMBER() to number rows grouped by name and account and ordered by date descending and then select the rows with number equal to 1. These rows are with max Date per group and CountItemsSend from the same row.
SELECT
t.[Name],
t.[Account],
t.[Date],
t.[CountItemsSend]
FROM (
SELECT
[Name],
[Account],
[Date],
[CountItemsSend],
ROW_NUMBER() OVER (PARTITION BY [Name], [Acount] ORDER BY [Date] DESC) AS Rn
FROM History
) t
WHERE t.Rn = 1
You don't need aggregation. Just:
select h.*
from History h
where h.Date = (select max(h2.Date)
from History h2
where h2.Account = h.Account and
h2.Name = h.Name
);

How to get the first row values in sql server query

My requirement is AllowedAmount for any latest postdate with latest PaymentID.I have tried many times just to get the firstrow value .But i get 2 rows instead.I tried using rownumber() but its not applicable after selecting for all patient name it doesn't give correct output .Does any one has another method apart from top 1 and rownumber() partition.
My requirement is get One ChargeID with AllowedAmount for the latest Postdate with latest PaymentID
SELECT
DISTINCT
TM.[PatientName] AS [PATIENT NAME],
[dbo].[SplitString](TM.InsPlanName, '(') AS [ Insurance],
ISNULL(TMmm1.ChargeAmount, 0) AS [Amount Billed],
ISNULL(TMM1.AllowedAmount, 0) AS AllowedAmount,
TMM1.PostDate,
TMM1.PaymentID,
TM.ChargeID AS ChargeID
FROM [MasterReport] AS TM
LEFT OUTER JOIN (SELECT
SUM(ISNULL(ChargeAmount, 0)) AS ChargeAmount,
[ChargeID]
FROM [dbo].[TransactionMasterReport]
WHERE transactiontype = 'Charges'
GROUP BY [ChargeID]) AS TMmm1
ON TM.ChargeID = TMmm1.ChargeID
LEFT OUTER JOIN (SELECT DISTINCT
MAX(PostDate) AS PostDate,
MAX(ISNULL(PaymentID, 0)) AS PaymentID,
[ChargeID],
AllowedAmount
FROM [dbo].[TransactionMasterReport]
WHERE ([TransactionType] = 'Payments'
OR [TransactionType] = 'Adjustments')
AND AllowedAmount >= 1
AND PaymentSource LIKE '%Primary%'
GROUP BY [ChargeID],
PostDate,
AllowedAmount,
PaymentID) AS TMM1
ON TM.[ChargeID] = TMM1.[ChargeID]
WHERE TM.ChargeId = 4255
ORDER BY TM.[ChargeID]
When I use top 1 in left outer join I get 0.00 in allowed Amount which is incorrect .
This should work, after you play with it for syntax errors. I do not have tables nor data that match yours. The changes are in the second LeftJoin to use Row_Number ordered by Descending of your fields. You may need to enclose the whole thing in another Select (...) and move the Where RN1 = 1 below that.
SELECT
DISTINCT
TM.[PatientName] AS [PATIENT NAME],
[dbo].[SplitString](TM.InsPlanName, '(') AS [ Insurance],
ISNULL(TMmm1.ChargeAmount, 0) AS [Amount Billed],
ISNULL(TMM1.AllowedAmount, 0) AS AllowedAmount,
TMM1.PostDate,
TMM1.PaymentID,
TM.ChargeID AS ChargeID
FROM [MasterReport] AS TM
LEFT OUTER JOIN (SELECT
SUM(ISNULL(ChargeAmount, 0)) AS ChargeAmount,
[ChargeID]
FROM [dbo].[TransactionMasterReport]
WHERE transactiontype = 'Charges'
GROUP BY [ChargeID]) AS TMmm1
ON TM.ChargeID = TMmm1.ChargeID
LEFT OUTER JOIN (SELECT
PostDate,
ISNULL(PaymentID, 0) AS PaymentID,
ChargeID,
AllowedAmount,
Row_Number() Over(Partition By ChargeID Order By PostDate Desc, PaymentID Desc) as RN1
FROM [dbo].[TransactionMasterReport]
WHERE ([TransactionType] = 'Payments'
OR [TransactionType] = 'Adjustments')
AND AllowedAmount >= 1
AND PaymentSource LIKE '%Primary%'
) AS TMM1
ON TM.[ChargeID] = TMM1.[ChargeID]
WHERE RN1 = 1
and TM.ChargeId = 4255
ORDER BY TM.[ChargeID]
We don't know the actual scenario but as suggested above it should work but as you said it's again returning the same output so use query as a subquery as below and try
To return only one record from the whole output
SELECT TOP 1 *
FROM ( <your query> )
ORDER BY postdate, paymentid DESC
To return top 1 value of each ChargeID
SELECT TOP (1) WITH TIES *
FROM ( <your query> )
GROUP BY ChargeID
ORDER BY postdate, paymentid DESC
I think, you should change your query like,
SELECT TOP 1 <your fields>
FROM [MasterReport] AS TM
LEFT OUTER JOIN <TMmm1> ON TM.ChargeID = TMmm1.ChargeID
LEFT OUTER JOIN <TMM1> ON TM.[ChargeID] = TMM1.[ChargeID]
WHERE TM.ChargeId = 4255
ORDER BY TMM1.PostDate DESC, TMM1.PaymentID DESC
It will give you only one row(TOP 1) and it will be the latest PostDate & PaymentID

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