How to list duplicate records? - sql-server

I have the following table structure:
id|date|studenttypeid|name|audituser
1|.....|4|Jason|....
2|.....|4|Robin|....
3|.....|4|Jason|....
4|.....|4|Dan|....
5|.....|4|Robin|....
I need to list all records which are duplicates on studenttypeid + name.
With the above data, the query should give me the following output:
1|.....|4|Jason|....
2|.....|4|Robin|....
3|.....|4|Jason|....
5|.....|4|Robin|....
How can I achieve this on SQL Server 2008?

You can use a group by and then join back to the original table, like this:
WITH Temp(StudentTypeId, Name) AS(
SELECT
StudentTypeId, Name
FROM YourTable
GROUP BY
StudentTypeId, Name
HAVING Count(1) > 1
)
SELECT YourTable.*
FROM YourTable
INNER JOIN Temp
ON YourTable.StudentTypeId = Temp.StudentTypeId
AND YourTable.Name = Temp.Name

you can use ROW_NUMBER()
SELECT ID, DATE, studenttypeid, name, audituser
FROM
(
SELECT ID, DATE, studenttypeid, name, audituser,
ROW_NUMBER() OVER (PARTITION BY studenttypeid, name
ORDER BY id) rn
FROM yourTableName
) a
WHERE rn = 1
SQLFiddle Demo

If you want to include every occurrence of the duplicates, some more methods using CROSS APPLY...
SELECT p.*
FROM people p
CROSS APPLY (
SELECT TOP(1) * FROM people p2 WHERE p2.ID <> p.ID AND p2.name = p.name AND p.studenttypeid = p2.studenttypeid
) as pWithDups
Or an EXISTS check
SELECT p.*
FROM people p
WHERE EXISTS (
SELECT *
FROM people p2
WHERE p2.ID <> p.ID AND p2.name = p.name AND p.studenttypeid = p2.studenttypeid
)

Try this
SELECT a.*
FROM yourtable a
JOIN (SELECT studenttypeid,
name
FROM yourtable
GROUP BY studenttypeid,
name
HAVING Count(studenttypeid) > 1) b ON b.name = a.name
ORDER BY a.id

Related

Select Multiple Columns join SQL Server

I have an Employee table like this
And a second table for EmployeeComments with the EmployeeID as foreign key:
I would like to query the employees with their comments in the following format:
select Name, Comment
from Employee emp
left join EmployeeComments empC on empC.EmployeeID = emp.ID
I would like the results to be like:
I have already looked at Pivot, but it doesn't resolve my issue
Use window function:
select case when row_number() over(partition by emp.name order by empC.ID) = 1
then Name
else '' end as Name,
Comment
from Employee emp
left join EmployeeComments empC On empC.EmployeeID = emp.ID
This might give you some kind of order in your result window at least
WITH cte AS(
SELECT emp.Name ,
empC.Comment,
RANK() OVER (ORDER BY emp.Name) NameOrder,
ROW_NUMBER() OVER (PARTITION BY emp.Name ORDER BY empC.ID) RN
FROM Employee emp
LEFT JOIN EmployeeComments empC ON empC.EmployeeID = emp.ID
)
SELECT
Name = (CASE WHEN RN = 1 THEN Name ELSE '' END),
Comment
FROM
cte
ORDER BY
NameOrder,
RN
"use Cross Join:"
Query:
select case t.cnt
when 1 then
coalesce(t.Name,' ')
end as Name,t.comment
from
(
select t1.Name,t2.comment,row_number()
over(partition by t1.name order by t1.Name)
as cnt
from
EmployeeComments t1
cross join
Employee t2
where t1.ID=t2.Employeeid
)t

How to use CROSS APPLY in this scenario

I have a ProductStatus table as listed below. I need to list all products whose latest status is “SU”. Along with that I need to list what was the previous status of this product.
Based on referring various posts, it seems like CROSS APPLY will be suitable for this. I made an attempt as listed below but that didn’t give the expected result.
What is the best way to achieve this in SQL Server 2005 (without using subquery)?
DECLARE #ProductStatus TABLE (ProductStatusID INT, productCode VARCHAR(5), statusCode VARCHAR(2))
INSERT INTO #ProductStatus
SELECT 1,'10011','RE' --Recevied
UNION
SELECT 2,'10011','SU' --Suspended
UNION
SELECT 3,'10012','IT' -- In Transit
UNION
SELECT 4,'10012','RE' -- Received
UNION
SELECT 10,'10012','PR' -- Produced
UNION
SELECT 12,'10012','SU' -- Suspended
UNION
SELECT 14,'10013','RE' -- Recevied
UNION
SELECT 16,'10014','SU' -- Recevied
UNION
SELECT 18,'10014','RE' -- Recevied
CROSS APPLY attempt
SELECT *
FROM #ProductStatus P
CROSS APPLY
(
SELECT MAX(V.ProductStatusID) as maxVal
FROM #ProductStatus V
WHERE V.ProductCode = P.ProductCode
AND V. ProductStatusID < P.ProductStatusID
GROUP BY V.ProductCode
)ML
WHERE P.statusCode = 'SU'
EXPECTED RESULT
You can do this with cross apply but I think row_number() is an easier approach:
select ProductCode,
max(case when seqnum = 1 then statusCode end) as LastStatus,
max(case when seqnum = 2 then statusCode end) as PrevStatus
from (select p.*,
row_number() over (partition by ProductCode order by ProductStatusId desc) as seqnum
from #ProductStatus p
) p
group by ProductCode
having max(case when seqnum = 1 then statusCode end) = 'SU';
Lijo, I've structured it as a CTE so you can see how I've developed my ideas. You can refactor it as sub-queries without affecting the meaning if you are more comfortable with those.
;with MostRecentStatus as (
select
MAX(ProductStatusID) as ProductStatusID,
productCode
from #ProductStatus as p1
group by productCode
)
,MostRecentIsSU as (
select
p2.ProductStatusID,
p2.productCode,
p2.statusCode
from MostRecentStatus as mrs
inner join #ProductStatus as p2
on p2.ProductStatusID = mrs.ProductStatusID
and p2.statusCode = 'SU'
)
select
m.ProductStatusID,
m.productCode,
m.statusCode,
p3.statusCode as PrevStatus,
p3.ProductStatusID as PrevProductStatusID
from MostRecentIsSU as m
left outer join #ProductStatus as p3
on p3.productCode = m.productcode
and p3.ProductStatusID = m.ProductStatusID - 1;
Edit: ..and here's the ROW_NUMBER() version with kudos to #attila.
;with InSquence as
(
select
ProductStatusID,
productCode,
statusCode,
ROW_NUMBER() OVER(PARTITION BY productCode ORDER BY ProductStatusID desc) as Sequence
from #ProductStatus
)
,FirstIsSU as
(
select
ProductStatusID,
productCode
from InSquence
where Sequence = 1
and statusCode = 'SU'
)
,PreviousCode as
(
select
ProductStatusID,
productCode,
statusCode
from InSquence
where Sequence = 2
)
select
f.ProductStatusID,
f.productCode,
'SU' as CurrentStatus,
p.statusCode as PrevStatus,
p.ProductStatusID as PrevProductStatusID
from FirstIsSU as f
left outer join PreviousCode as p
on p.productCode = f.ProductCode;
Here is a convoluted solution which serves mainly to illustrate that this should probably be done using row_number() :)
SELECT
F.productCode, F.statusCode, F.productStatusID, F.PriorProductStatusID, PriorStatus.statusCode
FROM
(
SELECT
PCS.productCode, PCS.statusCode, PCS.productStatusID, MAX(PS.productStatusID) PriorProductStatusID
FROM
(
SELECT productCode, MAX(productStatusID) productStatusID
FROM #ProductStatus
GROUP BY productCode
) LatestStatus
INNER JOIN
#ProductStatus PCS
ON PCS.productCode = LatestStatus.productCode
AND PCS.productStatusID = LatestStatus.productStatusID
AND PCS.statusCode = 'SU'
LEFT OUTER JOIN
#ProductStatus PS
ON PS.productCode = PCS.productCode
AND PS.productStatusID < PCS.productStatusID
GROUP BY PCS.productCode, PCS.statusCode, PCS.productStatusID
) F
LEFT OUTER JOIN
#ProductStatus PriorStatus
ON F.productCode = PriorStatus.productCode
AND F.PriorProductStatusID = PriorStatus.ProductStatusID

How to use count function in the below mentioned query?

I just want to know how to add count function in the below mentioned query in which I only have to display those records where count of p_id should equal to 1
select Distinct p_id,i.img_path as ImagesName,
(
select p.project_details from [Project] p where p.p_id=i.p_id
) as ProjectName
from [p_Image] i
Please try:
SELECT
*
FROM(
select
p_id,
i.img_path as ImagesName,
(
select p.project_details from [Project] p where p.p_id=i.p_id
) as ProjectName,
COUNT(*) OVER (PARTITION BY p_id) CNT
from [p_Image] i
)x WHERE CNT=1
Try this:
select p_id, i.img_path as ImagesName, p.project_details as ProjectName, count(*) as sum
from [p_Image] i
join [Project] p on (p.p_id=i.p_id)
group by p_id
having sum = 1;
Your query is equivalent to:
select p_id, i.img_path as ImagesName, p.project_details as ProjectName
from p_Image i left outer join
project p
on p.p_id=i.p_id;
Here are two ways to get "unique" p_id:
select p_id, min(i.img_path) as ImagesName, min(p.project_details) as ProjectName
from p_Image i left outer join
project p
on p.p_id = i.p_id
group by p_id
having count(*) = 1;
The logic: when the count is 1, then the min() there is only one value for img_path and project_details. The min() returns that value.
The following uses a subquery with a window function instead:
select p_id, ImagesName, ProjectName
from (select p_id, i.img_path as ImagesName, p.project_details as ProjectName,
count(*) over (partition by p_id) as cnt
from p_Image i left outer join
project p
on p.p_id=i.p_id
) pi
where cnt = 1;

How to get rows with Maximum id with condition of a table in SQL Server

i have a table similar this
id-value-RowInid
1-xy-1
1-xx-2
1-xz-3
2-xx-1
2-xr-2
3-xq-1
4-xa-1
4-xc-2
...
i need a function for this table with similar output to get maximum of RowInid in separated id group
1-xz-3
2-xr-2
3-xq-1
4-xc-2
...
You just need to use MAX(RowInid) with GROUP BY Id, value
SELECT ID, VALUE, MAX(RowInid) FROM myTable GROUP BY ID, VALUE
EDIT:
As you updated your question, you can get value field using sub-query like this:
SELECT ID, VALUE, RowInid
FROM myTable t1 WHERE RowInid =
(
SELECT MAX(RowInid) FROM myTable WHERE id = t1.id GROUP BY id
)
ORDER BY id ASC;
You can also achieve this using INNER JOIN like this:
SELECT t2.ID, VALUE, t2.RowInid FROM myTable t1
INNER JOIN
(
SELECT ID, MAX(RowInid) AS RowIniD FROM myTable GROUP BY ID
) AS t2
ON t1.ID = t2.ID AND t1.RowInid = t2.RowInid
ORDER BY t1.ID ASC;
See this SQLFiddle
See more about GROUP BY and MAX in SQL Server.
no need for group by or max at all
select id, value, rowinid from
( select *, row_number() over (partition by id, order by rowinid desc) rn from yourtable ) v
where rn = 1
Try with,
Use Sub Query to get Id, Value and Max RowInid,
SELECT m1.[Id],m1.Value, m1.RowInid
FROM [Practice].[dbo].[myTable] m1 WHERE RowInid = (SELECT MAX(m2.RowInid) FROM [Practice].[dbo].[myTable] m2 WHERE M1.Id = m2.Id GROUP BY Id)
above query return result like:
4-xx-2
3-xx-1
2-xx-2
1-xx-3
To Ascending this use,
SELECT m1.[id],m1.Value, m1.RowInid
FROM [Practice].[dbo].[myTable] m1 WHERE m1.RowInid = (SELECT MAX(m2.RowInid) FROM [Practice].[dbo].[myTable] m2 WHERE M2.id = m1.id GROUP BY id) ORDER BY m1.id ASC

select top 1 with a group by

I have two columns:
namecode name
050125 chris
050125 tof
050125 tof
050130 chris
050131 tof
I want to group by namecode, and return only the name with the most number of occurrences. In this instance, the result would be
050125 tof
050130 chris
050131 tof
This is with SQL Server 2000
I usually use ROW_NUMBER() to achieve this. Not sure how it performs against various data sets, but we haven't had any performance issues as a result of using ROW_NUMBER.
The PARTITION BY clause specifies which value to "group" the row numbers by, and the ORDER BY clause specifies how the records within each "group" should be sorted. So partition the data set by NameCode, and get all records with a Row Number of 1 (that is, the first record in each partition, ordered by the ORDER BY clause).
SELECT
i.NameCode,
i.Name
FROM
(
SELECT
RowNumber = ROW_NUMBER() OVER (PARTITION BY t.NameCode ORDER BY t.Name),
t.NameCode,
t.Name
FROM
MyTable t
) i
WHERE
i.RowNumber = 1;
select distinct namecode
, (
select top 1 name from
(
select namecode, name, count(*)
from myTable i
where i.namecode = o.namecode
group by namecode, name
order by count(*) desc
) x
) as name
from myTable o
SELECT max_table.namecode, count_table2.name
FROM
(SELECT namecode, MAX(count_name) AS max_count
FROM
(SELECT namecode, name, COUNT(name) AS count_name
FROM mytable
GROUP BY namecode, name) AS count_table1
GROUP BY namecode) AS max_table
INNER JOIN
(SELECT namecode, COUNT(name) AS count_name, name
FROM mytable
GROUP BY namecode, name) count_table2
ON max_table.namecode = count_table2.namecode AND
count_table2.count_name = max_table.max_count
I did not try but this should work,
select top 1 t2.* from (
select namecode, count(*) count from temp
group by namecode) t1 join temp t2 on t1.namecode = t2.namecode
order by t1.count desc
Here are to examples that you could use but the temp table use is more efficient than the view, but was done on a small data sample. You would want to check your own statistics.
--Creating A View
GO
CREATE VIEW StateStoreSales AS
SELECT t.state,t.stor_id,t.stor_name,SUM(s.qty) 'TotalSales'
,ROW_NUMBER() OVER (PARTITION BY t.state ORDER BY SUM(s.qty) DESC) AS 'Rank'
FROM [dbo].[sales] s
JOIN [dbo].[stores] t ON (s.stor_id = t.stor_id)
GROUP BY t.state,t.stor_id,t.stor_name
GO
SELECT * FROM StateStoreSales
WHERE Rank <= 1
ORDER BY TotalSales Desc
DROP VIEW StateStoreSales
---Using a Temp Table
SELECT t.state,t.stor_id,t.stor_name,SUM(s.qty) 'TotalSales'
,ROW_NUMBER() OVER (PARTITION BY t.state ORDER BY SUM(s.qty) DESC) AS 'Rank' INTO #TEMP
FROM [dbo].[sales] s
JOIN [dbo].[stores] t ON (s.stor_id = t.stor_id)
GROUP BY t.state,t.stor_id,t.stor_name
SELECT * FROM #TEMP
WHERE Rank <= 1
ORDER BY TotalSales Desc
DROP TABLE #TEMP

Resources