This is my query having the Current Results as displayed below.
SELECT
Distinct CONVERT(int, Employees_1.Emp_Badge_No) AS Emp_Badge_No,
Employees_1.Emp_LastName, Employees_1.Emp_FirstName, Employees_1.Email,
Employees_1.NT_Name, Employees_1.Dept_key,
Employees_1.Emp_LastName + ',' + Employees_1.Emp_FirstName AS FullName,
dbo.department_vw.DepartmentShortName AS deptname,
Employees_1.active_flag
FROM data_common.dbo.employees_union_vw AS Employees_1
INNER JOIN dbo.department_vw
ON Employees_1.Dept_key = dbo.department_vw.DepartmentKey
Sample data:
I need help to achieve the Expected Results. What will I modify with my existing sql query?
I want to keep all the records even though it is inactive as long as the Emp_Badge_No is not repeated. I only want those duplicate Emp_Badge_No to be remove.
Thanks in advance.
You may want to use ROW_NUMBER for this. Modify the ORDER BY clause depending on which row from the duplicate entry you want to retrieve:
WITH Cte AS(
SELECT
e.Emp_Badge_No,
e.Emp_LastName,
e.Emp_FirstName,
e.Email,
e.NT_Name,
e.Dept_key,
e.Emp_LastName + ',' + e.Emp_FirstName AS FullName,
d.DepartmentShortName AS deptname,
e.active_flag,
rn = ROW_NUMBER() OVER(PARTITION BY e.Emp_Badge_No ORDER BY e.Active)
FROM data_common.dbo.employees_union_vw AS e
INNER JOIN dbo.department_vw d
ON e.Dept_key = d.DepartmentKey
)
SELECT
Emp_Badge_No,
Emp_LastName,
Emp_FirstName,
Email,
NT_Name,
Dept_key,
FullName,
deptname,
active_flag
FROM Cte
WHERE rn = 1
The above will get the Inactive record if there are duplicates. If you want to get the Active records instead, replace rn with:
ROW_NUMBER() OVER(PARTITION BY Emp_Badge_No ORDER BY e.Active DESC)
If you don't care whether it's Active or Inactive, replace rn with:
ROW_NUMBER() OVER(PARTITION BY Emp_Badge_No ORDER BY (SELECT NULL))
Related
I have following result set,
Now with above results i want to print the records via select query as below attached image
Please note, I will have only two types of columns in output Present Employee & Absent Employees.
I tried using pivot tables, temporary table but cant achieve what I want.
One method would be to ROW_NUMBER each the the "statuses" and then use a FULL OUTER JOIN to get the 2 datasets into the appropriate columns. I use a FULL OUTER JOIN as I assume you could have a different amount of employees who were present/absent.
CREATE TABLE dbo.YourTable (Name varchar(10), --Using a name that doesn't require delimit identification
Status varchar(7), --Using a name that doesn't require delimit identification
Days int);
GO
INSERT INTO dbo.YourTable(Name, Status, Days)
VALUES('Mal','Present',30),
('Jess','Present',20),
('Rick','Absent',30),
('Jerry','Absent',10);
GO
WITH RNs AS(
SELECT Name,
Status,
Days,
ROW_NUMBER() OVER (PARTITION BY Status ORDER BY Days DESC) AS RN
FROM dbo.YourTable)
SELECT P.Name AS PresentName,
P.Days AS PresentDays,
A.Name AS AbsentName,
A.Days AS AbsentDays
FROM (SELECT R.Name,
R.Days,
R.Status,
R.RN
FROM RNs R
WHERE R.Status = 'Present') P
FULL OUTER JOIN (SELECT R.Name,
R.Days,
R.Status,
R.RN
FROM RNs R
WHERE R.Status = 'Absent') A ON P.RN = A.RN;
GO
DROP TABLE dbo.YourTable;
db<>fiddle
2 CTE's is actually far neater:
WITH Absents AS(
SELECT Name,
Status,
Days,
ROW_NUMBER() OVER (ORDER BY Days DESC) AS RN
FROM dbo.YourTable
WHERE Status = 'Absent'),
Presents AS(
SELECT Name,
Status,
Days,
ROW_NUMBER() OVER (ORDER BY Days DESC) AS RN
FROM dbo.YourTable
WHERE Status = 'Present')
SELECT P.Name AS PresentName,
P.Days AS PresentDays,
A.Name AS AbsentName,
A.Days AS AbsentDays
FROM Absents A
FULL OUTER JOIN Presents P ON A.RN = P.RN;
I have a table that logs all updates made to an application. I want to query the table and return the last update by [Timestamp] and the update before that for a different value [ITEM]. I'm struggling to figure out how to get what i need. I'm returning more than one record for each ID and don't want that.
;WITH cte AS
(
SELECT
ID,
LAG(ITEM) OVER (PARTITION BY ID ORDER BY timestamp DESC) AS ITEM,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY timestamp DESC) RN
FROM
MyLoggingTable
WHERE
accountid = 1234
)
SELECT
cte.ID,
dl.ITEM,
DL.timestamp
FROM
cte
JOIN
MyLoggingTable DL ON cte.ID = DL.ID
WHERE
rn = 1
AND cte.ID IN ('id here | Sub select :( ..')
Is ID unique? Because if it is, your code shouldn't return duplicates. If it isn't, you will get duplicates because you are joining back to the MyLoggingTable which isn't needed. You should just move those columns (dl.Item & dl.timestamp) into the cte and return them from the cte like you did cte.ID.
I removed the LAG since you didn't return that column in your final query.
;WITH cte AS
(
SELECT
ID,
ITEM,
[timestamp],
--LAG(ITEM) OVER (PARTITION BY ID ORDER BY timestamp DESC) AS ITEM,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY timestamp DESC) RN
FROM
MyLoggingTable
WHERE
accountid = 1234
)
SELECT
cte.ID,
cte.ITEM,
cte.timestamp
FROM
cte
WHERE
rn = 1
AND cte.ID IN ('id here | Sub select :( ..')
Note, if you wanted the second to the last item, as you stated in your comments, make rn=2
How to use DISTINCT keyword in SQL Server? I mean if it can work for given field.
select id, name, age
from dbo.XXX
There are multiple row returned by the query. I would like to get how many kinds of id or name or age.
select **distinct** id, name, age from dbo.XXX or
select id, **distinct** name, age from dbo.XXX or
select id, name, **distinct** age from dbo.XXX
To sum up, I would like to use a single SQL to get the distinct count of each fields, like select π±πΆπππΆπ»π°π id, π±πΆπππΆπ»π°π name, π±πΆπππΆπ»π°π age from dbo.XXX
Dense_Rank can be used to calculate a distinct count for any column and multiple columns:
Select col1, col2, col3,
dense_rank() over (partition by [col1] order by [Unique ID]) + dense_rank() over (partition by [col1] order by [Unique ID] desc) - 1 as DistCountCol1,
dense_rank() over (partition by [col2] order by [Unique ID]) + dense_rank() over (partition by [col2] order by [Unique ID] desc) - 1 as DistCountCol2,
dense_rank() over (partition by [col3] order by [Unique ID]) + dense_rank() over (partition by [col3] order by [Unique ID] desc) - 1 as DistCountCol3
from [table]
select distinct ID
from dbo.XXX
Select distinct name
from dbo.XXX
Select distinct age
from dbo.XXX
If you want to know how many rows you have for each distinct ID or Name or Age, you can use the following:
Select ID, count(id) as [ID_Recurrence]
from dbo.XXX
group by ID
Select Age, count(age) as [Age_Recurrence]
from dbo.XXX
group by Age
Select Name, count(name) as [Name_Recurrence]
from dbo.XXX
group by Name
The DISTINCT keyword return a unique row like the Following
SELECT DISTINCT ID FROM SomeTable
SELECT DISTINCT ID , SCORE FROM SomeTable
If you want to get unique value from row try the following code.
The Below code is copied from here
select t.id, t.player_name, t.team
from tablename t
join (select team, min(id) as minid from tablename group by team) x
on x.team = t.team and x.minid = t.id
select COUNT(distinct id) uniqueIDCount
from dbo.XXX
would count distinct values of id field, if you want to count distinct values for field combination you must concat fields, assuming your id is integer and name is nvarchar:
select COUNT(distinct CONVERT(nvarchar, id) + name) uniqueIDCount
from dbo.XXX
note that even this way looks nice it is probably not the most efficient one, here you have more efficient, but also more complicated method way:
with c as (
select distinct id, name
from dbo.XXX
)select COUNT(1)
from c
Not sure why it's complicated. U can have 3 different queries and u can union to return single set if u want .
I have two tables:
Customer which has an Id column representing the customer Id.
CustomerDonation that contains CustomerId (FK), Amount and DatePayed
I'd like have all the customers together with their latest donation and the amount of that donation.
I am receiving duplicate values on my query so I will not paste it here.
You could also use the WITH TIES option
Select Top 1 With Ties *
From YourTable
Order By Row_Number() over (Partition By CustomerId Order By DatePayed Desc)
WITH
SortedDonation AS
(
SELECT
ROW_NUMBER() OVER (PARTITION BY CustomerId ORDER BY DatePayed DESC) AS SeqID,
*
FROM
CustomerDonation
)
SELECT
*
FROM
Customer
LEFT JOIN
SortedDonation
ON SortedDonation.CustomerId = Customer.Id
AND SortedDonation.SeqId = 1
If the same customer can make multiple donations with the same DatePayed, then this will arbitrarily pick just one of them.
If you add additional fields to the ORDER BY you can deterministically pick which one you want.
Or, if you want all of them use DENSE_RANK() instead of ROW_NUMBER()
Use Row_Number() Analytic function .
Select * from (
Select customerId,Amount,DatePayed, row_number() over (partition by CustomerId order by DatePayed desc) as rowN)
as tab where rowN = 1
You only need the CustomerDonation table for this. You can join with the Customer table if you want other information of the customer.
WITH cte AS (
SELECT
CustomerId
, MAX(DatePayed) AS LastDate
FROM
CustomerDonation
)
SELECT
cd.CustomerId
, cd.Amount
, cd.DatePayed
FROM
CustomerDonation cd
JOIN cte ON cd.CustomerId = cte.CustomerId
AND cd.DatePayed = cte.LastDate
I have a table with a whole bunch of data. In that table there is a row, with not unique ids, so there can be dublets of them - I have found them by doing this query:
SELECT theid FROM thetable
GROUP BY theid
HAVING COUNT(*) > 1
In the table there is also columns like street1,street2,city1,city2
In the list of rows from the first query where I found dublets, in those I need to check if street1 is different from street2 and city1 from city2, in any of the dublets of the given id from the first query - makes sense?
So lets say we have two rows with the same ids - in those i need to check if street1 is different from street1 in all rows with the specific id
Any tips, pointers on how to do this, I am getting blind starring at this problem, and cant seem to find the right query for that.
Thanks a bunch
Using a CTE will help:
;WITH CTE AS
(
SELECT theID,
Street1,
Street2,
Street3,
City,
State,
Zip,
rn = ROW_NUMBER() OVER(PARTITION BY theID ORDER BY theID)
FROM Table
-- add joins if necessary
)
SELECT oldestID = c1.theID,
oldestStreet1 = c1.Street1,
newestStreet1 = c2.Street1,
newestID = c2.theID
FROM CTE c1
INNER JOIN CTE c2 ON c2.rn = c1.rn + 1
You could also add a case statement to display matches vs. non-matches. This will help to manually identify typos (1337 Test St. vs 1337 Test Street):
;WITH CTE AS
(
SELECT theID,
Street1,
Street2,
Street3,
City,
State,
Zip,
rn = ROW_NUMBER() OVER(PARTITION BY theID ORDER BY theID)
FROM Table
-- add joins if necessary
)
SELECT oldestID = c1.theID,
oldestStreet1 = CASE WHEN c1.Street1 = c2.Street1 THEN 'Match' ELSE c1.Street1 END,
newestStreet1 = CASE WHEN c1.Street1 = c2.Street1 THEn 'Match' ELSE c2.Street1 END,
newestID = c2.theID
FROM CTE c1
INNER JOIN CTE c2 ON c2.rn = c1.rn + 1
Or you could return just the items that do not match by adding it to your INNER JOIN clause:
;WITH CTE AS
(
SELECT theID,
Street1,
Street2,
Street3,
City,
State,
Zip,
rn = ROW_NUMBER() OVER(PARTITION BY theID ORDER BY theID)
FROM Table
-- add joins if necessary
)
SELECT oldestID = c1.theID,
oldestStreet1 = c1.Street1,
newestStreet1 = c2.Street1,
newestID = c2.theID
FROM CTE c1
INNER JOIN CTE c2 ON c2.rn = c1.rn + 1 AND c1.Street1 <> c2.Street1 -- add as many of these as you need.
Keep in mind these are exact matches. You could implement static-fuzzy logic LEFT(Zip, 5) to match only on the first 5 digits of Zip Code (in case some have a zip + 4 and some don't.)
you can also analyse like this,
;WITH CTE AS
(
SELECT theID,
Street1,
Street2,
Street3,
City,
State,
Zip,
rn = ROW_NUMBER() OVER(PARTITION BY theID ORDER BY theID)
FROM Table
-- add joins if necessary
)
,
CTE1 as
(
select *,ROW_NUMBER()
OVER(PARTITION BY theID,Street1,Street2,City,State,Zip
oRDER BY theID) rn2 from cte where rn>2
)
select * from cte1