I am trying to match the first name varchar (50) and last name varchar(50) from table A to the first name varchar(50) and last name varchar(50) on table B. The issue is that both table contain a lot of shortened first names like the name Andrew in table A and there might be a matching record with the last name but the first name is Andy so it comes up as not a match. Is there anyway to get around this in SQL. The shortened names is a vice verse problem meaning that both Table A and Table B have some shortened names.
Here are some more examples:
This is my current code.
Select *
FROM TableA p
JOIN TableB e ON e.CompanyNumber = 1 and e.LastName like '%' + rtrim(ltrim(p.lastname)) + '%'
and e.FirstName like '%' + ltrim(rtrim(p.firstname)) + '%'
NOTE: This is the only way to match the tables together.
Create a third table that associates Long-form and short-form names.
For examle:
Long Form Short Form
Andrew Andy
Andrew Drew
David Dave
William Will
William Bill
William Billy
William Willy
Provided you use a 3rd Table to hold you Long/Short Names as so.
CREATE TABLE TableNames
([Id] int, [OfficialName] varchar(7), [Alias] varchar(7))
;
INSERT INTO TableNames
([Id], [OfficialName], [Alias])
VALUES
(1, 'Andrew', 'Andy'),
(2, 'Andrew', 'Andrew'),
(3, 'William', 'Bill'),
(4, 'William', 'William'),
(5, 'David', 'Dave'),
(6, 'David', 'David')
The following query should give you what you are looking for.
SELECT *
FROM (
SELECT TableA.Id AS T1_Id
,CompanyId AS T1_CompanyId
,FirstName AS T1_FirstName
,LastName AS T1_LastName
,TableNames.OfficialName AS OfficialName
FROM tableA
INNER JOIN tableNames ON TableA.FirstName = TableNames.Alias
) T1
,(
SELECT tableB.Id AS T2_Id
,CompanyId AS T2_CompanyId
,FirstName AS T2_FirstName
,LastName AS T2_LastName
,TableNames.OfficialName AS OfficialName
FROM tableB
INNER JOIN tableNames ON TableB.FirstName = TableNames.Alias
) T2
WHERE T1.T1_CompanyId = T2.T2_CompanyId
AND T1.OfficialName = T2.OfficialName
AND T1.T1_LastName = T2.T2_LastName
I set up my solution sqlfiddle at http://sqlfiddle.com/#!3/64514/2
I hope this helps.
Select *
<br>FROM TableA pJOIN TableB e
<br>ON e.CompanyNumber = 1
<br>and e.LastName like '%' + rtrim(ltrim(p.lastname)) + '%'
<br>OR
<br>e.FirstName like '%' + ltrim(rtrim(p.firstname)) + '%'
Now this depends how you determine it is match,
example:
TableA:
--------
Rownum FristName LastName
1 Andy Smith
2 Andy Mathew
TableB:
--------
Rownum FristName LastName
1 Logan Andy
2 Mathew Andy
Now will you consider first record from both the tables as a match
What about the second record in both the tables?
Basing on this we can even change the query
Related
I have a database:
|id|surname|name
| 1|Smith |John
| 2|Smith |Mike
| 3|Smith |Bob
| 4|Knope |John
| 5|Knope |Mike
| 6|Knope |Dick
| 7|Pratt |John
| 8|Pratt |Jill
| 9|Pratt |James
and I want to find a family name that has in it John, Mike and Bob. I want it to return Smith. Or I want to search for a family that has in it John and Mike and I want it to return Smith and Knope. How can I do that?
the results that I want to get are above but here's the same with nicer form:
I'm looking for family that has Jon, Mike, Bob. I want to get:
|surname|
|Smith |
Then I want to look for John and Mike only and I want to get:
|surname|
|Smith |
|Knope |
Based on your explantions you can do something like this:
declare #table table (it int, surename varchar(50),name1 varchar(50))
insert into #table
values
(1,'Smith','John'),
(2,'Smith','Mike'),
(3,'Smith','Bob' ),
(4,'Knope','John'),
(5,'Knope','Mike'),
(6,'Knope','Dick'),
(7,'Pratt','John'),
(8,'Pratt','Jill'),
(9,'Pratt','James')
select * from #table
where name1 in ('john','mike','bob') and surename = 'smith'
union
select * from #table
where name1 in('john','mike') and surename in ('smith','knope')
Result
Your input has dynamically multiple values. Thus, I will assume you have put all of the names you want the family to include in a table #i with field "name". Then, you want all families for which no name specified in your input is missing.
select *
from (select distinct surename from yourtable)surnames
where not exists
(
select 1 from #i
where not exists
(
select 1
from yourtable t
where
t.surename=surnames.surename
and #i.name=t.name
)
)
This works in SQL Server - written before your question was tagged with PostgreSQL.
Set up the test data:
DECLARE #Names TABLE (ID INTEGER IDENTITY, Surname VARCHAR(50), Forenames VARCHAR(50));
INSERT
#Names (Surname, Forenames)
VALUES
('Smith', 'John'),
('Smith', 'Mike'),
('Smith', 'Bob' ),
('Knope', 'John'),
('Knope', 'Mike'),
('Knope', 'Dick'),
('Pratt', 'John'),
('Pratt', 'Jill'),
('Pratt', 'James');
Declare a table variable containing the forenames you'd like to match. This acts as a parameter, so you should edit the values we insert to test the results:
DECLARE #ForenamesToSearch TABLE (Forenames VARCHAR(50));
INSERT
#ForenamesToSearch
VALUES
('John')
, ('Mike')
, ('Bob');
Finally we use GROUP BY and HAVING COUNT to ensure the number of names matches exactly.
SELECT
Surname
FROM
(SELECT DISTINCT Forenames, Surname FROM #Names) Names
INNER JOIN #ForenamesToSearch Forenames ON Names.Forenames = Forenames.Forenames
GROUP BY
Surname
HAVING
COUNT(1) = (SELECT COUNT(1) FROM #ForenamesToSearch);
Probably not the best way to do this but you can try the following for Postgresql:
select *
from
(
select
concat(',' , string_agg(name1,',') , ',') as X,
surname
from
table_name as A
group BY
surname
) As B
Where B.X like '%,John,%' And B.X like '%,Mike,%' And B.X like '%,Bob,%';
SQLFIDDLE DEMO
The following is for SQL server:
select * from
(
select
', ' + STUFF((SELECT ', ' + name1 FROM table_name WHERE surname = A.surname FOR XML PATH('')),1,2,'') + ',' as X,
surname
from
table_name as A
group BY
surname
) as B
Where B.X like '%, John,%' And B.X like '%, Mike,%' And B.X like '%, Bob,%';
SQLFIDDLE DEMO
This is for a Homework assignment, but I want to go a step farther.
Let me show my Tables then I'll ask my question.
Table -- Students
StudentID PK, LastName, FirstName,
Table -- Courses
CourseID PK, CourseName
Table -- Registrations
StudentID FK, CourseID FK
The question is How can I add more than one CourseName in that specific cell? For Example I have one student who is taking 3 classes, can I show all 3 CourseNames for that particular student in the same cell in the same row?
Example.......
123456, Smith, John, English, Math, Science
Sorry if this seems simplistic but I just can't find what I'm looking for after searching.
You don't put them into 1 cell.
It will be 3 rows. An example will make this a bit more clear:
John Smith: ID 1025
Math ID 2500
English ID 2585
Violin ID 3250
In your database you will get the following rows:
StudentID CourseID
1025 2500
1025 2585
1025 3250
Well in the spirit of Christmas you can always imagine it's a turkey and STUFF it..
DECLARE #Students TABLE(StudentID INT, LastName VARCHAR(50), FirstName VARCHAR(50))
DECLARE #Courses TABLE(CourseID INT, CourseName VARCHAR(50))
DECLARE #Registrations TABLE(StudentID INT, CourseID INT)
INSERT INTO #Students VALUES
(123456, 'John', 'Smith'),(123457, 'Adrian', 'Sullivan'),(123458, 'Dude', 'Guy')
INSERT INTO #Courses VALUES
(1,'English'),(2,'Math'),(3,'Science')
INSERT INTO #Registrations VALUES
(123456,1),(123456,2),(123456,3),(123457,1),(123457,2),(123458,3)
DECLARE #STID INT
SELECT *, STUFF((SELECT ','+C2.CourseName
FROM #Registrations R2
INNER JOIN #Courses C2 ON C2.CourseID = R2.CourseID
WHERE R2.StudentID = S.StudentID
FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 1, '') [AllText]
FROM #Students S
For more reading on STUFF
Previously, I was trying to keep ALL previous last names of an employee in a table cell with commas (see below) but I didn’t know how. Someone then suggested using normalization which I’m not sure if it’ll be easier in this situation. My boss wants to display all previous last names of an employee on a web page each time she edits her account info. Simply put, when Judy changes her last name again – her last name Kingsley should be inserted behind Smith. So, my question is back to whether or not it is possible to add multiple last names in the same cell, separated with commas as I thought it’ll be simpler when I use a variable on the web page to display all the Alias at once? Yet, I’ve no clue the complexity to write the codes for this. Any help is truly appreciated.
Current SQL table
+---------------+-----------------+----------------+--------------------+
People FirstName LastName Alias
+---------------+-----------------+----------------+--------------------+
002112 Judy Smith Hall
Preferred
+---------------+-----------------+----------------+--------------------+
People FirstName LastName Alias
+---------------+-----------------+----------------+--------------------+
002112 Judy Kingsley Hall, Smith
Keep the database normalized.
People:
(Id, Firstname, Lastname)
LastnameHistory:
(PeopleId, OldLastname, NewLastname, DateChanged)
You can the create a view which would be a "GROUP_CONCAT" type of query to transform the data as required.
An example:
DECLARE #people TABLE ( id INT IDENTITY(1,1), fname VARCHAR(50), lname VARCHAR(50))
DECLARE #lnameHistory TABLE ( id INT IDENTITY(1,1), people_id INT, lname VARCHAR(50), date_changed DATETIME)
INSERT INTO #people (fname, lname)
VALUES ('john', 'smith'), ('jane', 'doe')
INSERT INTO #lnameHistory (people_id, lname, date_changed)
VALUES (2, 'shakespeare', '2012-01-01'), (2, 'einstein', '2013-12-12')
;WITH group_concat AS
(
SELECT people_id, LEFT(lnames , LEN(lnames )-1) AS lnames
FROM #lnameHistory AS o
CROSS APPLY
(
SELECT lname + ', '
FROM #lnameHistory AS i
WHERE o.people_id = i.people_id
ORDER BY date_changed ASC
FOR XML PATH('')
) pre_trimmed (lnames)
GROUP BY people_id, lnames
)
SELECT p.*, gc.lnames FROM #people p
JOIN group_concat gc ON gc.people_id = p.id
Some reference for syntax:
SQL Server CROSS APPLY and OUTER APPLY
XML Data (SQL Server)
Assuming your update statement is a stored procedure taking in parameters of #personId and #newLastName:
EDIT
Sorry, wrong version of SQL. Have to do it the old school way!
UPDATE PeopleTable
SET Alias = Alias + ', ' + LastName,
LastName = #newLastName
WHERE
People = #personId
When you update the table for a new LastName, use something like this:
UPDATE <table> SET Alias = Alias + ', ' + LastName, LastName = <newLastName>
I have the following tables
Table A
RID | Name |Phone |Email |CreatedOn
------------------------------------------------------------
1 | John Smith | 2143556789 |t1#gmail.com |2012-09-01 09:30:00
2 | Jason K Crull | 2347896543 |t2#gmail.com |2012-08-02 10:34:00
Table B
CID| FirstName |LastName |Phone |Email |CreatedOn |Title|Address|City|State
---------------------------------------------------------------------------------------------------
11 | John | Smith |2143556789 |t1#gmail.com |2012-09-01 09:30:00|NULL|NULL|NULL|NULL
12 | Jason | K Crull |2347896543 |t2#gmail.com |2012-08-02 10:34:00|NULL|NULL|NULL|NULL
Table C
RID | CID |IsAuthor|CreatedOn
-----------------------------------------
1 | 11 | 0 |2012-09-01 09:30:00
2 | 12 | 0 |2012-08-02 10:34:00
For every row in "Table A" need to create a row in "Table B" splitting the name into First and Last Name as shown and after creating a row, insert new row into Table C with RID from Table A, CID from Table B, IsAuthor bit Default to 0 and CreatedOn from Table A.The CID is auto incremented. Can anyone help me in achieving this. I am very new to SQL. Thanks!
I believe you're looking for something like this (I left off some fields, but this should get the point across). Main thing to see is the substring and charindex functions which are used to split the name into first name and last names:
insert into tableb (firstname,lastname,phone,email)
select
left(name, charindex(' ',name)-1),
substring(name, charindex(' ', name)+1, len(name)),
phone, email
from tablea ;
insert into tablec
select a.rid, b.cid, 0, a.createdon
from tablea a
inner join tableb b on a.name = b.firstname + ' ' + b.lastname
and a.phone = b.phone and a.email = b.email ;
SQL Fiddle Demo
If there is a concern for the same names, emails, etc, then you're probably going to need to look into using a dreaded cursor and scope_identity(). Hopefully you won't have to go down that route.
Stop thinking about "for every row" and think of it as "a set." Very rarely is it efficient to process anything row-by-row in SQL Server, and very rarely is it beneficial to think in those terms.
--INSERT dbo.TableC(RID, CID, IsAuthor, CreatedOn)
SELECT a.RID, b.CID, IsAuthor = 0, a.CreatedOn
FROM dbo.TableA AS a
INNER JOIN dbo.TableB AS b
ON a.Name = b.FirstName + ' ' b.LastName;
When you believe it is returning the right results, uncomment the INSERT.
To split the name I'd use CharIndex to find the position of the space, then Substring to break the word apart.
For keeping track of which row in TableA the data in TableB came from, I'd just stick a column onto B to record this data, then drop it when you come to inset into table C.
An alternative would be to make CID an identity column on C instead of B, populate C first, then feed that data into TableB when you come to populate that.
if OBJECT_ID('TableA','U') is not null drop table TableA
create table TableA
(
rid int not null identity(1,1) primary key clustered
, Name nvarchar(64)
, Phone nvarchar(16)
, Email nvarchar(256)
, CreatedOn datetime default (getutcdate())
)
if OBJECT_ID('TableB','U') is not null drop table TableB
create table TableB
(
cid int not null identity(1,1) primary key clustered
, FirstName nvarchar(64)
, LastName nvarchar(64)
, Phone nvarchar(16)
, Email nvarchar(256)
, CreatedOn datetime default (getutcdate())
, Title nvarchar(16)
, [Address] nvarchar(256)
, City nvarchar(64)
, [State] nvarchar(64)
)
if OBJECT_ID('TableC','U') is not null drop table TableC
create table TableC
(
rid int primary key clustered
, cid int unique
, IsAuthor bit default(0)
, CreatedOn datetime default (getutcdate())
)
insert TableA (Name, Phone, Email) select 'John Smith', '2143556789', 't1#gmail.com'
insert TableA (Name, Phone, Email) select 'Jason K Crull', '2347896543', 't2#gmail.com'
alter table TableB
add TempRid int
insert TableB(FirstName, LastName, Phone, Email, TempRid)
select case when CHARINDEX(' ', Name) > 0 then SUBSTRING(Name, 1, CHARINDEX(' ', Name)-1) else Name end
, case when CHARINDEX(' ', Name) > 0 then SUBSTRING(Name, CHARINDEX(' ', Name)+1, LEN(Name)) else '' end
, Phone
, Email
, Rid
from TableA
insert TableC (rid, cid)
select TempRid, cid
from TableB
alter table TableB
drop column TempRid
select * from TableB
select * from TableC
Try it here: http://sqlfiddle.com/#!3/aaaed/1
Or the alternate method (inserting to C before B) here: http://sqlfiddle.com/#!3/99592/1
I have a large table with a column x that I want to replicate to another column y in the same table. What would be the SQL statement for this?
The 1 st column is called name and it contains first name and last name separated by a space. How to move those to new first name and last name columns?
Sometimes names have extra spaces, this script will handle those situations
create table #t(name nvarchar(100), firstname nvarchar(50), lastname nvarchar(50))
insert #t (name) values ('Thomas Clausen')
insert #t (name) values (' Bill Gates')
insert #t (name) values ('Steven Jobs ')
insert #t (name) values ('Donald of Duck')
insert #t (name) values ('microsoft')
insert #t (name) values ('')
update #t
set firstname = nullif(left(ltrim(name), charindex(' ', ltrim(name) + ' ')-1), ''),
lastname = nullif(stuff(rtrim(name), 1,len(rtrim(name))
- charindex(' ', reverse(rtrim(name))), ''), '')
Result:
FirstName LastName
Thomas Clausen
Bill Gates
Steven Jobs
Donald Duck
microsoft NULL
NULL NULL
update YourTable
set y = x
Edited:
UPDATE Table
SET y = x
Edited:
From the modification on your question I understand that you have a column 'name' with something like John Adams and want to fill two columns that already exist, FirstName and LastName. If that is the case, try this
UPDATE table
SET FirstName = PARSENAME(REPLACE(name, ' ', '.'), 2),
LastName = PARSENAME(REPLACE(name, ' ', '.'), 1)
If there's no space separating the first name and last name, no error message will be encountered and a NULL value will be returned for the FirstName while the whole full name will be returned as the LastName.
Select t1.Name,t1.Marks as Maths,t2.Marks as physics,t3.Marks as Chemistry from
(select T.Name,T.Marks,T.Subjects
from Student as T
where T.Subjects like 'Maths') as t1
inner join
(select D.Name,D.Marks,D.Subjects
from Student as D
where D.Subjects like 'Physics') as t2
on t1.Name like t2.Name
inner join
(select E.Name,E.Marks,E.Subjects
from Student as E
where E.Subjects like 'Chemistry') as t3
on t2.Name like t3.Name