SQL Server - View that contains a TOP 1 select column - sql-server
I have a customer table, and then there's a separate transactional table that cross-references the customer table. With one particular column that I would like to present to the consumer as a combined SQL view. This transactional column is referred to as LastEdited.
The view itself is fine, if I run SELECT statements by querying columns like FirstName, LastName, etc. Where I run into issues is when querying the LastEdited column. This column is using a TOP 1 select criteria. For example, if I query LastEdited BETWEEN '1/1/2019 00:00:01' and '6/30/2019 23:59:59'. The results take a long time, since there are obvious performance penalties.
Any suggestions on how best to handle this? I've tried creating the column for this view by invoking a scalar function, like:
(select dbo.fncUser_LastCustomerEditDate(c.CustomerNo)) as LastEdited
This scalar function basically returns the TOP 1 record. I've also tried creating the column by referencing it against an OUTER APPLY, like:
...OUTER APPLY (SELECT top 1 GMTTimestamp from dbo.tbl121_DataLog dl where dl.PrimaryKey = c.Id and dl.DBActionId In (600001, 600002) order by dl.GMTTimeStamp DESC) dl
so that my SELECT list just looks at:
dl.GMTTimeStamp as LastEdited
Neither option provides me the ability to quickly return results by querying the resultant view based on this column.
Any help or suggestions would be appreciated!
Here are the two view constructions I've tried so far:
CREATE VIEW [dbo].[viwUser_Customers_Custom2]
AS
SELECT c.Id, c.Type, c.CustomerNo, sit.Code AS PrimarySiteCode, sit.Name AS PrimarySiteName, emp.Code AS PrimarySalespersonCode,
emp.Name AS PrimarySalespersonName, c.Title, c.FirstName, c.MiddleName, c.LastName, c.NickName, c.Greeting, c.PreviousName,
dbo.fncCustContactMethodText(c.PreferredContactMethod) AS PreferredContactMethod, cad.Address1, cad.Address2, cad.Address3, cad.City, cad.State,
cad.PostCode, cad.Country, cpp.CountryPrefix AS PhoneCountryPrefix, cpp.AreaCode AS PhoneAreaCode, cpp.Number AS PhoneNumber,
cpp.Extension AS PhoneExtension, dbo.fncCustFormattedPhoneNo(cpp.CountryPrefix, cpp.AreaCode, cpp.Number, cpp.Extension)
AS PhoneNumberFormatted, cpf.CountryPrefix AS FaxCountryPrefix, cpf.AreaCode AS FaxAreaCode, cpf.Number AS FaxNumber,
cpf.Extension AS FaxExtension, dbo.fncCustFormattedPhoneNo(cpf.CountryPrefix, cpf.AreaCode, cpf.Number, cpf.Extension) AS FaxNumberFormatted,
cpm.CountryPrefix AS MobileCountryPrefix, cpm.AreaCode AS MobileAreaCode, cpm.Number AS MobileNumber, cpm.Extension AS MobileExtension,
dbo.fncCustFormattedPhoneNo(cpm.CountryPrefix, cpm.AreaCode, cpm.Number, cpm.Extension) AS MobileNumberFormatted, cpe.EmailAddress, c.Sex,
c.UDFList1, c.UDFList2, c.UDFList3, c.UDFList4, c.UDFList5, c.UDFList6, c.UDFList7, c.UDFList8, c.UDFList9, c.UDFList10, c.UDFList11, c.UDFList12,
c.FingerSize1 AS LeftLittleFingerSize, c.FingerSize2 AS LeftRingFingerSize, c.FingerSize3 AS LeftMiddleFingerSize,
c.FingerSize4 AS LeftIndexFingerSize, c.FingerSize5 AS LeftThumbSize, c.FingerSize6 AS RightThumbSize, c.FingerSize7 AS RightIndexFingerSize,
c.FingerSize8 AS RightMiddleFingerSize, c.FingerSize9 AS RightRingFingerSize, c.FingerSize10 AS RightLittleFingerSize, c.LeftWristSize,
c.RightWristSize, c.NeckSize, c.SocSecNumber, c.POSComments, c.SecureComments, c.Status, c.Active, c.Day, c.Month, c.Year, dbo.fncGetDOB(c.Day,
c.Month, c.Year) AS BirthDate, dbo.fncGetAge(c.Day, c.Month, c.Year, c.Age, c.AgeReferenceDate, GETDATE()) AS Age, CAST('' AS varchar(1000))
AS MailingName, CAST('' AS varchar(1000)) AS GreetingName, CAST(0 AS money) AS CustomerSalesTotalForDateRange, CAST(0 AS money)
AS CustomerSalesTotal, CAST('' AS varchar(50)) AS PartnerCustomerNo, CAST('' AS varchar(20)) AS PartnerBirthDate, CAST(0 AS money)
AS PartnerSalesTotalForDateRange, CAST(0 AS money) AS PartnerSalesTotal, dbo.fnc604S_GetAnniversary(c.Id) as Anniversary,
Coalesce((Select Top 1 cd.DiscountPercent From tbl605_CustDiscount cd Where cd.CustomerId = c.Id),0) as DiscountPercent,
dl.GMTTimeStamp as LastEdited
FROM dbo.tbl600_Customer AS c INNER JOIN
dbo.tbl103_Sites AS sit ON c.SiteId = sit.Id LEFT OUTER JOIN
dbo.tbl601_CustAddress AS cad ON cad.CustomerId = c.Id AND cad.[Default] = 1 LEFT OUTER JOIN
dbo.tbl602_CustPhone AS cpp ON cpp.CustomerId = c.Id AND cpp.Device = 1 AND cpp.DeviceDefault = 1 LEFT OUTER JOIN
dbo.tbl602_CustPhone AS cpf ON cpf.CustomerId = c.Id AND cpf.Device = 3 AND cpf.DeviceDefault = 1 LEFT OUTER JOIN
dbo.tbl602_CustPhone AS cpm ON cpm.CustomerId = c.Id AND cpm.Device = 2 AND cpm.DeviceDefault = 1 LEFT OUTER JOIN
dbo.tbl602_CustPhone AS cpe ON cpe.CustomerId = c.Id AND cpe.Device = 4 AND cpe.DeviceDefault = 1 LEFT OUTER JOIN
dbo.tbl405_Employees AS emp ON dbo.fnc600S_GetPrimarySalespersonId(c.Id) = emp.Id OUTER APPLY
(SELECT top 1 GMTTimestamp from dbo.tbl121_DataLog dl where dl.PrimaryKey = c.Id and dl.DBActionId In (600001, 600002) order by dl.GMTTimeStamp DESC) dl
GO
CREATE VIEW [dbo].[viwUser_Customers_Custom]
AS
SELECT c.Id, c.Type, c.CustomerNo, sit.Code AS PrimarySiteCode, sit.Name AS PrimarySiteName, emp.Code AS PrimarySalespersonCode,
emp.Name AS PrimarySalespersonName, c.Title, c.FirstName, c.MiddleName, c.LastName, c.NickName, c.Greeting, c.PreviousName,
dbo.fncCustContactMethodText(c.PreferredContactMethod) AS PreferredContactMethod, cad.Address1, cad.Address2, cad.Address3, cad.City, cad.State,
cad.PostCode, cad.Country, cpp.CountryPrefix AS PhoneCountryPrefix, cpp.AreaCode AS PhoneAreaCode, cpp.Number AS PhoneNumber,
cpp.Extension AS PhoneExtension, dbo.fncCustFormattedPhoneNo(cpp.CountryPrefix, cpp.AreaCode, cpp.Number, cpp.Extension)
AS PhoneNumberFormatted, cpf.CountryPrefix AS FaxCountryPrefix, cpf.AreaCode AS FaxAreaCode, cpf.Number AS FaxNumber,
cpf.Extension AS FaxExtension, dbo.fncCustFormattedPhoneNo(cpf.CountryPrefix, cpf.AreaCode, cpf.Number, cpf.Extension) AS FaxNumberFormatted,
cpm.CountryPrefix AS MobileCountryPrefix, cpm.AreaCode AS MobileAreaCode, cpm.Number AS MobileNumber, cpm.Extension AS MobileExtension,
dbo.fncCustFormattedPhoneNo(cpm.CountryPrefix, cpm.AreaCode, cpm.Number, cpm.Extension) AS MobileNumberFormatted, cpe.EmailAddress, c.Sex,
c.UDFList1, c.UDFList2, c.UDFList3, c.UDFList4, c.UDFList5, c.UDFList6, c.UDFList7, c.UDFList8, c.UDFList9, c.UDFList10, c.UDFList11, c.UDFList12,
c.FingerSize1 AS LeftLittleFingerSize, c.FingerSize2 AS LeftRingFingerSize, c.FingerSize3 AS LeftMiddleFingerSize,
c.FingerSize4 AS LeftIndexFingerSize, c.FingerSize5 AS LeftThumbSize, c.FingerSize6 AS RightThumbSize, c.FingerSize7 AS RightIndexFingerSize,
c.FingerSize8 AS RightMiddleFingerSize, c.FingerSize9 AS RightRingFingerSize, c.FingerSize10 AS RightLittleFingerSize, c.LeftWristSize,
c.RightWristSize, c.NeckSize, c.SocSecNumber, c.POSComments, c.SecureComments, c.Status, c.Active, c.Day, c.Month, c.Year, dbo.fncGetDOB(c.Day,
c.Month, c.Year) AS BirthDate, dbo.fncGetAge(c.Day, c.Month, c.Year, c.Age, c.AgeReferenceDate, GETDATE()) AS Age, CAST('' AS varchar(1000))
AS MailingName, CAST('' AS varchar(1000)) AS GreetingName, CAST(0 AS money) AS CustomerSalesTotalForDateRange, CAST(0 AS money)
AS CustomerSalesTotal, CAST('' AS varchar(50)) AS PartnerCustomerNo, CAST('' AS varchar(20)) AS PartnerBirthDate, CAST(0 AS money)
AS PartnerSalesTotalForDateRange, CAST(0 AS money) AS PartnerSalesTotal, dbo.fnc604S_GetAnniversary(c.Id) as Anniversary,
Coalesce((Select Top 1 cd.DiscountPercent From tbl605_CustDiscount cd Where cd.CustomerId = c.Id),0) as DiscountPercent, (select dbo.fncUser_LastCustomerEditDate(c.CustomerNo)) as LastEdited
FROM dbo.tbl600_Customer AS c INNER JOIN
dbo.tbl103_Sites AS sit ON c.SiteId = sit.Id LEFT OUTER JOIN
dbo.tbl601_CustAddress AS cad ON cad.CustomerId = c.Id AND cad.[Default] = 1 LEFT OUTER JOIN
dbo.tbl602_CustPhone AS cpp ON cpp.CustomerId = c.Id AND cpp.Device = 1 AND cpp.DeviceDefault = 1 LEFT OUTER JOIN
dbo.tbl602_CustPhone AS cpf ON cpf.CustomerId = c.Id AND cpf.Device = 3 AND cpf.DeviceDefault = 1 LEFT OUTER JOIN
dbo.tbl602_CustPhone AS cpm ON cpm.CustomerId = c.Id AND cpm.Device = 2 AND cpm.DeviceDefault = 1 LEFT OUTER JOIN
dbo.tbl602_CustPhone AS cpe ON cpe.CustomerId = c.Id AND cpe.Device = 4 AND cpe.DeviceDefault = 1 LEFT OUTER JOIN
dbo.tbl405_Employees AS emp ON dbo.fnc600S_GetPrimarySalespersonId(c.Id) = emp.Id
GO
Time lags of 1-2 minutes querying the SQL view.
I found an easier way to accomplish this. Will just add a SQL trigger to insert a timestamped row into a supplementary table. This table will have the proper construction to make for quicker lookups.
Related
Converting Oracle Query into T-SQL query using WITH
I have a query from an old database that we converting into T-SQL, but having issues using CTE: Original Query in Oracle: select company_name, display_name, active_flag, naic_code, group_number, alien_code, fein, status_desc, status_detail_desc, due_to_merger_flag, co_code, to_char(status_date, 'MM/DD/YYYY') Inactive_Date, active_flag from (select nm.COMPANY_NAME, cmp.recordid_number, orgtp.display_name, cmp.active_flag, cmp.naic_code, grpnm.group_number, cmp.alien_code, cmp.fein, st.status_desc, stdt.status_detail_desc, storgjn.due_to_merger_flag, storgjn.co_code, storgjn.status_date, st.active_flag as activestatus, max(storgjn.status_date) over (partition by cmp.recordid_number, orgtp.display_name) max_status_date from aip.co_company cmp join aip.CO_NAME nm on cmp.COMPANY_ID = nm.company_id and nm.active_flag = 1 left outer join aip.co_company_group_jn cmpgrpjn on nm.COMPANY_ID = cmpgrpjn.company_id and cmpgrpjn.active_flag = 1 left outer join aip.co_group_name grpnm on cmpgrpjn.group_id = grpnm.group_id and grpnm.active_flag = 1 join aip.co_org org on cmp.COMPANY_ID = org.company_id join aip.co_org_type orgtp on org.org_type_id = orgtp.org_type_id join aip.co_status_org_jn storgjn on org.org_id = storgjn.org_id join aip.co_status_detail stdt on storgjn.status_detail_id = stdt.status_detail_id join aip.co_status st on stdt.status_id = st.status_id WHERE cmp.recordid_number = '10632' AND stdt.status_detail_desc <> 'Record Begin Date') WHERE status_date = max_status_date And converting into T-SQl im using: WITH YOURCTE(WHATEVA) AS ( SELECT nm.COMPANY_NAME, cmp.recordid_number, orgtp.display_name, cmp.active_flag, cmp.naic_code, grpnm.group_number, cmp.alien_code, cmp.fein, st.status_desc, stdt.status_detail_desc, storgjn.due_to_merger_flag, storgjn.co_code, storgjn.status_date, st.active_flag as activestatus, max(storgjn.status_date) over (partition by cmp.recordid_number, orgtp.display_name) max_status_date from aip.co_company cmp join aip.CO_NAME nm on cmp.COMPANY_ID = nm.company_id and nm.active_flag = 1 left outer join aip.co_company_group_jn cmpgrpjn on nm.COMPANY_ID = cmpgrpjn.company_id and cmpgrpjn.active_flag = 1 left outer join aip.co_group_name grpnm on cmpgrpjn.group_id = grpnm.group_id and grpnm.active_flag = 1 join aip.co_org org on cmp.COMPANY_ID = org.company_id join aip.co_org_type orgtp on org.org_type_id = orgtp.org_type_id join aip.co_status_org_jn storgjn on org.org_id = storgjn.org_id join aip.co_status_detail stdt on storgjn.status_detail_id = stdt.status_detail_id join aip.co_status st on stdt.status_id = st.status_id WHERE cmp.recordid_number = '10632' AND stdt.status_detail_desc <> 'Record Begin Date' ) select company_name, display_name, active_flag, naic_code, group_number, alien_code, fein, status_desc, status_detail_desc, due_to_merger_flag, co_code, CONVERT(VARCHAR(10),status_date,120) AS Inactive_Date, active_flag FROM YOURCTE WHERE status_date = max_status_date But I get the following error : Msg 8158, Level 16, State 1, Line 2 'YOURCTE' has more columns than were specified in the column list. The reason i have more columns in my cte is because I'm using the recordid_number column to bring other data for where conditioning. I will appreciate some help, thank you.
Either replace "WHATEVA" with a complete list of the column aliases you want to use, or remove it and let the original column names stand. Inherit ;WITH YOURCTE AS (... Explicit ;WITH YOURCTE (COMPANY_NAME, recordid_number, ...) AS (...
Filtering date after max date SQL
I have a table with values en date/timstamps. This table is dbo.meterdata.value. The output that i want to see is as followed: The latest date/timestamp (Max) but only the ones where te latest date/timestamp is last week. My Query is: SELECT dbo.meter.DataImportCode ,dbo.meter.NAME ,dbo.company.NAME ,dbo.meter.MeterNumber ,MAX(dbo.meterdata.RoundedTimeStamp) AS 'laatste datum' ,dbo.MeterOperator.Description ,dbo.meter.CumulativeReadings FROM dbo.meter LEFT OUTER JOIN DBO.MeterData ON dbo.meter.MeterID = dbo.meterdata.MeterID JOIN DBO.Site ON dbo.meter.SiteID = dbo.site.SiteID JOIN DBO.Company ON dbo.site.CompanyID = dbo.company.CompanyID JOIN DBO.MeterOperator ON dbo.meter.MeterOperatorID = dbo.MeterOperator.MeterOperatorID --WHERE (select (dbo.meterdata.roundedtimestamp) from dbo.MeterData) < DateAdd(DD,-7,GETDATE() ) AND dbo.meterdata.RoundedTimeStamp IS NOT NULL GROUP BY dbo.meter.DataImportCode ,dbo.company.NAME ,dbo.meter.NAME ,dbo.meter.MeterNumber ,dbo.MeterOperator.Description ,dbo.meter.CumulativeReadings Example of the unfilterd result: Example Thank you for help and support
Try the following: select dbo.meter.DataImportCode, dbo.meter.Name, dbo.company.Name, dbo.meter.MeterNumber,MAX(dbo.meterdata.RoundedTimeStamp) AS 'laatste datum', dbo.MeterOperator.Description, dbo.meter.CumulativeReadings from dbo.meter LEFT OUTER JOIN DBO.MeterData ON dbo.meter.MeterID = dbo.meterdata.MeterID JOIN DBO.Site on dbo.meter.SiteID = dbo.site.SiteID JOIN DBO.Company on dbo.site.CompanyID = dbo.company.CompanyID JOIN DBO.MeterOperator on dbo.meter.MeterOperatorID = dbo.MeterOperator.MeterOperatorID --WHERE (select (dbo.meterdata.roundedtimestamp) from dbo.MeterData) < DateAdd(DD,-7,GETDATE() ) --AND dbo.meterdata.RoundedTimeStamp is not null GROUP BY dbo.meter.DataImportCode, dbo.company.name, dbo.meter.Name, dbo.meter.MeterNumber, dbo.MeterOperator.Description, dbo.meter.CumulativeReadings HAVING [laatste datum] < DateAdd(day,-7,GETDATE()) If I understood you right, what you want to do is filter out the data after it has been grouped. This is done using the HAVING clause of the SELECT statement, as the above query depicts.
T-Sql How to get Max dated records?
I want max dated rows for per GroupCode I wrote this. SELECT FH.BelgeNo AS FaturaNo ,FHD.UrunId ,FH.Tarih ,UG.Grup AS GrupKodu ,FHD.Kodu ,FHD.UrunAdi ,FHD.BirimFiyat FROM FirmaHareketDetayi FHD LEFT JOIN FirmaHareketleri FH ON FH.ID = FHD.HareketId LEFT JOIN Urunler U ON U.UrunId = FHD.UrunId --and U.Kodu = FHD.Kodu LEFT JOIN UrunGruplari UG ON UG.GrupId = U.GrupId WHERE FHD.Kodu = '2S619H307CF' AND FH.FirmaId = 2610 ORDER BY Tarih DESC and results are like this There are 2 PIERBURG rows. is it possible to get only one PIERBURG ? I mean max dated one (Tarih: Date column, GrupKodu: Group Code) Notes: Table UrunGrupları: ProductGroups Table FirmaHareketleri: FirmMovements Table FirmaHareketDetayi: FirmMovementDetails (Connected with FirmMovements by HareketId (Foreign Key)) Sorry about my english :(
You can use window functions for this ;with cte as ( SELECT FH.BelgeNo AS FaturaNo ,FHD.UrunId ,FH.Tarih ,UG.Grup AS GrupKodu ,FHD.Kodu ,FHD.UrunAdi ,FHD.BirimFiyat , row_number() over(partition by UG.Grup order by FH.Tarih desc) as rownum FROM FirmaHareketDetayi FHD LEFT JOIN FirmaHareketleri FH ON FH.ID = FHD.HareketId LEFT JOIN Urunler U ON U.UrunId = FHD.UrunId --and U.Kodu = FHD.Kodu LEFT JOIN UrunGruplari UG ON UG.GrupId = U.GrupId WHERE FHD.Kodu = '2S619H307CF' AND FH.FirmaId = 2610 ) select * from cte where rownum = 1
need max(id)for multiple rows but am receiving multiple max id's
I need to retrieve the latest loadid by location now with multiple joins. for example ibiza's latest loadid is 692 and there are 2 records. The query below retrieves all of the loadid's for that location and not just the max. how can i achieve bringing back the latest records by location with the max(loadid) from the query below: select MAX(t.loadid) AS loadid, a.process_id, p.partitionkey, -- t.partitionkey, p.partdesc, p.partname, c.catname, r.rule_name, r.file_path, a.execution_start_time, a.execution_end_time, a.records_processed -- a.status, -- a.last_updated_by as processed_by, -- a.last_update_date FROM data t INNER JOIN part p ON t.partitionkey = p.partitionkey INNER JOIN process a ON t.loadid = a.process_id INNER JOIN categ c ON t.catkey = c.catkey INNER JOIN balance r ON t.RULE_ID = r.RULE_ID WHERE p.partname = 'ibiza' GROUP BY t.loadid, a.process_id, p.partitionkey, t.partitionkey, p.partdesc, p.partname, c.catname, r.rule_name, r.file_path, a.execution_start_time, a.execution_end_time, a.records_processed;
You can use CTE : ;WITH MaxLoadId AS ( select MAX(t.loadid) AS loadid, p.partitionkey, p.partdesc, p.partname FROM data t INNER JOIN part p ON t.partitionkey = p.partitionkey WHERE p.partname = 'ibiza' GROUP BY p.partitionkey, p.partdesc, p.partname ) select mli.loadid AS loadid, a.process_id, mli.partitionkey, -- t.partitionkey, mli.partdesc, mli.partname, c.catname, r.rule_name, r.file_path, a.execution_start_time, a.execution_end_time, a.records_processed -- a.status, -- a.last_updated_by as processed_by, -- a.last_update_date FROM MaxLoadId mli INNER JOIN data t ON mli.loadid = t.loadid INNER JOIN process a ON mli.loadid = a.process_id INNER JOIN categ c ON t.catkey = c.catkey INNER JOIN balance r ON t.RULE_ID = r.RULE_ID
Getting a results rank in TSQL
I have a Stored Procedure that is getting submission entries from my database along with how much each entry has raised. I am trying to get the "Rank" of the submission based on the amount raised vs all other submissions. The second return should be Rank 1 because it has a higher totalRaised amount than the first record which should be rank 2. Am I close?? My sp: SELECT A.[id], A.[petName], A.[petCaption], B.[petType], C.[FirstName] as ownerFirstName, C.[LastName] as ownerLastName, D.[imageName], ( SELECT CONVERT(varchar(20),sum(transactionAmount), 1) as totalRaised, RANK() OVER (ORDER BY sum(transactionAmount) DESC) AS Rank FROM petContestTransactions WHERE submissionID = A.[id] and paymentType = 'donation' FOR XML PATH ('transactionDetails'), TYPE, ELEMENTS ) FROM petContestSubmissions as A JOIN petContestTypes as B ON A.[petType] = B.[id] JOIN EmpTable as C ON A.[empID] = C.EmpID JOIN petContestImages as D ON A.[image] = D.[submissionID] JOIN petContestTransactions as E ON E.[submissionID] = A.[id] WHERE E.[transactionStatus] = 'completed' and E.[paymentType] = 'submission' FOR XML PATH ('submission'), TYPE, ELEMENTS, ROOT ('root'); XML Returned: <root> <submission> <id>1</id> <petName>Nala</petName> <petCaption>Shes a wonder pup!</petCaption> <petType>Dog</petType> <ownerFirstName>Carl</ownerFirstName> <ownerLastName>H</ownerLastName> <imageName>nalaHUS123.png</imageName> <transactionDetails> <totalRaised>130.00</totalRaised> <Rank>1</Rank> </transactionDetails> </submission> <submission> <id>2</id> <petName>Simba</petName> <petCaption>Shes a wonder pup!</petCaption> <petType>Cat</petType> <ownerFirstName>Carl</ownerFirstName> <ownerLastName>H</ownerLastName> <imageName>simbaHUS123.png</imageName> <transactionDetails> <totalRaised>250.00</totalRaised> <Rank>1</Rank> </transactionDetails> </submission> </root>
SELECT A.[id], A.[petName], A.[petCaption], B.[petType], C.[FirstName] as ownerFirstName, C.[LastName] as ownerLastName, D.[imageName], RANK() OVER (ORDER BY sum(F.totalRaised) DESC) AS Rank FROM petContestSubmissions as A JOIN petContestTypes as B ON A.[petType] = B.[id] JOIN EmpTable as C ON A.[empID] = C.EmpID JOIN petContestImages as D ON A.[image] = D.[submissionID] JOIN petContestTransactions as E ON E.[submissionID] = A.[id] OUTER APPLY ( SELECT sum(transactionAmount) as totalRaised, FROM petContestTransactions pt WHERE pt.submissionID = A.[id] and pt.paymentType = 'donation' ) F WHERE E.[transactionStatus] = 'completed' and E.[paymentType] = 'submission' FOR XML PATH ('submission'), TYPE, ELEMENTS, ROOT ('root'); I use outer apply to get the totalRaised and then you can rank it directly.