Find duplicate names with different dob tsql (T-SQL) - sql

I want to get the only duplicate names with different dob with dob in the result set. I don't want non-duplicate rows.
I tried CTE and combination of Group By and Having.
declare #person table (id int, e_name nvarchar(50), dob datetime)
INSERT #person VALUES (1,'Jack Hughens','1960-11-02')
INSERT #person VALUES (2,'Tom Hughens','1971-01-08')
INSERT #person VALUES (3,'Sam Scallion','1960-11-02')
INSERT #person VALUES (4,'Sam Scallion','1960-11-01')
INSERT #person VALUES (5,'Paul Darty','1994-10-19')
INSERT #person VALUES (6,'Paul Ashley','1983-09-21')
The result should be as below:
--------------------------------
|id|e_name |dob |
--------------------------------
|3|Sam Scallion |1960-11-02 |
--------------------------------
|4|Sam Scallion |1960-11-01 |
--------------------------------

If id is auto then you can do :
select p.*
from #person p
where exists (select 1 from #person p1 where p1.e_name = p.e_name and p.id <> p1.id);
However, you can also use dob instead of id :
select p.*
from #person p
where exists (select 1 from #person p1 where p1.e_name = p.e_name and p.dob <> p1.dob);

My suggestion uses GROUP BY with a HAVING-clause:
The mockup table to simulate your issue
declare #person table (id int, e_name nvarchar(50), dob datetime)
INSERT #person VALUES (1,'Jack Hughens','19601102')
INSERT #person VALUES (2,'Tom Hughens', '19710108')
INSERT #person VALUES (3,'Sam Scallion','19601102')
INSERT #person VALUES (4,'Sam Scallion','19601101')
INSERT #person VALUES (5,'Paul Darty', '19941019')
INSERT #person VALUES (6,'Paul Ashley', '19830921');
--The query
WITH FindNames AS
(
SELECT p.e_name
FROM #person p
GROUP BY p.e_name
HAVING COUNT(DISTINCT p.dob)>1
)
SELECT p.*
FROM #person p
INNER JOIN FindNames n ON p.e_name=n.e_name;
the idea in short:
Using COUNT(DISTINCT p.dob) will count differing values only.
The CTE will return names, where you see more than one, but different DOBs.
The final SELECT will JOIN the CTE's set, hence using it as filter.

Related

I need to migrate data from one old table to a new table by storing appropriate CityId instead CityName

I'm migrating data from one table to another table in SQL Server, In this process what I need to do is "I have 10 columns in old table one column is 'CityName' which is varchar and in the new table, I have a column 'CityId' which is an integer. And I have other table which has data about city id and names. I need store the appropriate cityId in new table instead of CityName. Please help me. Thanks in advance.
You'll need to join the source table to the CityName field in the city information table:
INSERT INTO dbo.Destination (CityID, OtherStuff)
SELECT t1.CityID, t2.OtherStuff
FROM CityInformationTable t1
INNER JOIN SourceTable t2
ON t1.CityName = t2.CityName
Below should give you an idea, you need to inner join to your look up table to achieve this.
declare #t_cities table (Id int, City nvarchar(20))
insert into #t_cities
(Id, City)
values
(1, 'London'),
(2, 'Dublin'),
(3, 'Paris'),
(4, 'Berlin')
declare #t table (City nvarchar(20), SomeColumn nvarchar(10))
insert into #t
values
('London', 'AaaLon'),
('Paris', 'BeePar'),
('Berlin', 'CeeBer'),
('London', 'DeeLon'),
('Dublin', 'EeeDub')
declare #finalTable table (Id int, SomeColumn nvarchar(10))
insert into #finalTable
select c.Id, t.SomeColumn
from #t t
join #t_cities c on c.City = t.City
select * from #finalTable
Output:
Id SomeColumn
1 AaaLon
3 BeePar
4 CeeBer
1 DeeLon
2 EeeDub

Check if entry of one table is in another one

I have two SQL Server tables.
First is filled with languagecodes (e.g. en, de, fr,..).
Second looks like:
ID | Lang | Text
----------------
..1..|..en..|..one..
..1..|..de..|..eins..
..1..|..fr..|..une..
..2..|..en..|..two..
..2..|..de..|..zwei..
Now what I want is to go trough the seconde table over every ID, check if there is a row for every language and if not add a empty row. So for the example above the second table will have an additional row:
..2..|..fr..|.. ..
Is there any way to realize this in SQL Server?
This whould be basic join question if you have ID at first table so the code is:
declare #tabLanguages table (id int,Lang char(2))
insert into #tabLanguages
values (1,'en'),(2,'de'),(3,'fr')
declare #Translation table (id int, Lang char(2), Text nvarchar(200))
insert into #Translation
values
(1,'en','one'),
(1,'de','eins'),
(1,'fr','.une'),
(2,'en','two'),
(2,'de','zwei')
select isnull(t.id,l.Id) as ID,
isnull(t.Lang,l.Lang) as Lang,
t.Text
from #tabLanguages l
left outer join #Translation t on l.id = t.Id
order by Id
But if you don't have Id in the first table then you can use following:
declare #tabLanguages table (Lang char(2))
insert into #tabLanguages
values ('en'),('de'),('fr')
declare #Translation table (id int, Lang char(2), Text nvarchar(200))
insert into #Translation
values
(1,'en','one'),
(1,'de','eins'),
(1,'fr','.une'),
(2,'en','two'),
(2,'de','zwei')
select isnull(t.id,l.Id) as ID,
isnull(t.Lang,l.Lang) as Lang,
t.Text
from (
select *, row_number() over (order by Lang) as Id
from #tabLanguages t
) l
left outer join #Translation t on l.id = t.Id
order by l.Id

Insert a row if it doesn't exist via query

I am trying to write a query that will insert a group of people into a table if that person does not exist. For example, I have table full of people and I need to add more people into the database and I don't know if they are already there. I do know that the social security number (ssn) will never be the same for two people. Could a query be used to check if the ssn is in the table and if not insert the person into the table? If the ssn is in the table then go to the next person and check?
I was thinking about using a stored procedure, but I do not have any rights to create a store procedure.
You can insert your data into a table variable or temp table and then INSERT INTO table from temp table where it does not exists in your table.
DECLARE #Inserted AS TABLE
(
NAME VARCHAR(50)
,SSN DECIMAL(10, 0)
)
INSERT INTO #Inserted
( NAME, SSN )
VALUES ( 'Bob', 123456789 )
, ( 'John', 123546789 )
, ( 'James', 123456798 )
INSERT INTO MyTable
SELECT *
FROM #Inserted AS i
LEFT OUTER JOIN MyTable AS m
ON i.SSN = m.SSN
WHERE m.SSN IS NULL
Here are a couple ideas to get you started. I use MERGE a lot because it offers so much control. You could also look into the IN clause as part of a WHERE predicate in the INSERT SELECT statement.
MERGE
DECLARE #PERSONTABLE TABLE (ID INT PRIMARY KEY IDENTITY(1,1), FirstName VARCHAR(max))
INSERT INTO #PERSONTABLE (FirstName) VALUES ('Bill'),('Sally'),('Bob')
DECLARE #NEWPEOPLE TABLE (FirstName VARCHAR(max))
INSERT INTO #NEWPEOPLE (FirstName) VALUES ('Jim'), ('Sally')
--MERGE
MERGE INTO #PERSONTABLE AS T
USING #NEWPEOPLE AS S
ON (T.FirstName = S.FirstName)
WHEN NOT MATCHED BY TARGET THEN
INSERT (FirstName) VALUES (S.FirstName);
SELECT * FROM #PERSONTABLE
EXCEPT
DECLARE #PERSONTABLE TABLE (ID INT PRIMARY KEY IDENTITY(1,1), FirstName VARCHAR(max))
INSERT INTO #PERSONTABLE (FirstName) VALUES ('Bill'),('Sally'),('Bob')
DECLARE #NEWPEOPLE TABLE (FirstName VARCHAR(max))
INSERT INTO #NEWPEOPLE (FirstName) VALUES ('Jim'), ('Sally')
--EXCEPT
INSERT INTO #PERSONTABLE (FirstName)
SELECT FirstName FROM #NEWPEOPLE
EXCEPT
SELECT FirstName FROM #PERSONTABLE
SELECT * FROM #PERSONTABLE
You could do it like this if the new people are in another table. If not, then use Vladimir's solution.
INSERT INTO People(ssn, firstname, lastname)
SELECT ssn, firstname, lastname
FROM newpeople
WHERE ssn not in (select ssn from people )
INSERT INTO People(ssn, firstname, lastname)
SELECT np.ssn, np.firstname, np.lastname
FROM newpeople np
LEFT JOIN People p on np.ssn = p.ssn
WHERE p.ssn IS NULL
Here's another option I use a lot. Normally joins are better than sub-selects... if the joined table value is null you know you don't have a hit in the joined table.

Find and insert dummy rows - possible scenario for OUTER APPLY

This is a mock up of the situation we've got:
IF OBJECT_ID('TEMPDB..#People') IS NOT NULL BEGIN DROP TABLE #People END;
CREATE TABLE #People
(
Name VARCHAR(100),
Category VARCHAR(20),
ID INT
);
INSERT INTO #People
values
('x','Bronze',1),
('y','Bronze',2),
('z','Silver',3),
('j','Gold',4),
('q','Bronze',5),
('x','Silver',1);
IF OBJECT_ID('TEMPDB..#Category') IS NOT NULL BEGIN DROP TABLE #Category END;
CREATE TABLE #Category
(
Category VARCHAR(100)
);
INSERT INTO #Category
values
('Gold'),
('Silver'),
('Bronze');
If a name does not have a Category e.g. x does not have Gold then I'd like a row creating and adding into the table #People with an ID of -1.
Current solution I have is this:
WITH x AS
(
SELECT DISTINCT
x.Name,
s.Category
FROM #People x
CROSS JOIN #Category s
)
INSERT INTO #People
SELECT J.Name,
J.Category,
ID = -1
FROM x J
WHERE NOT EXISTS
(
SELECT 1
FROM #People Q
WHERE J.Name = Q.Name
AND J.Category = Q.Category
);
See it works!...:
SELECT *
FROM #People;
I have a feeling CROSS APPLY might be a good operator to use in order to simplify the above - What is the simplest way to find, create and insert these rows?
insert into People(Name, Category, Id)
(
select distinct
p.Name,
c.Category,
p.Id
from
people p
cross join category c
where
Concat(p.id, c.Category) not in (select Concat(id, Category) from people)
);
http://www.sqlfiddle.com/#!6/92cd5/14

SQL Server 2005 Pivot Table question

I have an Entity-Value set of tables, and would like to pivot the results.
Here's the effect that I'm looking for, except you see that the SELECT stmt using Common Table Expressions isn't working exactly right yet.
My question is: Am I on the right track, or is there some sort of easy pivot command?
USE TempDB
Declare #Person TABLE(
PersonID Int Identity(101,1))
INSERT INTO #Person DEFAULT VALUES
INSERT INTO #Person DEFAULT VALUES
INSERT INTO #Person DEFAULT VALUES
INSERT INTO #Person DEFAULT VALUES
DECLARE #Attribute TABLE(
AttributeID Int Identity(10,1) PRIMARY KEY,
AttributeName Varchar(MAX))
INSERT INTO #Attribute(AttributeName) VALUES('Firstname')
INSERT INTO #Attribute(AttributeName) VALUES('Lastname')
DECLARE #Pat TABLE( -- A Person's Attributes
PatID Int Identity,
PersonID Int,
AttributeID Int,
PatValue Varchar(MAX)
)
INSERT INTO #Pat(PersonID,AttributeID,PatValue) VALUES(101,10,'John')
INSERT INTO #Pat(PersonID,AttributeID,PatValue) VALUES(102,10,'Paul')
INSERT INTO #Pat(PersonID,AttributeID,PatValue) VALUES(103,10,'George')
INSERT INTO #Pat(PersonID,AttributeID,PatValue) VALUES(104,10,'Ringo')
INSERT INTO #Pat(PersonID,AttributeID,PatValue) VALUES(101,11,'Lennon')
INSERT INTO #Pat(PersonID,AttributeID,PatValue) VALUES(102,11,'McCartney')
INSERT INTO #Pat(PersonID,AttributeID,PatValue) VALUES(103,11,'Harrison')
SELECT Pat.PersonID,AttributeName,PatValue
FROM #Pat Pat
INNER JOIN #Person Person
ON Pat.PersonID = Person.PersonID
INNER JOIN #Attribute Attribute
ON Pat.AttributeID=Attribute.AttributeID
--
;WITH CTE1 AS(
SELECT PersonID,PatValue AS FirstName
FROM #Pat Pat
INNER JOIN #Attribute Attribute
ON Pat.AttributeID=Attribute.AttributeID
WHERE AttributeName='FirstName'
)
,CTE2 AS(
SELECT PersonID,PatValue AS LastName
FROM #Pat Pat
INNER JOIN #Attribute Attribute
ON Pat.AttributeID=Attribute.AttributeID
WHERE AttributeName='LastName'
)
SELECT Pat.PersonID,FirstName,LastName
FROM #Pat Pat
LEFT OUTER JOIN CTE1
ON Pat.PersonID=CTE1.PersonID
LEFT OUTER JOIN CTE2
ON Pat.PersonID=CTE2.PersonID
ORDER BY PersonID
I just want a list of the 4 people, with their firstname and lastname.
Good example Here
Query in your case would look like this:
SELECT PersonId, FirstName, LastName
FROM
(
-- your query
SELECT Pat.PersonID,AttributeName,PatValue
FROM #Pat Pat
INNER JOIN #Person Person
ON Pat.PersonID = Person.PersonID
INNER JOIN #Attribute Attribute
ON Pat.AttributeID=Attribute.AttributeID
) up
PIVOT (MAX(PatValue) FOR AttributeName IN (FirstName, LastName)) AS pvt