Home > Back-end >  SQL Find duplicated names and count it for each status
SQL Find duplicated names and count it for each status

Time:01-20

I found 85 duplicated names in my base with

SELECT Name, COUNT(*) 
FROM Tab 
GROUP BY Name
HAVING COUNT(*) > 1
ORDER BY 2 DESC, 1;

with the result set:

Name    COUNT(*)
a   28
b   12
c   10
d   8
e   5
f   4
g   3
h   3
i   2
...

My concern is to sort these duplicated names (303 entries in total) per status

SELECT Status, COUNT(*) FROM Tab
WHERE Name IN (SELECT Name FROM Tab GROUP BY Name HAVING COUNT(*) > 1)
GROUP BY Status
ORDER by Name;

give me this result:

Status  COUNT(*)
Ended   38
Deleted 21
InUse   244

Now I would like a combinaison of both queries meaning to show the duplicated names counted by status.

Name Ended Deleted InUse
a 6 2 20
b 0 0 12
c 0 8 2
d 6 1 1
e 4 0 1
f 0 3 1
g 1 1 1
h 1 2 0
i 1 0 1

If I can have an extra column as Total will be great also but my main goal is to build a query for this result set

CodePudding user response:

An example of Nathan_Sav's suggestion -

SELECT
    Name,
    SUM(Status = 'Ended') AS Ended,
    SUM(Status = 'Deleted') AS Deleted,
    SUM(Status = 'InUse') AS InUse,
    COUNT(*) AS Total
FROM Tab 
GROUP BY Name 
HAVING COUNT(*) > 1
ORDER BY InUse DESC

CodePudding user response:

You can achieve this by combining the two queries you provided and using a subquery to join the Tab table with a subquery that retrieves the duplicate names, and then group by both the Name and Status columns.

SELECT 
  sub.Name, 
  SUM(CASE WHEN sub.Status = 'Ended' THEN sub.count END) AS Ended,
  SUM(CASE WHEN sub.Status = 'Deleted' THEN sub.count END) AS Deleted,
  SUM(CASE WHEN sub.Status = 'InUse' THEN sub.count END) AS InUse,
  SUM(sub.count) as Total
FROM (
  SELECT 
    Tab.Name, 
    Tab.Status,
    COUNT(*) as count
  FROM Tab
  WHERE Tab.Name IN (
    SELECT Name FROM Tab GROUP BY Name HAVING COUNT(*) > 1
  )
  GROUP BY Tab.Name, Tab.Status
) as sub
GROUP BY sub.Name
ORDER BY sub.Name

The first subquery will select all the rows that have a duplicate name, and group them by Name, Status and count them. The outer query will then take that subquery and group it by name and status, using the SUM function with a case statement to sum up the count of each status. The last column is the sum of the count column from the first subquery

Please note that, this query will work only if you have a SQL version that supports subqueries in the FROM clause

CodePudding user response:

you can use Window function For Calculation Count and Create To Result with Pivot

This Code work to use sql server

DECLARE @cols AS NVARCHAR(MAX),@scols  AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)
select @cols = STUFF((SELECT distinct ','   QUOTENAME([Status])  from Tab
                 FOR XML PATH(''), TYPE  ).value('.', 'NVARCHAR(MAX)')   ,1,1,'' )
 
 
select @scols = STUFF((SELECT distinct ',ISNULL('   QUOTENAME([Status])  ',''0'') as '   QUOTENAME([Status])
                 from Tab  FOR XML PATH(''), TYPE  ).value('.', 'NVARCHAR(MAX)')  ,1,1,'')
 

 set @query = 'SELECT   Name,' @scols ' from 
             (
               
                select Name,[Status],CounStatus,Total
                from (
                select *,count(*) over (partition by Name,[Status]) as CounStatus
                ,count(*) over (partition by Name ) as Total
                ,ROW_NUMBER() over (partition by Name,[Status] order by [Status]) as rw
                from  Tab
                )d
                where  rw=1

            ) x
            pivot 
            (
               sum( CounStatus)  for [Status] in ('   @cols   ')
            ) p 
            
            '

execute(@query)

You can to insert the basic data with the following codes

create table Tab(Name nvarchar(100),Status nvarchar(100))
insert into tab (Name,Status)
select 'a' as Name,'Ended' as Status
go 6

insert into tab (Name,Status)
select 'a','Deleted'
go 2

insert into tab (Name,Status)
select 'a','InUse'
go 20

insert into tab (Name,Status)
select 'b','InUse'
go 12


insert into tab (Name,Status)
select 'c','Deleted'
go 8

insert into tab (Name,Status)
select 'c','InUse'
go 2

select Name,[Status],CounStatus,Total
from (
select *,count(*) over (partition by Name,[Status]) as CounStatus
,count(*) over (partition by Name ) as Total
,ROW_NUMBER() over (partition by Name,[Status] order by [Status]) as rw
from  Tab
)d
where  rw=1

  • Related