TSQL group by generate duplicate row - sql-server

I'm trying to extract all prices and taxes by dates range (not necessary the same date) in 2 column and group by ID.
Because I need to group by 2 others columns because T-SQL need that:
Column '...' is invalid in the select list because
it is not contained in either an aggregate function or the GROUP BY clause.
I have a duplicate user/ID sometimes. ( don't know why by the way..)
I have this SQL:
WITH myQuery AS
(
Select
c.name, c.id,
CASE
WHEN g.dateCreated BETWEEN CAST ('2016-06-01 00:00:00.000' AS DATETIME)
AND CAST ('2017-05-31 23:59:59.000' AS DATETIME)
THEN SUM(CAST(g.price AS decimal(20,2) ))
ELSE 0
END AS TOTAL_PRICE,
CASE
WHEN g.dateCreated BETWEEN CAST ('2016-01-01 00:00:00.000' AS DATETIME)
AND CAST ('2016-12-31 23:59:59.000' AS DATETIME)
THEN SUM(CAST(g.tax AS decimal(20,2) ))
ELSE 0
END AS TOTAL_TAX
FROM customers c
inner join goodies g
ON c.id = g.customer_id
GROUP BY c.name, c.id, g.dateCreated
)
SELECT count(*) FROM myQuery
I got 5203 rows. I have only 5031 users.
When I Analyse my data, I have some duplicate data.
Example:
Alex, 12, 0.00, 0.00
Alex, 12, 100.00, 14.55
Nancy, 4, 0.00, 0.00
Arthur, 97, 48.14, 09.17
I tried to group by only by id but it seem that I can't do that.
Why I have a duplicate data and How to prevent that and ensure that I have 1 row by USER even if they don't buy goodies?

Correcting your conditional aggregation and removing dateCreated from the group by:
with myQuery as (
select
c.name
, c.id
, total_price = sum(case
when g.dateCreated >= '20160601' and g.dateCreated < '20170601'
then cast(g.price as decimal(20,2))
else 0
end)
, total_tax = sum(case
when g.dateCreated >= '20160101' and g.dateCreated < '20170101'
then cast(g.tax as decimal(20,2))
else 0
end)
from customers c
left join goodies g
on c.id = g.customer_id
group by
c.name
, c.id
--, g.dateCreated
)
select count(*) from myQuery;
Changing the inner join to a left join will return customers even if they have no corresponding row in goodies.
I also changed your date range code to be more explicit about what is included.
Reference:
Bad habits to kick : mis-handling date / range queries - Aaron Bertrand
What do between and the devil have in common? - Aaron Bertrand

Related

Adding the total number of distinct customers to a cte table in Microsoft SQL Server

I am using Microsoft SQL Server and am trying to achieve the following
Date
Distinct Customers last 30Days
2020-12-01
20000
2020-12-02
23000
What I am trying to get is that between 2020-11-01 and 2020-12-01 I had 20000 distinct customers.
I have created a cte table with the List of Dates as can be seen below:
WITH listdate AS
(
SELECT CAST('2020-11-01' AS datetime) DateValue
UNION ALL
SELECT DateValue + 1
FROM listdate
WHERE DateValue + 1 < getdate()
)
SELECT
cast(DateValue as date) as DateValue
FROM listdate d
Now I am trying to join the customer and usage table with the list of dates table, however, I am not getting the correct end result. The following is what I have tried doing:
WITH listdate AS
(
SELECT CAST('2020-11-01' AS datetime) DateValue
UNION ALL
SELECT DateValue + 1
FROM listdate
WHERE DateValue + 1 < getdate()
)
SELECT
cast(DateValue as date) as DateValue
,count(distinct case when m.CallDate between dateadd(dd,-30,cast(d.datevalue as date)) and cast(d.datevalue as date) then m.Customerid end) as Distinct_CID
FROM listdate d
join Usage m on d.DateValue=m.CallDate
left join Customer c on c.CustomerID=m.Customer
where c.customertype = 'type A'
group by d.DateValue
OPTION (MAXRECURSION 0)
Can someone maybe suggest a different way of how to solve such a query?
Thanks
I would go for a lateral join to bring the count of distinct customers for the last 30 days:
with listdate as (
select cast('20201101' as date) as datevalue
union all
select dateadd(day, 1, datevalue) from listdate where datevalue < cast(getdate() as date)
)
select ld.datevalue, x.cnt
from listdate ld
cross apply (
select count(distinct c.customerid) as cnt
from usage u
inner join customer c on c.customerid = u.customerid
where
c.customertype = 'type A'
and c.calldate >= dateadd(day, -29, datevalue)
and c.calldate < dateadd(day, 1, datevalue)
) x
option (maxrecursion 0)
Note that I simplified the parts related to dates: this uses proper literal dates and date arithmetics in the recursive query; the where clause of the subquery implements what I understand as the last 30 days (today + the preceding 29 days), and properly handles the time portion of calldate, if any.

Using Max with CTE and CASE T-SQL

I am trying to use MAX() to select the most recent placement date within our database, and use Table_CTE so I can then select and filter between the dates desired.
BEGIN
DECLARE #Rangetill DATE, #Rangefrom DATE
SET #rangefrom = DATEADD(day, -50, GETDATE())
SET #Rangetill = DATEADD(day, -90, GETDATE());
WITH Table_CTE (Name, ID, Rangefrom, Rangetill, StatusID, Statusdate) AS
(
SELECT
PE.Personname + ' ' + PE.Surname [Name],
A.ApplicantId,
#rangefrom [Expiry warning from],
#rangetill [Expiry warning till],
A.Statusid,
selected = CASE
WHEN P.EndDate IS NOT NULL AND P.EndDate > A.StatusDate
THEN CONVERT(DATE, P.EndDate, 103)
ELSE CONVERT(DATE, A.StatusDate, 103)
END
FROM
Applicants AS A
LEFT JOIN
Person AS PE ON A.ApplicantId = PE.PersonID
LEFT JOIN
Placements AS P on A.applicantid = P.Applicantid
)
SELECT *
FROM Table_CTE
WHERE table_cte.Statusdate BETWEEN #Rangetill AND #Rangefrom
AND (Table_CTE.StatusID = 58 OR Table_CTE.statusid = 63)
ORDER BY Name DESC
END
The above selects the right information but also selects duplicate applicants with placement end dates (p.enddate) as they could have been placed more than once. The WHERE clause also limits the most recent enddate to within the range provided by the Variables and as there needs to be a log there will be multiple end dates. so my solution or idea would be to uses a max() within the Case or CTE Select. However I am not sure how to use or work with Max() in this case.
In this case I would like to check and return the Max(p.enddate) if it exists and store that in the statusdate of Table_CTE.
Is this possible and is it the best way to provide this information in a stored procedure?
In the CTE would be more efficient but this is easier
SELECT c.[Name], max(c.Statusdate)
FROM Table_CTE c
WHERE c.Statusdate Between #Rangetill and #Rangefrom
AND c.StatusID in (58, 63)
group by c.[Name]
Add the other columns on your own
Declare
#Rangetill date,
#Rangefrom date
SET #rangefrom = DATEADD(day, -50, GETDATE())
SET #Rangetill = DATEADD(day, -90, GETDATE());
With Table_CTE ( ID, Rangefrom, Rangetill, Statusdate)
AS (
Select
A.ApplicantId
, #rangefrom [Expiry warning from]
, #rangetill [Expiry warning till]
, selected = CASE
WHEN max(P.EndDate) IS NOT NULL AND max(P.EndDate) > max(A.StatusDate)
THEN max(CONVERT(DATE, P.EndDate, 103))
ELSE max(CONVERT(DATE, A.StatusDate, 103))
END
FROM Applicants AS A
LEFT JOIN Person AS PE ON A.ApplicantId = PE.PersonID
LEFT JOIN Placements AS P on A.applicantid = P.Applicantid
GROUP BY A.ApplicantId
)
SELECT
PE.PersonName + ' ' + PE.Surname [NAME]
, A.ApplicantId
, Table_CTE.ID
, Table_CTE.Statusdate
, #Rangefrom [Range from]
, #Rangetill [Range till]
FROM Table_CTE
LEFT JOIN Applicants AS A ON A.ApplicantId = Table_CTE.ID
LEFT JOIN Person as PE on PE.PersonID = A.ApplicantId
WHERE table_cte.Statusdate Between #Rangetill and #Rangefrom
AND (A.StatusID = 58 or A.statusid = 63 )
Order by PE.PersonName + ' '+ PE.Surname desc
END
Really messy way around things but I got my solution by removing all but the variables and ID from CTE so I could select Max(DATE) on both A.statusdate and P.EndDate.
By doing this I could group by A.ApplicantID and rejoin specific tables outside of the CTE in order to get Applicant Name and Status ID back into my results set.
Thank you for your help everyone.

How to get a list of months and year between two dates in SQL Server

I have to get the list of months and year in between my dates. Currently it only returns month and year for dates that has data associated with it.
for example my dates is between: '8'+'/1'+'/'+'2015' and DATEADD(mm, 15, '8'+'/1'+'/'+'2016'
It only prints out: May2016, June2016, July2016, Auguest2016, September2016
I want it to print out all of the months and year in between. Here is my sql queries:
select d.id_base as case_id,
c.C_LAST_ACTION AS Docketed,
c.C_CASE_TYPE AS caseType,
ct.C_NAME As caseName,
ct.C_DESCRIPTION AS caseNameDescription,
case when d.c_mod_decision_id is not null then '' else DATENAME(mm, d.c_issue_date) + DATENAME(yyyy, d.c_issue_date) end as display
from t_case_decision d JOIN T_CASE_INPUT c on c.id = d.id_base JOIN T_CASE_TYPE ct on C_CASE_TYPE = ct.id
where cast(d.c_issue_date AS date) BETWEEN '8'+'/1'+'/'+'2015' and DATEADD(mm, 15, '8'+'/1'+'/'+'2016')
First, create a numbers table
CREATE TABLE Numbers(N INT)
insert into Numbers(N)
select top 1000000 row_number() over(order by t1.number) as N
from master..spt_values t1
cross join master..spt_values t2
then use DATEADD to list dates between desired values, like this
declare #iniDate as date
set #iniDate='20150801'
select dateadd(MONTH,N,#iniDate) dates
from Numbers
where N<15 order by N
These returns dates from #iniDate up to 15 months later
EDIT: try this, I don't have sql right now
select datename(mm, dateadd(MONTH,N,#iniDate))+datename(yyyy ,dateadd(MONTH,N,#iniDate)) display
from ( select top 15row_number() over(order by t1.number) as N
from master..spt_values t1
cross join master..spt_values t2) numbers right join (
select d.id_base as case_id,
c.C_LAST_ACTION AS Docketed,
c.C_CASE_TYPE AS caseType,
ct.C_NAME As caseName,
ct.C_DESCRIPTION AS caseNameDescription,
case when d.c_mod_decision_id is not null then '' else DATENAME(mm, d.c_issue_date) + DATENAME(yyyy, d.c_issue_date) end as display
from t_case_decision d JOIN T_CASE_INPUT c on c.id = d.id_base JOIN T_CASE_TYPE ct on C_CASE_TYPE = ct.id
where cast(d.c_issue_date AS date) BETWEEN '8'+'/1'+'/'+'2015' and DATEADD(mm, 15, '8'+'/1'+'/'+'2016')
sql-server
) qq
on datename(mm, dateadd(MONTH,N,#iniDate))+datename(yyyy ,dateadd(MONTH,N,#iniDate)) = qq.display
where N<15 order by N
If I understand what you're trying to accomplish, a recursive CTE might help. Here's a quick example of what you can do. The CTE will expand out into a list of dates, which you can then use as the base for your query.
The contents of the TargetData CTE may need to be adjusted, as I don't have a complete picture of your data structure.
DECLARE #startDate DATE = '1/1/2015';
DECLARE #endDate DATE = '7/31/2016';
-- Recursive CTE to generate a list of months within the date range:
WITH Months AS (
SELECT CONVERT(DATE, DATEADD(D, -(DAY(#startDate)) + 1, #startDate)) [MonthDate]
UNION ALL
SELECT DATEADD(M, 1, MonthDate)
FROM Months
WHERE MonthDate <= DATEADD(M, -1, #endDate)
),
TargetData AS (
-- This is a slightly modified version of the original query:
select
d.id_base as case_id,
c.C_LAST_ACTION AS Docketed,
c.C_CASE_TYPE AS caseType,
ct.C_NAME As caseName,
ct.C_DESCRIPTION AS caseNameDescription,
case when d.c_mod_decision_id is not null then '' else DATENAME(mm, d.c_issue_date) + DATENAME(yyyy, d.c_issue_date) end as display,
-- Return the "MonthDate" so that it can be left joined to the Months table:
DATEADD(D, -(DAY(d.c_issue_date)) + 1, d.c_issue_date) [MonthDate]
from t_case_decision d JOIN T_CASE_INPUT c on c.id = d.id_base JOIN T_CASE_TYPE ct on C_CASE_TYPE = ct.id
where cast(d.c_issue_date AS date) BETWEEN #startDate AND #endDate
)
SELECT
m.MonthDate,
DATENAME(mm, m.MonthDate) + DATENAME(yyyy, m.MonthDate),
td.*
FROM Months m
LEFT JOIN TargetData td ON td.MonthDate = m.MonthDate;
You need to join on primary keys between tables, I haven't seen a between statement with that syntax. So I suggest trying the following:
SELECT d.id_base as case_id, c.C_LAST_ACTION AS 'Docketed',c.C_CASE_TYPE AScaseType,ct.C_NAME As 'caseName', ct.C_DESCRIPTION AS 'caseNameDescription'
,CASE
WHEN d.c_mod_decision_id is not null THEN '' AS 'null_val'
ELSE CONCAT(YEAR(d.c_issue_dateDATENAME), MONTH(d.c_issue_date))
END AS 'display'
FROM t_case_decision d INNER JOIN T_CASE_INPUT c on c.id = d.id_base
INNER JOIN T_CASE_TYPE ct on c.id = ct.id
WHERE CONVERT(DATE,d.c_issue_date) BETWEEN '08/01/2015'
AND '08/01/2016';
I hope this helps or points you in the right direction :)

How to calculate a daily running total from an aliased column

I'm writing a query to return a table of booking data for an event. I've used a SUM aggregate to group the number of daily bookings. I'd now like to create a column with a cumulative running total.
I can't make my query work because (I'm presuming) it doesn't like the aliased column title being included in the aggregate function.
Please can anyone advise me on the best approach to make this work?
SELECT
'Recruitment Event' Event,
CAST(ep.CREATIONDATE AS date) AS 'Date of Booking',
SUM(CASE
WHEN ep.CREATIONDATE IS NOT NULL THEN 1
ELSE 0
END) 'Total Bookings',
(SELECT
SUM('Total Bookings')
FROM EVENTPLACE AS ep
WHERE CAST(ep.CREATIONDATE AS date) <= CAST(ep.CREATIONDATE AS date))
'Running Total'
FROM EVENTPLACE AS ep
LEFT JOIN EVENTMODULE AS em
ON em.EVENTMODULENO = ep.EVENTMODULENO
WHERE em.EVENTMODULENO = '11111111-ABCD-1234-1234-1010101010'
GROUP BY CAST(ep.CREATIONDATE AS date)
ORDER BY CAST(ep.CREATIONDATE AS date) DESC
try this
SELECT
[Event] = 'Recruitment Event' ,
[Date of Booking] = CAST(ep.CREATIONDATE AS DATE),
[Total Bookings] = COUNT(ep.CREATIONDATE),
[Running Total] = SUM(COUNT(ep.CREATIONDATE)) OVER (ORDER BY CAST(ep.CREATIONDATE AS DATE) DESC)
FROM
EVENTPLACE AS ep
WHERE
EXISTS (SELECT
*
FROM
EVENTMODULE em
WHERE
em.EVENTMODULENO = ep.EVENTMODULENO
AND em.EVENTMODULENO = '11111111-ABCD-1234-1234-1010101010')
GROUP BY
CAST(ep.CREATIONDATE AS DATE)
ORDER BY
CAST(ep.CREATIONDATE AS DATE) DESC
COUNT(ep.CREATIONDATE) will ignore null values with the same result as your SUM(CASE)
You dont really have to use EXISTS, but you should probably change your LEFT JOIN to a JOIN since you're using the em.EVENTMODULENO in the WHERE statement
SUM(COUNT(ep.CREATIONDATE)) OVER () will give you running total of the count. You use ORDER BY in the OVER to determine the order of the SUM. Since you're ordering by CAST(ep.CREATIONDATE AS DATE) DESC you can just use that in the OVER()
You are getting error because of these lines..
SUM (case when ep.CREATIONDATE IS NOT NULL then 1 else 0 end) 'Total Bookings',
(SELECT SUM ('Total Bookings') FROM EVENTPLACE
You are trying to select alias which was defined in same phase and you are passing it as string .your query wont work unless you correlate it with main table which you are not doing..
Below query works from SQLServer 2012
;with cte
as
(
SELECT 'Recruitment Event' Event,
cast(ep.CREATIONDATE as date) as 'Date of Booking',
SUM (case when ep.CREATIONDATE IS NOT NULL then 1 else 0 end) 'Total Bookings',
FROM EVENTPLACE as ep
LEFT JOIN EVENTMODULE as em ON em.EVENTMODULENO=ep.EVENTMODULENO
WHERE em.EVENTMODULENO = '11111111-ABCD-1234-1234-1010101010'
GROUP BY cast(ep.CREATIONDATE as date)
)
select *,
sum([Total Bookings])
over (order by [Date of Booking] ROWS UNBOUNDED ECEDING ) as 'Runningtotal'
from
cte
The problem is that there is a SUM() function in your select statement, but not all the other columns are included in your group by clause.
The solution is that add an OVER(ORDER BY ...) clause after your SUM function to calculate the running total.
SELECT
'Recruitment Event' Event,
CAST(ep.CREATIONDATE AS date) AS 'Date of Booking',
SUM(CASE
WHEN ep.CREATIONDATE IS NOT NULL THEN 1
ELSE 0
END)OVER(ORDER BY CAST(ep.CREATIONDATE AS date) DESC) 'Running Total',
FROM EVENTPLACE AS ep
LEFT JOIN EVENTMODULE AS em
ON em.EVENTMODULENO = ep.EVENTMODULENO
WHERE em.EVENTMODULENO = '11111111-ABCD-1234-1234-1010101010'
CAST(ep.CREATIONDATE AS date) DESC

SQL Server - Get customers with nth order in specific date range

I'm tasked with the following:
Select a list of all customers who had their nth order during a certain date range (usually a specific month).
This list needs to contain: customer id, sum of first n orders
My tables are something like this:
[dbo.customers]: customerID
[dbo.orders]: orderID, customerID,
orderDate, orderTotal
Here is what I've tried so far:
-- Let's assume our threshold (n) is 10
-- Let's assume our date range is April 2013
-- Get customers that already had n orders before the beginning of the given date range.
DECLARE #tmpcustomers TABLE (tmpcustomerID varchar(8))
INSERT INTO
#tmpcustomers
SELECT
c.customerID
FROM
orders o
INNER JOIN customers c ON o.customerID = c.customerID
WHERE
o.orderDate < '2013-04-01'
GROUP BY c.customerID
HAVING (COUNT(o.orderID) >= 10)
-- Now get all customers that have n orders sometime within the given date range
-- but did not have n orders before the beginning of the given date range.
SELECT
a.customerID, SUM(orderTotal) AS firstTenOrderTotal
SELECT
o.customerID, o.orderID, o.orderTotal
FROM
orders o
INNER JOIN customers c ON c.customerID = o.customerID
WHERE
a.customerID NOT IN ( SELECT tmpcustomerID FROM #tmpcustomers )
AND
o.orderDate > '2013-04-01'
AND
o.orderDate < '2013-05-01'
GROUP BY c.customerID
HAVING COUNT(o.orderID) >= 10
This seems to work but it's clunky and slow. Another big problem is that the firstTenOrderTotal is actually the SUM of the total amount of orders by the end of the given date range and not necessarily the first 10.
Any suggestions for a better approach would be much appreciated.
In the insert to #tmpcustomers, why are you joining back to the customer table? The order table already has the customerID that you want. Also, why are you looking for orders where the order date is before your date range? Don't you just want customers with more than n orders between a date range? This will make the second query easier.
By only having the customers with n or more orders in the table variable #tmpcustomers, you should just be able to join it and the orders table in the second query to get the sum of all the orders for those customers where you would once again limit order table records to your date range (so you do not get orders outside of that range). This will remove the having statement and the join to the customers table in your final result query.
Give this a try. Depending on your order distribution it may perform better. In this query im assembling the list of orders in the range, and then looking back to count the number of prior orders (also grabbing the orderTotal).
note: I am assuming the orderID increments as orders are placed.
If this isnt the case just use a row_number over the date to project the sequence into the query.
declare #orders table (orderID int primary key identity(1,1), customerID int, orderDate datetime, orderTotal int)
insert into #orders (customerID, orderDate, orderTotal)
select 1, '2013-01-01', 1 union all
select 1, '2013-01-02', 2 union all
select 1, '2013-02-01', 3 union all
select 2, '2013-01-25', 5 union all
select 2, '2013-01-26', 5 union all
select 2, '2013-02-02', 10 union all
select 2, '2013-02-02', 10 union all
select 2, '2013-02-04', 20
declare #N int, #StartDate datetime, #EndDate datetime
select #N = 3,
#StartDate = '2013-02-01',
#EndDate = '2013-02-20'
select o.customerID,
[total] = o.orderTotal + p.total --the nth order + total prior
from #orders o
cross
apply ( select count(*)+1, sum(orderTotal)
from #orders
where customerId = o.customerID and
orderID < o.orderID and
orderDate <= o.orderDate
) p(n, total)
where orderDate between #StartDate and #EndDate and p.n = #N
Here is my suggestion:
Use Northwind
GO
select ords.OrderID , ords.OrderDate , '<-->' as Sep1 , derived1.* from
dbo.Orders ords
join
(
select CustomerID, OrderID, ROW_NUMBER() OVER(PARTITION BY CustomerID ORDER BY OrderId DESC) AS ThisCustomerCardinalOrderNumber from dbo.Orders
) as derived1
on ords.OrderID = derived1.OrderID
where
derived1.ThisCustomerCardinalOrderNumber = 3
and ords.OrderDate between '06/01/1997' and '07/01/1997'
EDIT:::::::::
I took my CTE example, and reworked it for multiple Customers (seen below).
Give it the college try.
Use Northwind
GO
declare #BeginDate datetime
declare #EndDate datetime
select #BeginDate = '01/01/1900'
select #EndDate = '12/31/2010'
;
WITH
MyCTE /* http://technet.microsoft.com/en-us/library/ms175972.aspx */
( ShipName,ShipAddress,ShipCity,ShipRegion,ShipPostalCode,ShipCountry,CustomerID,CustomerName,[Address],
City,Region,PostalCode,Country,Salesperson,OrderID,OrderDate,RequiredDate,ShippedDate,ShipperName,
ProductID,ProductName,UnitPrice,Quantity,Discount,ExtendedPrice,Freight,ROWID) AS
(
SELECT
ShipName ,ShipAddress,ShipCity,ShipRegion,ShipPostalCode,ShipCountry,CustomerID,CustomerName,[Address]
,City ,Region,PostalCode,Country,Salesperson,OrderID,OrderDate,RequiredDate,ShippedDate,ShipperName
,ProductID ,ProductName,UnitPrice,Quantity,Discount,ExtendedPrice,Freight
, ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY OrderDate , ProductName ASC ) as ROWID /* Note that the ORDER BY (here) is directly related to the ORDER BY (near the very end of the query) */
FROM
dbo.Invoices inv /* “Invoices” is a VIEW, FYI */
where
(inv.OrderDate between #BeginDate and #EndDate)
)
SELECT
/*
ShipName,ShipAddress,ShipCity,ShipRegion,ShipPostalCode,ShipCountry,CustomerID,CustomerName,[Address],
City,Region,PostalCode,Country,Salesperson,OrderID,OrderDate,RequiredDate,ShippedDate,ShipperName,
ProductID,ProductName,UnitPrice,Quantity,Discount,ExtendedPrice,Freight,
*/
/*trim the list down a little for the final output */
CustomerID ,OrderID , OrderDate, (ExtendedPrice + Freight) as ComputedTotal
/*The below line is the “trick”. I reference the above CTE, but only get data that is less than or equal to the row that I am on (outerAlias.ROWID)*/
, (Select SUM (ExtendedPrice + Freight) from MyCTE innerAlias where innerAlias.ROWID <= outerAlias.ROWID and innerAlias.CustomerID = outerAlias.CustomerID) as RunningTotal
, ROWID as ROWID_SHOWN_FOR_KICKS , OrderDate as OrderDate
FROM
MyCTE outerAlias
GROUP BY CustomerID ,OrderID, OrderDate, ProductName,(ExtendedPrice + Freight) ,ROWID,OrderDate
/*Two Order By Options*/
ORDER BY outerAlias.CustomerID , outerAlias.OrderDate , ProductName
/* << Whatever the ORDER BY is here, should match the “ROW_NUMBER() OVER ( ORDER BY ________ ASC )” statement inside the CTE */
/*ORDER BY outerAlias.ROWID */ /* << Or, to keep is more “trim”, ORDER BY the ROWID, which will of course be the same as the “ROW_NUMBER() OVER ( ORDER BY” inside the CTE */

Resources