Getting unique records for each group using sql - sql

I have an sql Log table with two columns like this:
RegistrantID compnayID Creation date
1 1 .....
1 1
2 1
3 1
1 2
2 2
2 2
3 2 .....
I have a stored procedure which brings first record based creation date. It brings one record if two companies has same registrant id so for registrantid 1, It will being first row and not the 5th row, and for registrantId 2, it will bring row 3 but not 6th. I want to get row 1 and 5 for registrantid 1 and 3rd and 6th for registrantid 2, row 4 and 8 for registrant id 3. Here is my stored procedure.
ALTER PROCEDURE [dbo].[hr_ActionLog_GetList]
#Action INT = NULL,
#DateFrom DATETIME = NULL,
#DateTo DATETIME = NULL,
#CompanyID INT = NULL,
#RegistrantID INT = NULL,
#VacancyID INT = NULL,
#Language INT = 1
AS
BEGIN
WITH CTE AS
(
SELECT AL.*,
RV.Forename,
RV.Surname,
RV.Username AS RegistrantUsername,
E.Forename AS EmployeeForename,
E.Surname AS EmployeeSurname,
U.Username,
CASE
WHEN #Language = 2 THEN C.NameLang2
ELSE C.NameLang1
END AS CompanyName,
CASE
WHEN #Language = 2 THEN V.JobTitleLang2
ELSE V.JobTitleLang1
END AS JobTitle
, ROW_NUMBER() OVER(PARTITION BY AL.RegistrantID
ORDER BY ActionDate ASC) AS RN
FROM dbo.hr_ActionLog AL LEFT OUTER JOIN dbo.RegistrantsListView RV ON AL.RegistrantID = RV.RegistrantID
LEFT OUTER JOIN dbo.hr_Employees E ON AL.EmployeeID = E.EmployeeID
LEFT OUTER JOIN dbo.hr_Users U ON AL.UserID = U.UserID
LEFT OUTER JOIN dbo.hr_Companies C ON AL.CompanyID = C.CompanyID
LEFT OUTER JOIN dbo.hr_Vacancies V ON AL.VacancyID = V.VacancyID
LEFT OUTER JOIN dbo.hr_Companies VC ON V.CompanyID = VC.CompanyID
WHERE (#Action IS NULL OR AL.Action = #Action)
AND (#DateFrom IS NULL OR dbo.DateOnly(AL.ActionDate) >= dbo.DateOnly(#DateFrom))
AND (#DateTo IS NULL OR dbo.DateOnly(AL.ActionDate) <= dbo.DateOnly(#DateTo))
AND (#CompanyID IS NULL OR AL.CompanyID = #CompanyID)
AND (#RegistrantID IS NULL OR AL.RegistrantID = #RegistrantID)
AND (#VacancyID IS NULL OR AL.VacancyID = #VacancyID)
--ORDER BY AL.ActionDate DESC
)
SELECT *
FROM CTE
WHERE RN = 1;
END
Please suggest how to change this stored procedure ?

You need to partition by both RegistrantId and CompanyID
ROW_NUMBER() OVER(PARTITION BY AL.RegistrantID, AL.CompanyID
ORDER BY ActionDate ASC)

Removing where clause RN=1 and adding a distinct should be enough.

Related

Select distinct on foreign key, inner join another table

Basically what I want to do is, select the 3 last actions made from the user. But no duplicates on RelationId, and also innerjoin permissions just to make sure the user has permission still to make the same action.
The only thing I want from permission is RelationId.
By no duplicated I mean if there is two rows of Action with the same RelationId the one closes to the top ( Ordered by TimeStamp ) should be picked.
What I've came up with so far:
SELECT DISTINCT a.*, p.RelationId
FROM [Action] [a]
INNER JOIN [Permission] p
ON ([p].[RelationId] = [a].[RelationId]
AND [p].[RelationType] = [a].[RelationType]
AND [p].[UserId] = [a].[UserId]
AND [p].[Deleted] = 0)
WHERE [a].[ActionType] = 'Clicked'
AND [a].[RelationType] = 'Direct'
AND [a].[UserId] = 5
AND [a].[Deleted] = 0
ORDER BY [a].[TimeStamp] DESC
OFFSET 0 ROWS
FETCH NEXT 3 ROWS ONLY
It need to use OFFSET X ROWS and FETCH NEXT 3 ROWS ONLY for paging
This doesn't work for some reason, because I get duplicates on RelationId.
No errors.
example data:
action (
id INTEGER PRIMARY KEY,
ActionType VARCHAR(50) not null,
RelationId INTEGER ForeignKey,
Deleted Bit not null,
TimeStamp DATE not null,
UserId INTEGER ForeignKey
);
Desired result: 3 last actions made by one user that has permissions for it distinct by RelationId.
From your definition of last 3 per user (if last 3 then it can't be a single row per relationId):
with data as (
SELECT *,
row_number() over (partition by relationId order by [timeStamp] desc) as rNo
from action
where [ActionType] = 'Clicked' AND
[RelationType] = 'Direct' AND
[UserId] = 5 AND
[Deleted] = 0
)
select a.id,a.ActionType,a.RelationId,a.Deleted,a.TimeStamp,a.UserId,
p.RelationId as pRelId
FROM [data] [a]
INNER JOIN [Permission] p ON ([p].[RelationId] = [a].[RelationId] AND [p].[RelationType] = [a].[RelationType] AND [p].[UserId] = [a].[UserId])
WHERE p.[Deleted] = 0 and a.rNo <= 3
ORDER BY [a].[TimeStamp] DESC;
If I get it, you need for each Permission only the latest action, and from all these keep most recent three rows. Here:
select top 3 p.RelationId,top_action.*
from
[Permission] p
cross apply
(
select top 1 *
from [Action] [a]
where
[p].[RelationId] = [a].[RelationId] AND [p].[RelationType] = [a].[RelationType] AND [p].[UserId] = [a].[UserId]
and [a].[ActionType] = 'Clicked' AND [a].[RelationType] = 'Direct' AND [a].[UserId] = 5 AND [a].[Deleted] = 0
order by [a].[TimeStamp] DESC
)top_action
where [p].[Deleted] = 0
order by top_action.[TimeStamp] DESC
Distinct will always distinct all parameters. Selecting * will always differ.
You need to choose just one parameter to determine.
You can use group by, or simply make it in two steps using same select. Like this:
select * from Action where id in (
SELECT DISTINCT a.id
FROM [Action] [a]
INNER JOIN [Permission] p
ON ([p].[RelationId] = [a].[RelationId]
AND [p].[RelationType] = [a].[RelationType]
AND [p].[UserId] = [a].[UserId]
AND [p].[Deleted] = 0)
WHERE [a].[ActionType] = 'Clicked'
AND [a].[RelationType] = 'Direct'
AND [a].[UserId] = 5
AND [a].[Deleted] = 0
ORDER BY [a].[TimeStamp] DESC
OFFSET 0 ROWS
FETCH NEXT 3 ROWS ONLY
)
Solved it by doing this. Don't know if its the best solution though.
SELECT [a].*, [p].[Id]
FROM (SELECT *, ROW_NUMBER() OVER(PARTITION BY [RelationId] ORDER BY [TimeStamp] DESC) AS row from [Action]) a
INNER JOIN [Permission] p ON ([ep].[RelationId] = [a].[RelationId] AND [p].[RelationType] = [a].[RelationType] AND [p].[UserId] = [a].[UserId] AND [p].[Deleted] = 0)
WHERE row = 1 AND [a].[ActionType] = 'Clicked' AND [a].[RelationType] = 'Direct' AND [a].[UserId] = 5 AND [a].[Deleted] = 0
ORDER BY [a].[TimeStamp] DESC
OFFSET 0 ROWS
FETCH NEXT 3 ROWS ONLY

There is already an object named '#FutureDatedExclude' in the database

SELECT FutureDatedEmployeeRecordsKey INTO #FutureDatedExclude
FROM dbo.vwRptDimEmployee_FutureDated FD1
WHERE EXISTS (SELECT 1 FROM dbo.vwRptDimEmployeeAll EE1 WITH (NOLOCK)
WHERE FD1.EmployeeID = EE1.EmployeeID AND FD1.EmployeeRecord = EE1.EmployeeRecord
AND FD1.JobEffectiveDate = EE1.JobEffectiveDT AND FD1.JobEffectiveDateSequence = EE1.JobEffectiveDateSequence
AND FD1.ActionCode = EE1.ActionCode AND FD1.ActionReasonCode = EE1.ActionReasonCode)
declare #JobStartDate date = '07/01/2014', #JobEndDate date = '06/30/2015'
SELECT DISTINCT
E.LastName,
E.SecondLastName,
E.FirstName,
E.MiddleName,
E.PreferredName,
E.PreferredFirstName,
E.NameAC,
E.LastNameAC,
E.FirstNameAC,
E.MiddleNameAC,
E.GUI,
E.EmployeeID,
E.LPN,
E.GPN,
E.EmployeeRecord,
E.JobEffectiveDT JobEffectiveDate,
E.JobEffectiveDateSequence,
E.ActionCode,
E.Action,
E.ActionDate,
E.ActionReasonCode,
AR.Description ActionReason,
E.EmployeeStatusCode,
E.EmployeeStatusDesc,
CASE WHEN YEAR(E.LeaveEffectiveDT) > 2100 THEN NULL ELSE E.LeaveEffectiveDT END LeaveEffectiveDate,
CASE WHEN YEAR(E.ExpectedReturnDate) > 2100 THEN NULL ELSE E.ExpectedReturnDate END ExpectedReturnDate,
E.FullPartTime,
E.ShiftCode FWACode,
E.Shift FWAName,
E.TeleWork,
E.StandardHoursFrequency,
E.StandardHours,
E.FTE,
E.PaidFTE,
E.OvertimeEligibility,
E.EmployeeClassCode,
E.EmployeeClass,
E.RegularVersusTemporary RegularTemporary,
E.EmployeeType,
E.PersonnelStatusDesc,
E.PersonOrganizationRelationshipCode,
P.PersonOfInterest,
P.PersonOfInterestDesc,
E.PaygroupCode,
E.EmployeeCategoryCode,
E.EmployeeSubcategoryCode,
P.EmploymentCategory,
E.NonEmployeeNonWorkTypeCD NonEmployeeNonWorkTypeCode,
P.NonEmployeeNonWorkTypeDesc,
A.GlobalAssignmentProgramCD GlobalAssignmentProgramCode,
A.GlobalAssignmentProgramDesc,
CASE WHEN YEAR(E.GlobalAssignmentStartDT) > 2100 THEN NULL ELSE E.GlobalAssignmentStartDT END GlobalAssignmentStartDate,
CASE WHEN YEAR(E.GlobalAssignmentEndDT) > 2100 THEN NULL ELSE E.GlobalAssignmentEndDT END GlobalAssignmentEndDate,
E.InPatExPatStatus,
E.HomeCountry,
E.HomeHostCountry HostCountry,
CASE WHEN YEAR(E.EYStartDate) > 2100 THEN NULL ELSE E.EYStartDate END EYStartDate,
CASE WHEN YEAR(E.LastRehireDate) > 2100 THEN NULL ELSE E.LastRehireDate END LastRehireDate,
CASE WHEN YEAR(E.SeniorityDate) > 2100 THEN NULL ELSE E.SeniorityDate END SeniorityDate,
CASE WHEN YEAR(E.EmployeeEffectiveDate) > 2100 THEN NULL ELSE E.EmployeeEffectiveDate END CurrentEmploymentDate,
CASE WHEN YEAR(E.PartnerAdmissionDate) > 2100 THEN NULL ELSE E.PartnerAdmissionDate END PartnerAdmissionDate,
R.RankCDName RankCodeName,
E.Rank,
R.RankDesc,
E.BusinessTitle,--NEW
R.RankGroup1,--NEW
E.GFISRank,
E.ExperienceLevel,
E.GlobalGrade,
E.JobCode,--NEW
E.JobCDDesc JobCodeDesc,--NEW
E.DepartmentCode,
E.DepartmentName,
E.CompanyCode,
C.Description Company,
C.DescrAc CompanyAC,
E.ManagerialCountryCD ManagerialCountry,
O.CodeBlock,
O.BUCD BU,
O.OUCD OU,
O.MUCD MU,
O.SMUCD SMU,
O.BUName,
O.OUName,
O.MUName,
O.SMUName,
O.UserDefSLHierarchy1 ServiceLine,
O.UserDefSLHierarchy2 SubSL1,
O.UserDefSLHierarchy3 SubSL2,
O.AlternateServiceLine,
O.UserDefAreaHierarchy1 BULevel1,
O.UserDefAreaHierarchy2 BULevel2,
O.UserDefAreaHierarchy3 BULevel3,
L.Location LocationCode,
L.City LocationCity,
L.State LocationStateProv,
L.Country LocationCountry,
L.UserDefinedHRGeo1 GeoLevel1,
L.UserDefinedHRGeo2 GeoLevel2,
L.UserDefinedHRGeo3 GeoLevel3,
L.UserDefinedHRGeo4 GeoLevel4,
L.UserDefinedHRGeo5 GeoLevel5,
E.CounselorGUI,--NEW
E.CounselorName,--NEW
E.BillRate,
E.Source,
--**** confidential fields ****
E.GenderCode,
E.TermCD TermCode,
E.TerminationReasonCode,
E.CompensationCurrency,
E.CompensationRate,
E.CompensationFrequency,
E.MonthlyCompensationRate,
E.AnnualCompensationRate,
CASE WHEN YEAR(P.SalaryEffectiveDT) > 2100 THEN NULL ELSE P.SalaryEffectiveDT END SalaryEffectiveDate,
E.SalaryAdminPlanCode,
E.SalaryAdminPlan,
E.SalaryGrade,
CASE WHEN YEAR(E.SalaryGradeEntryDate) > 2100 THEN NULL ELSE E.SalaryGradeEntryDate END SalaryGradeEntryDate,
NULL JobKEY,
NULL RowOrder
FROM dbo.vwRptFactEmployee F WITH (NOLOCK)
INNER JOIN dbo.vwRptDimEmployee E WITH (NOLOCK) ON (F.DimEmployeeKey = E.DimEmployeeKey)
INNER JOIN dbo.vwRptDimRank R WITH (NOLOCK) ON (F.DimRankKey = R.DimRankKey)
INNER JOIN dbo.vwRptDimOrganization O WITH (NOLOCK) ON (F.DimOrganizationKey = O.DimOrganizationKey)
INNER JOIN dbo.vwRptDimLocation L WITH (NOLOCK) ON (F.DimLocationKey = L.DimLocationKey)
INNER JOIN dbo.vwRptDimAssignment A WITH (NOLOCK) ON (F.DimAssignmentKey = A.DimAssignmentKey)
--INNER JOIN dbo.vwRptDimDate D WITH (NOLOCK) ON (F.TransEffectiveDateKey = D.DimDateKey)
INNER JOIN dbo.vwRptDimEmployeeV2 P WITH (NOLOCK) ON (F.DimEmployeeKey = P.DimEmployeeKey)
LEFT OUTER JOIN (SELECT ActionCode, ActionReasonCode, Description, row_number() over (partition by ActionCode, ActionReasonCode order by EffectiveDate DESC) as RowOrder
FROM PISupport.vwRptSetfActionReason WITH (NOLOCK)) AR
ON (AR.ActionCode = E.ActionCode AND AR.ActionReasonCode = E.ActionReasonCode AND AR.RowOrder = 1)
LEFT OUTER JOIN (SELECT DISTINCT C1.*, ROW_NUMBER() OVER (PARTITION BY CompanyCode ORDER BY EffectiveDate DESC) as RowOrder
FROM PISupport.vwRptSetfCompany C1 WITH (NOLOCK)) C
ON (C.CompanyCode = E.CompanyCode AND C.RowOrder = 1)
WHERE (E.JobEffectiveDT BETWEEN #JobStartDate AND #JobEndDate)
-- AND (E.ActionCode in ('ADD','DTA','HIR','POI','REH','PER','TER'))
--AND (O.BUCD+O.OUCD+O.MUCD+O.SMUCD LIKE '%'+#CodeBlock+'%' OR #CodeBlock IS NULL)
--AND (E.GPN = #GPN OR #GPN IS NULL)
--AND (E.GUI = #GUI OR #GUI IS NULL)
--AND (L.UserDefinedHRGeo1 in (#GeoArea) )
AND (L.UserDefinedHRGeo2 in ('UK and Ireland'))
--AND (L.UserDefinedHRGeo3 in (#Country) )
--AND (O.UserDefAreaHierarchy1 in (#Area) )
--AND (O.UserDefAreaHierarchy2 in (#Region) )
--AND (O.UserDefSLHierarchy1 in (#ServiceLine) )
--AND (O.UserDefSLHierarchy2 in (#SubServiceLine) )
--AND (R.RankCD in (#RankCode) )
UNION
SELECT DISTINCT * FROM (
SELECT DISTINCT
ISNULL(E.LastName,N.LastName) LastName,
ISNULL(E.SecondLastName,N.SecondLastName) SecondLastName,
ISNULL(E.FirstName,N.FirstName) FirstName,
ISNULL(E.MiddleName,N.MiddleName) MiddleName,
E.PreferredName,
ISNULL(E.PreferredFirstName,N.PreferredFirstName) PreferredFirstName,
ISNULL(E.NameAC,N.NameAlternateCharacter) NameAC,
E.LastNameAC,
E.FirstNameAC,
E.MiddleNameAC,
E.GUI,
FD.EmployeeID,
FD.LPN,
FD.GPN,
FD.EmployeeRecord,
FD.JobEffectiveDate,
FD.JobEffectiveDateSequence,
FD.ActionCode,
FD.Action,
FD.ActionDate,
FD.ActionReasonCode,
FD.ActionReason,
FD.EmployeeStatusCode,
FD.EmployeeStatus,
NULL LeaveEffectiveDate,
CASE WHEN YEAR(FD.ExpectedReturnDate) > 2100 THEN NULL ELSE FD.ExpectedReturnDate END ExpectedReturnDate,
FD.FullPartTime,
FD.ShiftCode FWACode,
FD.Shift FWAName,
NULL Telework,
FD.StandardHoursFrequency,
NULL StandardHours,
FD.FTE,
FD.PaidFTE,
NULL OvertimeEligibility,
FD.EmployeeClassCode,
FD.EmployeeClass,
FD.RegularVersusTemporary RegularTemporary,
FD.EmployeeType,
NULL PersonnelStatusDesc,
FD.PersonOrganizationRelationshipCode,
NULL PersonOfInterest,
NULL PersonOfInterestDesc,
FD.PaygroupCode,
FD.EmployeeCategoryCode,
FD.EmployeeSubcategoryCode,
NULL EmploymentCategory,
NULL NonEmployeeNonWorkTypeCode,
NULL NonEmployeeNonWorkTypeDesc,
NULL GlobalAssignmentProgramCode,
NULL GlobalAssignmentProgramDesc,
NULL GlobalAssignmentStartDate,
NULL GlobalAssignmentEndDate,
NULL InPatExPatStatus,
NULL HomeCountry,
NULL HostCountry,
NULL EYStartDate,
NULL LastRehireDate,
NULL SeniorityDate,
NULL CurrentEmploymentDate,
NULL PartnerAdmissionDate,
R.RankCDName RankCodeName,
FD.Rank,
R.RankDesc,
FD.BusinessTitle,--NEW
R.RankGroup1,--NEW
FD.GFISRank,
NULL ExperienceLevel,
NULL GlobalGrade,
FD.JobCode,--NEW
NULL JobCodeDesc,--NEW
FD.DepartmentCode,
NULL DepartmentName,
FD.CompanyCode,
C.Description Company,
C.DescrAc CompanyAC,
NULL ManagerialCountry,
O.CodeBlock,
O.BUCD BU,
O.OUCD OU,
O.MUCD MU,
O.SMUCD SMU,
O.BUName,
O.OUName,
O.MUName,
O.SMUName,
O.UserDefSLHierarchy1 ServiceLine,
O.UserDefSLHierarchy2 SubSL1,
O.UserDefSLHierarchy3 SubSL2,
O.AlternateServiceLine,
O.UserDefAreaHierarchy1 BULevel1,
O.UserDefAreaHierarchy2 BULevel2,
O.UserDefAreaHierarchy3 BULevel3,
L.Location LocationCode,
L.City LocationCity,
L.State LocationStateProv,
L.Country LocationCountry,
L.UserDefinedHRGeo1 GeoLevel1,
L.UserDefinedHRGeo2 GeoLevel2,
L.UserDefinedHRGeo3 GeoLevel3,
L.UserDefinedHRGeo4 GeoLevel4,
L.UserDefinedHRGeo5 GeoLevel5,
NULL CounselorGUI,--NEW
NULL CounselorName,--NEW
NULL BillRate,
FD.Source,
--**** confidential fields ****
NULL GenderCode,
NULL TermCode,
FD.TerminationReasonCode,
FD.CompensationCurrency,
FD.CompensationRate,
FD.CompensationFrequency,
FD.MonthlyCompensationRate,
FD.AnnualCompensationRate,
NULL SalaryEffectiveDate,
FD.SalaryAdminPlanCode,
FD.SalaryAdminPlan,
FD.SalaryGrade,
CASE WHEN YEAR(FD.SalaryGradeEntryDate) > 2100 THEN NULL ELSE FD.SalaryGradeEntryDate END SalaryGradeEntryDate,
FD.Job_KEY,
row_number() over (partition by FD.EmployeeID, FD.EmployeeRecord, FD.JobEffectiveDate,
FD.JobEffectiveDateSequence, FD.ActionCode, FD.ActionReasonCode order by FD.Job_KEY DESC) as RowOrder
FROM dbo.vwRptDimEmployee_FutureDated FD
INNER JOIN dbo.vwRptDimOrganization O WITH (NOLOCK) ON (FD.DimOrganizationKey = O.DimOrganizationKey)
INNER JOIN dbo.vwRptDimLocation L WITH (NOLOCK) ON (FD.DimLocationKey = L.DimLocationKey)
LEFT OUTER JOIN dbo.vwRptDimRank R WITH (NOLOCK) ON (FD.Rank = R.RankCD)
LEFT OUTER JOIN dbo.vwRptDimEmployeeAll E WITH (NOLOCK) ON (FD.GPN = E.GPN AND FD.GPN <> '' AND E.RowIsCurrent = 'Y')
LEFT OUTER JOIN (SELECT *, ROW_NUMBER() OVER (PARTITION BY EmployeeID, NameType ORDER BY EffectiveDate DESC) AS RowOrder
FROM PISupport.vwRptPersonACNames WITH (NOLOCK)
) N ON (N.EmployeeID = FD.EmployeeID AND N.NameType = 'PRI' AND N.CountryNameFormat = FD.SetIDLaborAgreement AND N.RowOrder = 1)
LEFT OUTER JOIN (SELECT DISTINCT C1.*, ROW_NUMBER() OVER (PARTITION BY CompanyCode ORDER BY EffectiveDate DESC) as RowOrder
FROM PISupport.vwRptSetfCompany C1 WITH (NOLOCK)) C
ON (C.CompanyCode = FD.CompanyCode AND C.RowOrder = 1)
WHERE
FD.JobEffectiveDate BETWEEN #JobStartDate AND #JobEndDate
AND FD.EDWIsCurrentRecord = 1
AND FD.EmployeeID IS NOT NULL
--AND (E.ActionCode in ('ADD','DTA','HIR','POI','REH','PER','TER'))
--AND (O.BUCD+O.OUCD+O.MUCD+O.SMUCD LIKE '%'+#CodeBlock+'%' OR #CodeBlock IS NULL)
--AND (FD.GPN = #GPN OR #GPN IS NULL)
--AND (L.UserDefinedHRGeo1 in (#GeoArea) )
AND (L.UserDefinedHRGeo2 in ('UK and Ireland'))
--AND (L.UserDefinedHRGeo3 in (#Country) )
--AND (O.UserDefAreaHierarchy1 in (#Area) )
--AND (O.UserDefAreaHierarchy2 in (#Region) )
--AND (O.UserDefSLHierarchy1 in (#ServiceLine) )
--AND (O.UserDefSLHierarchy2 in (#SubServiceLine) )
--AND (FD.Rank in (#RankCode) )
AND FD.FutureDatedEmployeeRecordsKey NOT IN (SELECT FutureDatedEmployeeRecordsKey FROM #FutureDatedExclude)
) X
WHERE RowOrder = 1
DROP TABLE #FutureDatedExclude
You most likely ran this code before you added the DROP TABLE at the bottom of your code. Therefore, the table is created and yet to be dropped. Instead of dropping it at the end, or in addition to dropping it if you want, place this at the very top of your script:
IF OBJECT_ID('tempdb..#FutureDatedExclude') IS NOT NULL DROP TABLE #FutureDatedExclude

Ordering the results of CTE in SQL

I have following SQL:
;WITH CTE
AS (SELECT AL.*,
RV.FORENAME,
RV.SURNAME,
RV.USERNAME AS RegistrantUsername,
E.FORENAME AS EmployeeForename,
E.SURNAME AS EmployeeSurname,
U.USERNAME,
CASE
WHEN #Language = 2 THEN C.NAMELANG2
ELSE C.NAMELANG1
END AS CompanyName,
CASE
WHEN VC.COMPANYID IS NULL THEN
CASE
WHEN #Language = 2 THEN V.COMPANYNAMELANG2
ELSE V.COMPANYNAMELANG1
END
ELSE
CASE
WHEN #Language = 2 THEN VC.NAMELANG2
ELSE VC.NAMELANG1
END
END AS VacancyCompanyName,
CASE
WHEN #Language = 2 THEN V.JOBTITLELANG2
ELSE V.JOBTITLELANG1
END AS JobTitle,
ROW_NUMBER()
OVER(
PARTITION BY AL.REGISTRANTID, AL.COMPANYID
ORDER BY ACTIONDATE ASC) AS RN
FROM DBO.HR_ACTIONLOG AL
LEFT OUTER JOIN DBO.REGISTRANTSLISTVIEW RV
ON AL.REGISTRANTID = RV.REGISTRANTID
LEFT OUTER JOIN DBO.HR_EMPLOYEES E
ON AL.EMPLOYEEID = E.EMPLOYEEID
LEFT OUTER JOIN DBO.HR_USERS U
ON AL.USERID = U.USERID
LEFT OUTER JOIN DBO.HR_COMPANIES C
ON AL.COMPANYID = C.COMPANYID
LEFT OUTER JOIN DBO.HR_VACANCIES V
ON AL.VACANCYID = V.VACANCYID
LEFT OUTER JOIN DBO.HR_COMPANIES VC
ON V.COMPANYID = VC.COMPANYID
WHERE ( #Action IS NULL
OR AL.ACTION = #Action )
AND ( #DateFrom IS NULL
OR DBO.DATEONLY(AL.ACTIONDATE) >=
DBO.DATEONLY(#DateFrom) )
AND ( #DateTo IS NULL
OR DBO.DATEONLY(AL.ACTIONDATE) <= DBO.DATEONLY(#DateTo) )
AND ( #CompanyID IS NULL
OR AL.COMPANYID = #CompanyID )
AND ( #RegistrantID IS NULL
OR AL.REGISTRANTID = #RegistrantID )
AND ( #VacancyID IS NULL
OR AL.VACANCYID = #VacancyID )
--ORDER BY AL.ActionDate DESC
)
SELECT *
FROM CTE
WHERE RN = 1;
It returns first element from the group based on actiondate which is fine but the returned result is not ordered by date means returns each groups first record but the this collection of first records is not ordered by action date. I tried ORDER BY AL.ActionDate DESC in CTE but it gives error:
The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP or FOR XML is also specified.
Try this one -
;WITH CTE AS
(
SELECT ...
FROM dbo.hr_ActionLog AL
LEFT JOIN ...
WHERE AL.[Action] = ISNULL(#Action, AL.[Action])
AND dbo.DateOnly(AL.ActionDate) BETWEEN
dbo.DateOnly(ISNULL(#DateFrom, AL.ActionDate))
AND
dbo.DateOnly(ISNULL(#DateTo, '30000101'))
AND AL.CompanyID = ISNULL(#CompanyID, AL.CompanyID)
AND AL.RegistrantID = ISNULL(#RegistrantID, AL.RegistrantID)
AND AL.VacancyID = ISNULL(#VacancyID, AL.VacancyID)
)
SELECT *
FROM CTE
WHERE RN = 1
ORDER BY AL.ActionDate DESC;
Move order by clause outside of cte:
WITH CTE AS
(
...
)
SELECT *
FROM CTE
WHERE RN = 1;
ORDER BY ActionDate DESC
you do the ordering outside CTE
WITH CTE
AS
{
....
}
SELECT *
FROM CTE
WHERE RN = 1
ORDER BY ActionDate DESC
Yes, the only ORDER BY that affects the order in which the results are returned is one placed on the outermost SELECT:
SELECT *
FROM CTE
WHERE RN = 1
ORDER BY ActionDate DESC
You have a ROW_NUMBER function inside the CTE and the query only takes the row with RN=1.
If I understand the problem correctly, just change the ORDER BY clause in the ROW_NUMBER function and you should get the results you're looking for.

Getting distinct data using TSQL ( Top 1)

I have a stored procedure which gets data from different tables using LEFT join. I want to pick distinct records ( first one only).
Stored procedure is like this:
ALTER PROCEDURE [dbo].[hr_ActionLog_GetList]
#Action INT = NULL,
#DateFrom DATETIME = NULL,
#DateTo DATETIME = NULL,
#CompanyID INT = NULL,
#RegistrantID INT = NULL,
#VacancyID INT = NULL,
#Language INT = 1
AS
BEGIN
SELECT AL.[RegistrantID]
,[EmployeeID]
,AL.[UserID]
,[CompanyID]
,[VacancyID]
,[Action])
,[ActionDate],
RV.Forename,
RV.Surname,
RV.Username AS RegistrantUsername,
E.Forename AS EmployeeForename,
E.Surname AS EmployeeSurname,
U.Username,
CASE
WHEN #Language = 2 THEN V.JobTitleLang2
ELSE V.JobTitleLang1
END AS JobTitle
FROM dbo.hr_ActionLog AL LEFT OUTER JOIN dbo.RegistrantsListView RV ON AL.RegistrantID = RV.RegistrantID
LEFT OUTER JOIN dbo.hr_Employees E ON AL.EmployeeID = E.EmployeeID
LEFT OUTER JOIN dbo.hr_Users U ON AL.UserID = U.UserID
LEFT OUTER JOIN dbo.hr_Companies C ON AL.CompanyID = C.CompanyID
LEFT OUTER JOIN dbo.hr_Vacancies V ON AL.VacancyID = V.VacancyID
LEFT OUTER JOIN dbo.hr_Companies VC ON V.CompanyID = VC.CompanyID
WHERE (#Action IS NULL OR AL.Action = #Action)
AND (#DateFrom IS NULL OR dbo.DateOnly(AL.ActionDate) >= dbo.DateOnly(#DateFrom))
AND (#DateTo IS NULL OR dbo.DateOnly(AL.ActionDate) <= dbo.DateOnly(#DateTo))
AND (#CompanyID IS NULL OR AL.CompanyID = #CompanyID)
AND (#RegistrantID IS NULL OR AL.RegistrantID = #RegistrantID)
AND (#VacancyID IS NULL OR AL.VacancyID = #VacancyID)
ORDER BY AL.ActionDate DESC
END
sample data
1786 16294 15 16321 3 NULL 4 2013-08-03 12:18:08.130 cv 3 cv3#cc.com asif hameed asif#bb.com my company1aa NULL NULL
1785 16294 15 16321 3 NULL 4 2013-08-03 12:17:57.797 cv 3 cv3#cc.com asif hameed asif#bb.com my company1aa NULL NULL
1784 16293 15 16321 3 NULL 4 2013-08-03 12:17:47.243 cv 2 cv2#cc.com asif hameed asif#cc.com my company1aa NULL NULL
1783 16295 15 16321 3 NULL 4 2013-08-03 12:17:40.967 cv 4 cv4#cc.com asif hameed asif#cc.com my company1aa NULL NULL
1782 16292 15 16321 3 NULL 4 2013-08-03 12:17:31.953 cv 1 CV1#cc.com asif hameed asif#bb.com my company1aa NULL NULL
I want to get first record from action log table which is distinct.
I am not sure whether I understood your question correct; when you say "I want top get first record which is distinct".
But something like this might help.
I am still not sure what columns have duplicate values, but you can try this.
Select Distinct TOP 1 * from
( SELECT
AL.[RegistrantID]
,[EmployeeID]
,AL.[UserID]
,[CompanyID]
,[VacancyID]
,[Action])
,[ActionDate],
RV.Forename,
RV.Surname,
RV.Username AS RegistrantUsername,
E.Forename AS EmployeeForename,
E.Surname AS EmployeeSurname,
U.Username,
CASE
WHEN #Language = 2 THEN V.JobTitleLang2
ELSE V.JobTitleLang1
END AS JobTitle
FROM dbo.hr_ActionLog AL LEFT OUTER JOIN dbo.RegistrantsListView RV ON AL.RegistrantID = RV.RegistrantID
LEFT OUTER JOIN dbo.hr_Employees E ON AL.EmployeeID = E.EmployeeID
LEFT OUTER JOIN dbo.hr_Users U ON AL.UserID = U.UserID
LEFT OUTER JOIN dbo.hr_Companies C ON AL.CompanyID = C.CompanyID
LEFT OUTER JOIN dbo.hr_Vacancies V ON AL.VacancyID = V.VacancyID
LEFT OUTER JOIN dbo.hr_Companies VC ON V.CompanyID = VC.CompanyID
WHERE (#Action IS NULL OR AL.Action = #Action)
AND (#DateFrom IS NULL OR dbo.DateOnly(AL.ActionDate) >= dbo.DateOnly(#DateFrom))
AND (#DateTo IS NULL OR dbo.DateOnly(AL.ActionDate) <= dbo.DateOnly(#DateTo))
AND (#CompanyID IS NULL OR AL.CompanyID = #CompanyID)
AND (#RegistrantID IS NULL OR AL.RegistrantID = #RegistrantID)
AND (#VacancyID IS NULL OR AL.VacancyID = #VacancyID)
ORDER BY AL.ActionDate DESC ) subquery
You can even add Distinct inside the subquery and just select TOP 1 * in the main select
As ##BogdanSahlean suggested you can try following
Select * from
( SELECT
AL.[RegistrantID]
,[EmployeeID]
,AL.[UserID]
,[CompanyID]
,[VacancyID]
,[Action])
,[ActionDate],
RV.Forename,
RV.Surname,
RV.Username AS RegistrantUsername,
E.Forename AS EmployeeForename,
E.Surname AS EmployeeSurname,
U.Username,
CASE
WHEN #Language = 2 THEN V.JobTitleLang2
ELSE V.JobTitleLang1
END AS JobTitle,
ROW_NUMBER() OVER(PARTITION BY DATEPART(yy,YOURDATEHERE) ORDER BY YOURDATEHERE DESC) ROW
FROM dbo.hr_ActionLog AL LEFT OUTER JOIN dbo.RegistrantsListView RV ON AL.RegistrantID = RV.RegistrantID
LEFT OUTER JOIN dbo.hr_Employees E ON AL.EmployeeID = E.EmployeeID
LEFT OUTER JOIN dbo.hr_Users U ON AL.UserID = U.UserID
LEFT OUTER JOIN dbo.hr_Companies C ON AL.CompanyID = C.CompanyID
LEFT OUTER JOIN dbo.hr_Vacancies V ON AL.VacancyID = V.VacancyID
LEFT OUTER JOIN dbo.hr_Companies VC ON V.CompanyID = VC.CompanyID
WHERE (#Action IS NULL OR AL.Action = #Action)
AND (#DateFrom IS NULL OR dbo.DateOnly(AL.ActionDate) >= dbo.DateOnly(#DateFrom))
AND (#DateTo IS NULL OR dbo.DateOnly(AL.ActionDate) <= dbo.DateOnly(#DateTo))
AND (#CompanyID IS NULL OR AL.CompanyID = #CompanyID)
AND (#RegistrantID IS NULL OR AL.RegistrantID = #RegistrantID)
AND (#VacancyID IS NULL OR AL.VacancyID = #VacancyID)
ORDER BY AL.ActionDate DESC ) subquery
where subquery.Row = 1

Find Duplicate Phones using cte by comparing against other groups

I am trying to determine how many duplicate work phones I can find in Group 94 by comparing against all other groups that are active.
Contacts are grouped using GroupId
The ContactTable Only contains ids and NOT Phones
The DetailedContactTable contains phones
The ContactSummaryTable contains Group status
The sql is working by setting rownumber for each duplicate Workphone > 1.
The problem is that is setting the rownumber > 1 for all groups except for 94. I need to know 94 first and foremost. Any idea how I set rownumber > 1 for duplicates in GroupId 94 first?
DECLARE #GroupID Int
SET #GroupID = 94
;WITH cte AS
(
SELECT ROW_NUMBER() OVER (PARTITION BY d.WorkPhone ORDER BY c.id DESC)
AS rownumber
,d.WorkPhone
,c.id
,GroupID
FROM ContactTable c
INNER JOIN DetailedContactTable d
ON c.DetailedContactId = d.id
WHERE c.GroupID IN
(
SELECT id
FROM ContactSummaryTable WHERE id = #GroupID
OR GroupActive = 1
)
AND NOT d.WorkPhone IS NULL
AND d.WorkPhone <> ''
)
SELECT * FROM cte WHERE rownumber > 1
ORDER BY GroupID;
DECLARE #GroupID INT;
SET #GroupID = 94;
WITH BaseGroup
AS
(
SELECT c.GroupID
,d.WorkPhone
,c.id ContactID
FROM ContactTable c
INNER JOIN DetailedContactTable d ON c.DetailedContactId = d.id
WHERE c.GroupID = #GroupID
AND NOT d.WorkPhone IS NULL
AND d.WorkPhone <> ''
),
OtherGroups
AS
(
SELECT
d.WorkPhone
FROM ContactTable c
INNER JOIN DetailedContactTable d ON c.DetailedContactId = d.id
WHERE c.GroupID <> #GroupID
AND NOT d.WorkPhone IS NULL
AND d.WorkPhone <> ''
AND EXISTS (
SELECT *
FROM ContactSummaryTable WHERE id = c.GroupID
AND GroupActive = 1)
)
SELECT a.*
FROM BaseGroup a
INNER JOIN OtherGroups b ON a.WorkPhone = b.WorkPhone
ORDER BY a.WorkPhone
or
SELECT a.*, CASE WHEN b.WorkPhone IS NULL THEN 'no duplicate' ELSE 'duplicate' END [Status]
FROM BaseGroup a
LEFT JOIN OtherGroups b ON a.WorkPhone = b.WorkPhone
ORDER BY a.WorkPhone