How to convert the oracle sql to Snowflake sql - snowflake-cloud-data-platform

Hi I am calling a select query in a select, in Snowflake. I am facing the error as INVALID IDENTIFIER AS ROWNUM, when I comment Rownum, I am facing the error as Unsupported Subquery type cant evaluted.
My requirement is converting the existing oracle query to SNowflake.
SELECT DISTINCT cust.Id AS Customer_Id
,nvl((
SELECT *
FROM (
SELECT to_char(cliterm.Quantity)
FROM ContractLineItemTerm cliterm
WHERE cliterm.ContractLineItem_id = cli.Id
AND (
cliterm.EndDate IS NULL
OR cliterm.EndDate > add_months(sysdate, - 3)
)
AND cliterm.PriceRuleItem_id IS NULL
ORDER BY cli.id DESC
)
WHERE rownum = 1
), cli.Quantity) AS Quantity_Purchased
,nvl((
SELECT *
FROM (
SELECT cliterm.UsedQuantity
FROM ContractLineItemTerm cliterm
WHERE cliterm.ContractLineItem_id = cli.Id
AND (
cliterm.EndDate IS NULL
OR cliterm.EndDate > add_months(sysdate, - 3)
)
AND cliterm.PriceRuleItem_id IS NULL
ORDER BY cli.id DESC
)
WHERE rownum = 1
), cli.UsedQuantity) AS Quantity_Used_To_Date
,nvl((
SELECT *
FROM (
SELECT cliterm.StartDate
FROM ContractLineItemTerm cliterm
WHERE cliterm.ContractLineItem_id = cli.Id
AND (
cliterm.EndDate IS NULL
OR cliterm.EndDate > add_months(sysdate, - 3)
)
AND cliterm.PriceRuleItem_id IS NULL
ORDER BY cli.id DESC
)
WHERE rownum = 1
), cli.StartDate) AS sbscription_Term_Start_Date
,nvl((
SELECT *
FROM (
SELECT cliterm.EndDate
FROM ContractLineItemTerm cliterm
WHERE cliterm.ContractLineItem_id = cli.Id
AND (
cliterm.EndDate IS NULL
OR cliterm.EndDate > add_months(sysdate, - 3)
)
AND cliterm.PriceRuleItem_id IS NULL
ORDER BY id DESC
)
WHERE rownum = 1
), cli.EndDate) AS sbscription_Term_End_Date
,nvl(to_char(cli.EndDate), (
CASE
WHEN (
cli.StartDate IS NOT NULL
AND con.InitialTerm > 0
)
THEN 'Auto Renewal'
ELSE ''
END
)) AS Contr_End_Date
FROM ContractLineItem cli
INNER JOIN Contract con ON cli.Contract_id = con.Id
INNER JOIN Customer cust ON con.Customer_id = cust.Id
INNER JOIN Organization org ON org.Customer_id = cust.Id
INNER JOIN Product prod ON cli.Product_id = prod.Id
INNER JOIN Producttype pt ON prod.ProductBrand_id = pt.Id
LEFT JOIN account acc ON cust.SAN = acc.acc__c
LEFT JOIN account acc1 ON acc.parentid = acc1.id
LEFT JOIN sbSCRIPTION sb ON sb.id = cli.sforceid
LEFT JOIN sbSCRIPTION pasb ON pasb.id = sb.srequired
LEFT JOIN scontract1 cntr ON cntr.contractnumber = con.ContNumber
LEFT JOIN user accowner ON acc.ownerid = accowner.id
LEFT JOIN user accsalesmanager ON accowner.managerid = accsalesmanager.id
LEFT JOIN (
SELECT f.accountid
,g.managerid
,max(g.NAME) CSM
,max(g.id) CSMID
FROM accountteammember f
JOIN user g ON f.userid = g.id
WHERE f.teammemberrole = 'AGM'
GROUP BY f.accountid
,g.managerid
) acccsm ON acccsm.accountid = acc.id
LEFT JOIN product2 prd ON prod.Code = prd.productcode
LEFT JOIN prdfam prod_fam ON prod_fam.product_family_desc = prd.Product_Family__c
)
WHERE Quantity_Purchased <> 0
);
How to convert the same to snowflake supported, as it should pick the quantity column based on rownum=1, if it is null, it should be replaced by some x.

Try and change your query to this (change WHERE rownum = 1 to limit 1 :
,nvl((
SELECT *
FROM (
SELECT to_char(cliterm.Quantity)
FROM ContractLineItemTerm cliterm
WHERE cliterm.ContractLineItem_id = cli.Id
AND (
cliterm.EndDate IS NULL
OR cliterm.EndDate > add_months(sysdate, - 3)
)
AND cliterm.PriceRuleItem_id IS NULL
ORDER BY cli.id DESC
)
limit 1

The example SQL is missing a couple layers of SELECT * FROM ( as you have to unmatched paren at the end. But assuming you are selecting * so your WHERE Quantity_Purchased <> 0 this can be coverted to a QUALIFY and the layers can be skipped.
There are two main things, how to convert the SQL, and how to avoid the corrolated sub-query
firstly the three sub-select in the JOIN have the same pattern, so we will talk about the first one, WHERE rownum = 1 can been done via a limit 1 order via QUALIFY I prefer the latter.
SELECT to_char(cliterm.Quantity)
FROM ContractLineItemTerm cliterm
WHERE cliterm.ContractLineItem_id = cli.Id
AND (
cliterm.EndDate IS NULL
OR cliterm.EndDate > add_months(sysdate, - 3)
)
AND cliterm.PriceRuleItem_id IS NULL
QUALIFY row_numumber() OVER (ORDER BY cli.id DESC) = 1
then as you use this in the corrolated sub-query, which is actually also random, because you are ordering by cli.id but also joining on that same clause, so you in effect are not sorting your data. So firstly you need to have a better clause for selecting from ContractLineItemTerm I am going to make up a column called is_best just so the SQL makes sense, and then you can put something in there that, makes sense.
The next thing to note is your four selects are all the same SQL block, so we can change this to one join and be done with it.
so I have used a CTE just so you can see how the fours blocks where written as one, and reformatted your JOIN ON's to be on new lines, as for more complex SQL it is nicer, and I rewrote your CASE to be an IFF as it is a simple two branch case.
WITH best_per_id (
SELECT cliterm.ContractLineItem_id
,to_char(cliterm.Quantity) as Quantity
,cliterm.UsedQuantity
,cliterm.StartDate
FROM ContractLineItemTerm cliterm
WHERE cliterm.PriceRuleItem_id IS NULL
AND (
cliterm.EndDate IS NULL
OR cliterm.EndDate > add_months(sysdate, - 3)
)
QUALIFY row_numumber() OVER (PARTITION BY cliterm.ContractLineItem_id
ORDER BY cliterm.is_best ) = 1
)
SELECT DISTINCT cust.Id AS Customer_Id
,nvl(bpi.Quantity, cli.Quantity) AS Quantity_Purchased
,nvl(bpi.UsedQuantity, cli.UsedQuantity) AS Quantity_Used_To_Date
,nvl(bpi.StartDate, cli.StartDate) AS sbscription_Term_Start_Date
,nvl(bpi.EndDate, cli.EndDate) AS sbscription_Term_End_Date
,nvl(to_char(cli.EndDate),
IFF(cli.StartDate IS NOT NULL AND con.InitialTerm > 0, 'Auto Renewal', '')
) AS Contr_End_Date
FROM ContractLineItem cli
INNER JOIN Contract con
ON cli.Contract_id = con.Id
INNER JOIN Customer cust
ON con.Customer_id = cust.Id
INNER JOIN Organization org
ON org.Customer_id = cust.Id
INNER JOIN Product prod
ON cli.Product_id = prod.Id
INNER JOIN Producttype pt
ON prod.ProductBrand_id = pt.Id
LEFT JOIN best_per_id as bpi
ON cli.id = bpi.ContractLineItem_id
LEFT JOIN account acc
ON cust.SAN = acc.acc__c
LEFT JOIN account acc1
ON acc.parentid = acc1.id
LEFT JOIN sbSCRIPTION sb
ON sb.id = cli.sforceid
LEFT JOIN sbSCRIPTION pasb
ON pasb.id = sb.srequired
LEFT JOIN scontract1 cntr
ON cntr.contractnumber = con.ContNumber
LEFT JOIN user accowner
ON acc.ownerid = accowner.id
LEFT JOIN user accsalesmanager
ON accowner.managerid = accsalesmanager.id
LEFT JOIN (
SELECT f.accountid
,g.managerid
,max(g.NAME) CSM
,max(g.id) CSMID
FROM accountteammember f
JOIN user g ON f.userid = g.id
WHERE f.teammemberrole = 'AGM'
GROUP BY f.accountid
,g.managerid
) acccsm ON acccsm.accountid = acc.id
LEFT JOIN product2 prd
ON prod.Code = prd.productcode
LEFT JOIN prdfam prod_fam
ON prod_fam.product_family_desc = prd.Product_Family__c
QUALIFY Quantity_Purchased <> 0;
but that can all be written as a subselect like is done with acccsm like so:
WITH best_per_id (
SELECT cliterm.ContractLineItem_id
,to_char(cliterm.Quantity) as Quantity
,cliterm.UsedQuantity
,cliterm.StartDate
FROM ContractLineItemTerm cliterm
WHERE cliterm.PriceRuleItem_id IS NULL
AND (
cliterm.EndDate IS NULL
OR cliterm.EndDate > add_months(sysdate, - 3)
)
QUALIFY row_numumber() OVER (PARTITION BY cliterm.ContractLineItem_id
ORDER BY cliterm.is_best ) = 1
)
SELECT DISTINCT cust.Id AS Customer_Id
,nvl(bpi.Quantity, cli.Quantity) AS Quantity_Purchased
,nvl(bpi.UsedQuantity, cli.UsedQuantity) AS Quantity_Used_To_Date
,nvl(bpi.StartDate, cli.StartDate) AS sbscription_Term_Start_Date
,nvl(bpi.EndDate, cli.EndDate) AS sbscription_Term_End_Date
,nvl(to_char(cli.EndDate),
IFF(cli.StartDate IS NOT NULL AND con.InitialTerm > 0, 'Auto Renewal', '')
) AS Contr_End_Date
FROM ContractLineItem cli
INNER JOIN Contract con
ON cli.Contract_id = con.Id
INNER JOIN Customer cust
ON con.Customer_id = cust.Id
INNER JOIN Organization org
ON org.Customer_id = cust.Id
INNER JOIN Product prod
ON cli.Product_id = prod.Id
INNER JOIN Producttype pt
ON prod.ProductBrand_id = pt.Id
LEFT JOIN (
SELECT cliterm.ContractLineItem_id
,to_char(cliterm.Quantity) as Quantity
,cliterm.UsedQuantity
,cliterm.StartDate
FROM ContractLineItemTerm cliterm
WHERE cliterm.PriceRuleItem_id IS NULL
AND (
cliterm.EndDate IS NULL
OR cliterm.EndDate > add_months(sysdate, - 3)
)
QUALIFY row_numumber() OVER (PARTITION BY cliterm.ContractLineItem_id ORDER BY cliterm.is_best ) = 1
) as bpi
ON cli.id = bpi.ContractLineItem_id
LEFT JOIN account acc
ON cust.SAN = acc.acc__c
LEFT JOIN account acc1
ON acc.parentid = acc1.id
LEFT JOIN sbSCRIPTION sb
ON sb.id = cli.sforceid
LEFT JOIN sbSCRIPTION pasb
ON pasb.id = sb.srequired
LEFT JOIN scontract1 cntr
ON cntr.contractnumber = con.ContNumber
LEFT JOIN user accowner
ON acc.ownerid = accowner.id
LEFT JOIN user accsalesmanager
ON accowner.managerid = accsalesmanager.id
LEFT JOIN (
SELECT f.accountid
,g.managerid
,max(g.NAME) CSM
,max(g.id) CSMID
FROM accountteammember f
JOIN user g ON f.userid = g.id
WHERE f.teammemberrole = 'AGM'
GROUP BY f.accountid
,g.managerid
) acccsm ON acccsm.accountid = acc.id
LEFT JOIN product2 prd
ON prod.Code = prd.productcode
LEFT JOIN prdfam prod_fam
ON prod_fam.product_family_desc = prd.Product_Family__c
QUALIFY Quantity_Purchased <> 0;

Related

Add condition to two sub selects in query

I have this query.
SELECT DISTINCT
u.email,
(
SELECT
count(DISTINCT o.id)
FROM
orders o
INNER JOIN cart_dates cd ON cd.order_id = o.id
WHERE
u.id = o.user_id
) as total,
(
SELECT
count(DISTINCT o.id)
FROM
orders o
INNER JOIN cart_dates cd ON cd.order_id = o.id AND o.pre_order = TRUE
WHERE
u.id = o.user_id
) as count
FROM
users u
How can I get rows where for example, count > (total / 2)?
I am only assumming to answer this question.
SELECT
u.email
FROM
users u
INNER JOIN cart_dates cd ON cd.order_id = o.id
GROUP BY
u.email
HAVING
COUNT(DISTINCT Case when o.pre_order = TRUE then o.id else null end) >
(COUNT(DISTINCT o.id)/2)
I tried to making it more simpler.

Column name doesn't exist in CTE statement

I'm trying to create a CTE statement:
WITH StartCash (StartCash) AS
(
SELECT StartCash
FROM CashierInfo
WHERE CashierID = (SELECT MAX( CashierID)
FROM CashierInfo
WHERE UserID = 1 AND EndDate IS NULL)
)
SELECT
StartCash, a.username AS Username, b.Adress AS Adress,
(SUM(c.quantity * c.discountprice)) AS SumPrice,
c.Printed AS Printed, c.CashierUserID AS CashierUserID,
c.RetailDelivery AS RetailDelivery, c.TrnDocumentID
FROM
Users a
JOIN
InventoryTransTemp c ON c.CashierUserID = a.UserID
JOIN
DeliveryAdress b ON b.DeliveryAdressID = c.DeliveryAdressID
WHERE
c.cashieruserid = 1
GROUP BY
a.Username, b.Adress, c.Printed,
c.CashierUserID, c.RetailDelivery, c.TrnDocumentID
But I am getting an error
Invalid column name 'StartCash'
StartCash does not exist because your CTE is not included in your FROM clause.
Based solely on what I can see in your question, I assume it would be safe to JOIN CashierInfo.UserID to Users.UserID.
So try something like this:
WITH StartCash
AS (
SELECT StartCash
,UserID
FROM CashierInfo
WHERE CashierID = (
SELECT MAX(CashierID)
FROM CashierInfo
WHERE UserID = 1
AND EndDate IS NULL
)
)
SELECT sc.StartCash
,a.username AS Username
,b.Adress AS Adress
,(SUM(c.quantity * c.discountprice)) AS SumPrice
,c.Printed AS Printed
,c.CashierUserID AS CashierUserID
,c.RetailDelivery AS RetailDelivery
,c.TrnDocumentID
FROM StartCash sc
INNER JOIN Users a ON sc.UserID = a.UserID
INNER JOIN InventoryTransTemp c ON c.CashierUserID = a.UserID
INNER JOIN DeliveryAdress b ON b.DeliveryAdressID = c.DeliveryAdressID
WHERE c.cashieruserid = 1
GROUP BY sc.StartCash
,a.Username
,b.Adress
,c.Printed
,c.CashierUserID
,c.RetailDelivery
,c.TrnDocumentID
You do not have the CTE in the from clause. You need to join to the CTE but your CTE has only a summary value. https://learn.microsoft.com/en-us/sql/t-sql/queries/with-common-table-expression-transact-sql?view=sql-server-2017

SQL Query tuning - MS SQL Server -2012

I am new to sql tuning. I have the following SQL which takes around 15 to 20 seconds to produce the results.
SELECT D.DealerName,
Z.Zone,
C.Id ,
L.Id ,
A.Id ,
L.LeadDate,
LT.LeadType ,
EM.FirstName + ' ' + EM.LastName ,
LS.LeadSource ,
--C.*,
E.Id ,
E.StartDateTime,
0 ,
Chiefed = CASE A.AppointmentTypeId
WHEN 3 THEN 'True'
ELSE ''
END,
9 AS WorkflowPhase
FROM Customers C( NOLOCK )
INNER JOIN Dealers D
ON C.DEALERId = D.Id
INNER JOIN Leads L( NOLOCK )
ON L.CustomerId = C.Id
INNER JOIN Appointments A( NOLOCK )
ON A.LeadId = L.Id
AND ( NOT( A.AppointmentTypeId = 5
OR A.AppointmentTypeId = 6 ) )
JOIN CalendarEvents E( NOLOCK )
ON E.TableId = 1
AND E.TableRowId = A.Id
AND E.IsDeleted = 0
AND Dateadd(hh, #TZO, Getdate()) >= E.StartDateTime
LEFT OUTER JOIN AppointmentResults AR( NOLOCK )
ON AR.EventId = E.Id
LEFT OUTER JOIN LeadSources LS( NOLOCK )
ON LS.Id = L.LeadSourceId
LEFT OUTER JOIN LeadTypes LT( NOLOCK )
ON LT.Id = L.LeadTypeId
LEFT OUTER JOIN Users EM( NOLOCK )
ON EM.Id = E.EmployeeId
LEFT OUTER JOIN Zone Z( NOLOCK )
ON Z.Id = C.ZoneId
WHERE EXISTS(SELECT 1
FROM WorkflowStatus WS( NOLOCK )
WHERE TableId = 1
AND TableRowId = A.Id
AND WorkflowPhaseId = 9
AND IsCompleted = 0
AND IsDeleted = 0)
AND ( EXISTS (SELECT 1
FROM dbo.Uft_userpermissionzonesbyworkflow(#EmployeeId, 9)
WHERE ZoneId = C.zoneid) )
AND EXISTS (SELECT 1
FROM Uft_userenableddealers(#EmployeeId)
WHERE DealerId = C.DealerId)
ORDER BY C.LastName,
C.CompanyName,
C.CompanyContact
I already tuned up to my knowledge but still I can see some index scans. I tried to convert those index scans to index seek but it is not possible due to number of records.
Please refer the screenshot of plan diagram and top operations
Kindly provide any suggestions to improvise this query.
DECLARE #p TABLE (DealerId INT PRIMARY KEY WITH (IGNORE_DUP_KEY=ON))
INSERT INTO #p
SELECT DealerId
FROM dbo.Uft_userenableddealers(#EmployeeId)
DECLARE #z TABLE (ZoneId INT PRIMARY KEY WITH (IGNORE_DUP_KEY=ON))
INSERT INTO #z
SELECT ZoneId
FROM dbo.Uft_userpermissionzonesbyworkflow(#EmployeeId, 9)
SELECT ...
FROM ...
WHERE EXISTS(SELECT 1
FROM WorkflowStatus WS( NOLOCK )
WHERE TableId = 1
AND TableRowId = A.Id
AND WorkflowPhaseId = 9
AND IsCompleted = 0
AND IsDeleted = 0)
AND C.zoneid IN (SELECT * FROM #z)
AND C.DealerId IN (SELECT * FROM #p)
ORDER BY C.LastName,
C.CompanyName,
C.CompanyContact
OPTION(RECOMPILE)
as discussed below Devarts answer here the example with a CTE instead of the declared table variables. I'd assume that the declared TVs are faster due to the key, but the CTE is ad-hoc and - maybe - better integrated. Thx for testing:
;WITH p AS
(
SELECT DealerId
FROM dbo.Uft_userenableddealers(#EmployeeId)
)
,z AS
(
SELECT ZoneId
FROM dbo.Uft_userpermissionzonesbyworkflow(#EmployeeId, 9)
)
SELECT ...
FROM ...
WHERE EXISTS(SELECT 1
FROM WorkflowStatus WS( NOLOCK )
WHERE TableId = 1
AND TableRowId = A.Id
AND WorkflowPhaseId = 9
AND IsCompleted = 0
AND IsDeleted = 0)
AND C.zoneid IN (SELECT ZoneId FROM z)
AND C.DealerId IN (SELECT DealerId FROM p)
ORDER BY C.LastName,
C.CompanyName,
C.CompanyContact
OPTION(RECOMPILE)

Get non duplicate Rows From This Query Without using distinct keyword

I need to filter out distinct rows from below query without using distinct keyword.
So in the CM.PfmFolderMstIpMap Table there are duplicate F.Id's or PMMAP.PfmFolderFK Id's so I want to filter out non-duplicate ones
SELECT F.Id,
F.folderno,
F.folderstatusdate,
(SELECT codedesc
FROM cm.codetable
WHERE id = F.FolderStatusCode) 'FolderStatus',
(SELECT codedesc
FROM cm.codetable
WHERE id = F.FolderLocationCode) 'Location',
F.volume,
F.sdexhibits,
F.cost,
F.remarks
FROM cm.pfmfolder F WITH(nolock)
INNER JOIN cm.pfmfoldermstipmap PMMAP WITH(nolock)
ON PMMAP.pfmfolderfk = F.id
INNER JOIN cm.mstip MST WITH(nolock)
ON MST.id = PMMAP.mstipfk
LEFT JOIN tm.mstirsdmstipmap IRMAP WITH(nolock)
ON IRMAP.mstipfk = MST.id
LEFT JOIN tm.mstirsd IRSD WITH(nolock)
ON IRSD.id = IRMAP.mstirsdfk
LEFT JOIN tm.mstir IR WITH(nolock)
ON IR.id = IRSD.mstirfk
LEFT JOIN tm.mstiabasicmark IABM
ON IABM.basicmarknbr = MST.applnnbr
LEFT JOIN tm.mstia IA
ON IA.id = IABM.mstiafk
WHERE ( #FolderNbr IS NULL
OR F.folderno LIKE + #FolderNbr + '%' )
AND ( #ApplnNbr IS NULL
OR MST.applnnbr LIKE + #ApplnNbr + '%' )
AND ( #IrNbr IS NULL
OR IR.irnbr LIKE + #IrNbr + '%' )
AND ( #IaNbr IS NULL
OR IA.ianbr LIKE + #IaNbr + '%' )
AND ( #FolderStatusCode IS NULL
OR F.folderstatuscode = #FolderStatusCode )
AND ( #FolderLocationCode IS NULL
OR F.folderlocationcode = #FolderLocationCode )
AND ( F.folderstatusdate >= #FolderStatusDateFrom
AND F.folderstatusdate < #FolderStatusDateTo )
AND MST.registrycode = #RegistryCode
AND PMMAP.deletedby IS NULL
As Sam said Distinct is the best option. Otherwise use Group by using all columns
You can use Row_Number feature too
Try this
SELECT * FROM
(
SELECT F.Id,
F.folderno,
F.folderstatusdate,
(SELECT codedesc
FROM cm.codetable
WHERE id = F.FolderStatusCode) 'FolderStatus',
(SELECT codedesc
FROM cm.codetable
WHERE id = F.FolderLocationCode) 'Location',
F.volume,
F.sdexhibits,
F.cost,
F.remarks,
Row_number() OVER(partition BY F.Id ORDER BY (SELECT NULL) ASC) RN
FROM cm.pfmfolder F WITH(nolock)
INNER JOIN cm.pfmfoldermstipmap PMMAP WITH(nolock)
ON PMMAP.pfmfolderfk = F.id
INNER JOIN cm.mstip MST WITH(nolock)
ON MST.id = PMMAP.mstipfk
LEFT JOIN tm.mstirsdmstipmap IRMAP WITH(nolock)
ON IRMAP.mstipfk = MST.id
LEFT JOIN tm.mstirsd IRSD WITH(nolock)
ON IRSD.id = IRMAP.mstirsdfk
LEFT JOIN tm.mstir IR WITH(nolock)
ON IR.id = IRSD.mstirfk
LEFT JOIN tm.mstiabasicmark IABM
ON IABM.basicmarknbr = MST.applnnbr
LEFT JOIN tm.mstia IA
ON IA.id = IABM.mstiafk
WHERE ( #FolderNbr IS NULL
OR F.folderno LIKE + #FolderNbr + '%' )
AND ( #ApplnNbr IS NULL
OR MST.applnnbr LIKE + #ApplnNbr + '%' )
AND ( #IrNbr IS NULL
OR IR.irnbr LIKE + #IrNbr + '%' )
AND ( #IaNbr IS NULL
OR IA.ianbr LIKE + #IaNbr + '%' )
AND ( #FolderStatusCode IS NULL
OR F.folderstatuscode = #FolderStatusCode )
AND ( #FolderLocationCode IS NULL
OR F.folderlocationcode = #FolderLocationCode )
AND ( F.folderstatusdate >= #FolderStatusDateFrom
AND F.folderstatusdate < #FolderStatusDateTo )
AND MST.registrycode = #RegistryCode
AND PMMAP.deletedby IS NULL
) AS T
WHERE RN = 1
Distinct is the best option. Otherwise use Group by using all columns

sql server 2008, how to get rid of duplications when inner join 3 tables

here's my query. when I inner join 2 tables, there's no problem.
SELECT S.* ,
U.Avatar ,
U.Displayname ,
ROW_NUMBER() OVER ( ORDER BY S.Id DESC ) rownum
FROM dbo.Smoothie AS S
INNER JOIN dbo.[User] AS U ON S.UserId = U.Id
WHERE S.IsPublic = 1
AND S.Status = 3
AND S.UserId = 2
then, I added another inner join. now, I got alot duplications.
SELECT S.* ,
U.Avatar ,
U.Displayname,
ROW_NUMBER() OVER ( ORDER BY S.Id DESC ) rownum
FROM dbo.Smoothie AS S
INNER JOIN dbo.[User] AS U ON S.UserId = U.Id
INNER JOIN dbo.Favorite AS F ON U.Id = F.UserId
WHERE S.IsPublic = 1
AND S.Status = 3
AND F.UserId = 2
one solutions is to use distinct. however, I have to comment out row_number, i need that row_number to do paging. is there another way to get rid of duplication?
SELECT DISTINCT S.* ,
U.Avatar ,
U.Displayname
-- ROW_NUMBER() OVER ( ORDER BY S.Id DESC ) rownum
FROM dbo.Smoothie AS S
INNER JOIN dbo.[User] AS U ON S.UserId = U.Id
INNER JOIN dbo.Favorite AS F ON U.Id = F.UserId
WHERE S.IsPublic = 1
AND S.Status = 3
AND F.UserId = 2
Why not use the query you have, without the row_number as a subquery, then add the row number back later:
SELECT *,
ROW_NUMBER() OVER ( ORDER BY subQuery.Id DESC ) rownum
FROM (
SELECT DISTINCT S.* ,
U.Avatar ,
U.Displayname
FROM dbo.Smoothie AS S
INNER JOIN dbo.[User] AS U ON S.UserId = U.Id
INNER JOIN dbo.Favorite AS F ON U.Id = F.UserId
WHERE S.IsPublic = 1
AND S.Status = 3
AND F.UserId = 2
) AS subQuery
Dense_Rank would also do the job with the your otherwise unmodified query.

Resources