sql get duplicate column values grouped by another column - sql

I've got the following temp table as an output from a query:
FacilityID UserID User_Name
1046 105 John Smith
1046 106 John Smith
1046 110 Jack Welsh
1091 107 Ana Romero
1091 248 Rebecca Cruz
1095 418 Alex Sterling
I need to display only these facilities that have users with the same name, and only these names should pass the query filter. This is to find out if any facility has users with exactly same name (even though these are different people). So, considering table above, I need to display only the following:
FacilityID UserID User_Name
1046 105 John Smith
1046 106 John Smith

I would use exists :
select t.*
from table t
where exists (select 1
from table t1
where t1.FacilityID = t.FacilityID and
t1.User_Name = t.User_Name and t.userid <> t1.userid
);

You can use exists:
select t.*
from t
where exists (select 1
from t t2
where t2.FacilityID = t.FacilityID and t2.user_name = t.user_name and
t2.UserId <> t.userId and
);
If you have a query returning results, then window functions are also a good choice:
with t as (<your query here>)
select t.*
from (select t.*, min(userid) over (partition by FacilityID, user_name) as min_ui,
max(userid) over (partition by FacilityID, user_name) as max_ui
from t
) t
where min_ui <> max_ui;

I would use the EXISTS clause:
(Example uses a CTE [TEMP] as a test)
;WITH TEMP (FacilityID, UserID, User_Name) AS (
SELECT * FROM (
VALUES
('1046','105','John Smith'),
('1046','106','John Smith'),
('1046','110','Jack Welsh'),
('1091','107','Ana Romero'),
('1091','248','Rebecca Cruz'),
('1095','418','Alex Sterling')
) AS A (Column1, Column2, Column3)
)
SELECT TEMP.*
FROM TEMP
WHERE EXISTS (SELECT 1
FROM TEMP SubT
WHERE SubT.FACILITYID = TEMP.FACILITYID
AND SubT.USER_NAME = TEMP.USER_NAME
AND TEMP.USERID <> SubT.USERID
)

I'll chip in my solution:
select FacilityID, UserID, User_Name from (
select FacilityID, UserID, User_Name
count(*) over (partition by User_Name) cnt
from MY_TABLE
) a where cnt > 1

Related

Select the duplicate rows with specific values

How can I only get the data with the same ID, but not the same Name?
The following is the example to explain my thought. Thanks.
ID Name Date
123 Amy 08/03/2022
123 Amy 12/03/2022
456 Billy 08/03/2022
456 Cat 09/03/2022
789 Peter 10/03/2022
Expected Output:
ID Name Date
456 Billy 08/03/2022
456 Cat 09/03/2022
How I have done.
select ID, Name, count(*)
from table
groupby ID, Name
having count(*) > 1
But the result included the following parts that I do not want it.
ID Name Date
123 Amy 08/03/2022
123 Amy 12/03/2022
One approach would be to use a subquery to identify IDs that have multiple names.
SELECT *
FROM YourTable
WHERE ID IN (SELECT ID FROM YourTable GROUP BY ID HAVING COUNT(DISTINCT Name) > 1)
I'd join the table to its self like this:
SELECT DISTINCT
a.Id as ID_A,
b.Id as ID_B,
a.[Name] as Name_A
FROM
Test as a
INNER JOIN Test as b
ON A.Id = B.Id
WHERE
A.[Name] <> B.[Name]
Do you want
SELECT * FROM table_name
WHERE ID = 456;
or
SELECT * FROM table_name
WHERE ID IN
(SELECT
ID
FROM table_name
GROUP BY ID
HAVING COUNT(DISTINCT name) > 1
);
?
Window functions are likely to be the most efficient here. They do not require self-joining of the source table.
Unfortunately, SQL Server does not support COUNT(DISTINCT as a window function. But we can simulate it by using DENSE_RANK and MAX
WITH DistinctRanks AS (
SELECT *,
rnk = DENSE_RANK(*) OVER (PARTITION BY ID ORDER BY Name)
FROM YourTable
),
MaxRanks AS (
SELECT *,
mr = MAX(rnk) OVER (PARTITION BY ID)
FROM DistinctRanks
)
SELECT
ID,
Name,
Count
FROM MaxRanks t
WHERE t.mr > 1;

SQL query to find same ID but different names

I have a table like this:
ID | name
45 Alex
98 Diana
32 Peter
98 Daniel
45 Alex
23 Bob
98 Jake
I need to find all rows where is the same ID but different name.
You could use first/last value() window functions here:
with n as (
select *,
First_Value(name) over(partition by id order by (select null)) n1,
Last_Value(name) over(partition by id order by (select null)) n2
from t
)
select Id, Name
from n
where n1 != n2
You can use exists:
select t.*
from mytable t
where exists (select 1
from mytable t2
where t2.id = t.id and t2.name <> t.name
);
A windowed count is usually the most efficient:
SELECT
t.ID,
t.name
FROM (
SELECT *,
c = COUNT() OVER (PARTITION BY t.name)
FROM YourTable t
) t
WHERE c > 1;
SELECT
ID,
name,
CASE WHEN COUNT(ID) OVER(PARTITION BY ID) = 1 THEN 'OK' ELSE 'NOT OK' END AS CountID
FROM Table
GROUP BY ID,name
ORDER BY ID
Example:

Procedure to copy data from a table to another table in SQL Server

I have a table A, with 4 columns:
first_name, invoice, value, date.
And a table B (first_name, max_invoice_name, max_invoice_value, last_date)
I want to create a procedure in order to move data from A, to B, but:
first_name should be one time in B,
max_invoice_name is the name of the max invoice value
max_invoice_value is the max value
last_date is the latest date from invoices from the same first_name.
For example:
TABLE A:
Smith | Invoice1 | 100 | 23.06.2016
John | Invoice13 | 23 | 18.07.2016
Smith | Invoice3 | 200 | 01.01.2015
Table B should be:
Smith |Invoice3 | 200 | 23.06.2016
John |Invoice13| 23 | 18.07.2016
Something like this should work:
select *, (select max(date) from #Table1 T1 where T1.first_name = X.first_name)
from (
select
*,
row_number() over (partition by first_name order by invoice_Value desc) as RN
from
#Table1
) X
where RN = 1
Row number takes care of selecting the row with biggest value, and the max get's the date. You'll need to list the columns in correct place instead of *
You will need to create 2 scalar functions getMaxNameForMaxValue AND getLastDateByFirstName to get the values you want.
INSERT INTO TableB (first_name, max_invoice_name, max_invoice_value, last_date) (SELECT DISTINCT first_name, getMaxNameForMaxValue(MAX(max_value)) AS 'max_invoice_name', MAX(max_invoice_value) AS 'max_invoice_value', getLastDateByFirstName(first_name) AS 'lastDate' FROM Table A)
You can use something like this:
--INSERT INTO TableB
SELECT first_name,
invoice_name,
invoice_value,
last_date
FROM (
SELECT a.first_name,
a.invoice_name,
a.invoice_value,
COALESCE(p.last_date,a.last_date) as last_date,
ROW_NUMBER() OVER (PARTITION BY a.first_name ORDER BY a.last_date) as rn
FROM TableA a
OUTER APPLY (SELECT TOP 1 * FROM TableA WHERE first_name = a.first_name and last_date > a.last_date) as p
) as res
WHERE rn = 1
As output:
first_name invoice_name invoice_value last_date
John Invoice13 23 2016-07-18
Smith Invoice3 200 2016-06-23
Try this
Insert into TableB(first_name, max_invoice_name, max_invoice_value, last_date)
select t1.first_name,t1.invoice,t1,value,t2.date from TableA as t1 inner join
(
select first_name, max(replace(invoice,'invoice','')) as invoice, max(date) as date
from TableA group by first_name
) as t2 on t1.first_name=t2.first_name and t1.invoice=t2.invoice

How to check duplicate column values?

I have create stored procedure to select data and result is:
ID NAME EMAIL
1 John asd#asd.com
2 Sam asd#asd.com
3 Tom asd#asd.com
4 Bob bob#asd.com
5 Tom asc#asd.com
and I would like to get result like:
ID NAME EMAIL
1 John asd#asd.com
2 Sam asd#asd.com
3 Tom asd#asd.com, asc#asd.com
4 Bob bob#asd.com
so, how can I do it?
Thanks.
select
id,
name,
email
from (
select
rn = row_number() over(partition by name order by id asc),
id,
name,
email = stuff((select ', ' + convert(varchar, t2.email)
from #table_var t2
where t1.name = t2.name
for xml path(''))
,1,2,'')
from #table_var t1
group by t1.id, t1.name
)t
where rn = 1
order by id
GROUP BY is what you're after.
For example
SELECT name, email, count(email)
FROM table
GROUP BY name, email
will return something like
1 John asd#asd.com 1
2 Sam asd#asd.com 1
3 Tom asd#asd.com 2
4 Bob bob#asd.com 1
adding
HAVING count(email) > 1
to the end will result in
1 Tom asd#asd.com 2
Just another way, could help
;WITH cte
AS
(
SELECT Id
,Name
,Email
,ROW_NUMBER() OVER(PARTITION BY Name,Email ORDER BY Id) AS rowNum
FROM Table
)
SELECT Id,Name,Email
FROM cte
WHERE rowNum=1;
A solution is :
select distinct e1.Name,
(case when e2.Email is null then e1.Email else
( case when e1.Email > e2.Email then e1.Email + ','+ e2.Email else e2.Email + ','+ e1.Email end )
end ) from MyTable e1
left join MyTable e2 on e1.Name = e2.Name and e1.Email <> e2.Email

How to perform SQL Query to get last entry

I am working on creating a SQL query where the result will return a student test score
from the last test that they took. I think that this should be fairly simple but I am just not seeing it.
Here is my test data
Name Date Score
John 2/3/2012 94
John 2/14/2012 82
John 2/28/2012 72
Mary 2/3/2012 80
Mary 2/28/2012 71
Ken 2/14/2012 68
Ken 2/14/2012 66
I want the returned result to be
John 2/28/2012 72
Mary 2/28/2012 80
Ken 2/14/2012 66
I appreciate any assistance.
select date, name, score
from temp t1
where date = (select max(date) from temp where t1.name = temp.name)
OR
SELECT a.*
FROM temp a
INNER JOIN
(
SELECT name,MAX(date) as max_date
FROM temp a
GROUP BY name
)b ON (b.name = a.name AND a.date=b.max_date)
Here is a sql fiddle with an example
or even this if you have more than one record for each person on a date like you show in your sample data.
SELECT c.name,c.date, MAX(c.score) as max_score
FROM
(
SELECT a.*
FROM temp a
INNER JOIN
(
SELECT name,MAX(date) as max_date
FROM temp a
GROUP BY name
)b ON (b.name = a.name AND a.date=b.max_date)
)c
group by c.name,c.date
Sql fiddle with this example
SELECT Name, Date, Score
FROM tablename t1
WHERE Date = (SELECT MAX(Date)
FROM tablename
WHERE Name = t1.Name
GROUP BY Name)
Which database are you using? Most support row_number() which is the right way to answer this:
select *
from
(
select t.*, row_number() over (partition by name order by date desc) as seqnum
from table t
)
where rownum = 1