SQL Server ORDER BY [aggregation] DESC/ASC - sql

I want to be able to sort [comment] by ascending or descending. I've tried performing the aggregation again in the "order by" clause, but that didn't work. I also tried sorting outside of the sub query which let me use the alias [comment], but that only sorted between rows 0 and 10.
This query is a smaller version of a much larger query.
SELECT *
FROM (SELECT ISNULL((SELECT COUNT("order")
FROM order_comment
WHERE "order" = "order"."id"
GROUP BY "order"), 0) AS [comment],
Row_number() OVER (ORDER BY "order"."id" DESC) AS [rownum]
FROM [order]
WHERE ISNULL((SELECT COUNT("order")
FROM order_comment
WHERE "order" = "order"."id"
GROUP BY "order"), 0) > 0) AS [filter]
WHERE [rownum] BETWEEN 0 AND 10
So easy in MySql!
SELECT Ifnull((SELECT COUNT(`order`)
FROM order_comment
WHERE `order` = `order`.`id`
GROUP BY `order`), 0) AS `comment`
FROM `order`
HAVING `comment` > 0
ORDER BY `comment` DESC
LIMIT 0, 10

Following latest edit suspect you want something like this
;WITH oc AS
(
SELECT [order],
COUNT([order]) AS order_count
FROM order_comment
GROUP BY [order]
), occ AS
(
SELECT o.*,
order_count AS comment,
ROW_NUMBER() OVER (ORDER BY order_count DESC) AS [rownum]
FROM [order] o
INNER JOIN oc ON oc.[order] = o.id
)
SELECT *
FROM occ
WHERE [rownum] BETWEEN 0 AND 10
ORDER BY [rownum]
The INNER JOIN will already exclude any rows with no child rows in order_comment

I assume that you don't know that you can use the OVER clause with aggregate functions.
COUNT(order) OVER(PARTITION BY id) AS [comment]
....
ORDER BY [comment]

in SQL Server you can order by column number from your query as in ORDER BY 1
more info here http://blog.sqlauthority.com/2010/12/27/sql-server-order-by-columnname-vs-order-by-columnnumber/
SELECT *
FROM (SELECT ISNULL((SELECT COUNT("order")
FROM order_comment
WHERE "order" = "order"."id"
GROUP BY "order"), 0) AS [comment],
Row_number() OVER (ORDER BY "order"."id" DESC) AS [rownum]
FROM [order]
WHERE ISNULL((SELECT COUNT("order")
FROM order_comment
WHERE "order" = "order"."id"
GROUP BY "order"), 0) > 0) AS [filter]
WHERE [rownum] BETWEEN 0 AND 10
ORDER BY 1

Related

SQL select row with max value or distinct value and sum all

I have the following data that is returned to me. I need to get a distinct or max sum of all the commission by taxid for a single repnbr. The 'qtrlycommrep' column is the value I'm trying to get to, but not able to. For repnbr c590, I need to get the 854.66 commission amount, which is the max for each taxid.
What am I doing wrong?
Any help would be much appreciated!
Here's what I've tried so far. Using the Row_number
select distinct
sub.Repnbr
, (sub.QtrLYComm) as qtrlycommrep
from (
select distinct repnbr, QtrLYComm
, rn = row_number() over(partition by repnbr order by QtrLYComm desc)
from #qtrly
) sub
where sub.rn = 1
Cross Apply
select distinct
#qtrly.repnbr
, x.QtrLYComm as qtrlycommrep
from #qtrly
cross apply (
select top 1
*
from #qtrly as i
where i.repnbr = Repnbr
order by i.qtrlycomm desc
) as x;
inner join
select
#qtrly.repnbr, #qtrly.qtrlycomm as qtrlycommrep
from #qtrly
inner join (
select maxvalue = max(qtrlycomm), repnbr
from #qtrly
group by repnbr
) as m
on #qtrly.repnbr = m.repnbr
and #qtrly.qtrlycomm = m.maxvalue;
order by row_number
select top 1 with ties
#qtrly.repnbr, #qtrly.qtrlycomm as qtrlycommrep
from #qtrly
order by
row_number() over(partition by repnbr
order by qtrlycomm desc)
You want one value per tax id. You need to include that. For instance:
select q.Repnbr, sum(q.QtrLYComm) as qtrlycommrep
from (select q.*,
row_number() over(partition by repnbr, taxid order by QtrLYComm desc) as seqnum
from #qtrly q
) q
where seqnum = 1
group by q.Repnbr;
However, I would be inclined to use two levels of aggregation:
select q.Repnbr, sum(q.QtrLYComm) as qtrlycommrep
from (select distinct repnbr, taxid, QtrLYComm
from #qtrly q
) q
group by q.Repnbr;

SQL MAX in two columns by statistic

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.

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.

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

Incorrect Syntax near 'order' when using the Min aggreate function in SQL Server 2008

I'm need to run the following query in SQL Server 2008R2 but it's throwing me the error Incorrect Syntax near 'Order' on Min/Max aggregate part of the query.
Note that the PONumber field is a string but we use the min/max to identify the first and last po and this works as expected in 2012.
Anyway this can be resolved?
WITH CTE AS
(
SELECT AuditId, DocMasterId, PoNumber,
RN_ASC = ROW_NUMBER() OVER (PARTITION BY DocMasterID
ORDER BY PoNumber ASC),
RN_DESC = ROW_NUMBER() OVER (PARTITION BY DocMasterID
ORDER BY PoNumber DESC),
CNT = COUNT(*) OVER (PARTITION BY DocMasterID),
F = MIN(PONumber) OVER (PARTITION BY DocMasterId
ORDER BY PoNumber ASC),
L = MAX(PONumber) OVER (PARTITION BY DocMasterId
ORDER BY PoNumber ASC)
FROM dbo.MyTable
WHERE (PONumber IS NOT NULL) AND (PONumber <> '') AND
(DocumentType = 'Purchase Order') and docmasterid > 0
)
Your logic is strange. You are taking the cumulative min and max of a column, which is the column used for the ordering. So:
The min is the overall min (for each DocMasterId). A cumulative min is not needed.
The max is the current value (for each DocMasterId), which also happens to be the current value period. A cumulative max is not needed.
So, you can rewrite the logic as:
WITH CTE AS
(
SELECT AuditId, DocMasterId, PoNumber,
RN_ASC = ROW_NUMBER() OVER (PARTITION BY DocMasterID
ORDER BY PoNumber ASC),
RN_DESC = ROW_NUMBER() OVER (PARTITION BY DocMasterID
ORDER BY PoNumber DESC),
CNT = COUNT(*) OVER (PARTITION BY DocMasterID),
F = MIN(PONumber) OVER (PARTITION BY DocMasterId)
L = PoNumber
FROM dbo.MyTable
WHERE (PONumber IS NOT NULL) AND (PONumber <> '') AND
(DocumentType = 'Purchase Order') and docmasterid > 0
)
You might actually want:
F = MIN(PONumber) OVER (PARTITION BY DocMasterId)
L = PoNumber OVER (PARTITION BY DocMasterId)
But the first query is equivalent to the query in your question (well, if the PoNumber could be NULL, I'd have to think harder about whether they are exactly equivalent in that case).
The following statement using subqueries should be equivalent:
WITH myCTE(AuditId, DocMasterId, PoNumber) AS
(
SELECT AuditId, DocMasterId, PoNumber
FROM dbo.MyTable
WHERE (PONumber IS NOT NULL) AND (PONumber <> '') AND
(DocumentType = 'Purchase Order') and docmasterid > 0
),
CTE AS
(
SELECT AuditId, DocMasterId, PoNumber,
ROW_NUMBER() OVER (PARTITION BY DocMasterID
ORDER BY PoNumber ASC) AS RN_ASC,
ROW_NUMBER() OVER (PARTITION BY DocMasterID
ORDER BY PoNumber DESC) AS RN_DESC,
( SELECT COUNT(*) FROM myCTE t2 WHERE t2.DocMasterID = t.DocMasterID) AS CNT,
( SELECT MIN(PONumber) FROM myCTE t2 WHERE t2.DocMasterID = t.DocMasterID) AS F,
( SELECT MAX(PONumber) FROM myCTE t2 WHERE t2.DocMasterID = t.DocMasterID) AS L
FROM myCTE t
)
Here's what we ended up using as a work-around. Unfortunately, anyone trying to help wouldn't have been able to provide the final answer as we ended up using another field in our Query i.e. AuditId. Note this field was not required in SQL Server 2012.
Using the AuditId field allowed us to use the Min/Max aggregate function and using the Partion By as part of our query without using the Order By.
WITH CTE AS
(
SELECT AuditId, DocMasterId, PoNumber,
RN_ASC = ROW_NUMBER() OVER
(PARTITION BY DocMasterID ORDER BY AuditId ASC),
RN_DESC = ROW_NUMBER() OVER
(PARTITION BY DocMasterID ORDER BY AuditId DESC),
CNT = COUNT(*) OVER (PARTITION BY DocMasterID),
MIN(AuditId) OVER (PARTITION BY DocMasterId) AS F,
MAX(AuditId) OVER (PARTITION BY DocMasterId) AS L
FROM MyTable
WHERE (PONumber IS NOT NULL) AND (PONumber <> '') AND
(DocumentType = 'Purchase Order') and docmasterid > 0
)
We then applied a couple of inner join to return the PONumber associated with the AuditId.
The returned results from our audit table were then used to fix the erroneous entries in our live table, so it was it was critical for us the ensure the FirstPO and LastPO were indeed in the correct order in our audit table.
SELECT DISTINCT CTE.DocMasterId, A.PONumber AS FirstPO, B.PONumber AS LastPO
FROM CTE
INNER JOIN MyTable A
ON CTE.F = A.AuditId
INNER JOIN MyTable B
ON CTE.L = B.AuditId
WHERE CNT >= 2 and a.PONumber <> B.PONumber
AND (RN_ASC = 1 OR RN_DESC = 1) AND (F <> L)
ORDER BY CTE.DocMasterId;
Thanks again to all for trying to help. Really appreciated.