Insert values from one table to another if certain columns are unique from different databases - sql

The setup I have is the following I have to databases A and B on the same server.
A and B have identical table names. I want to append data from tables of A to tables of B. However I want to append a certain row from A to B if and only if that row is unique on certain fields. For instance if i have table named People.
in A
People:
ID name Surname
1 Mark Anthony
2 Julius Ceasar
3 Marcus Crassus
in B
People
ID name Surname
1 Marcus Caelius
2 Julius Ceasar
3 Sevilius Casca
4 Marcus Crassus
I want to add to the People table in B database those rows of People table in A where the name and surname fields do not already exist People of B.
so the result would be
in B
People
ID name Surname
1 Marcus Caelius
2 Julius Ceasar
3 Sevilius Casca
4 Marcus Crassus
5 Mark Anthony

I think this is just an insert . . . select:
insert into b.people(name, surname)
select name, surname
from a.people a
where not exists (select 1 from b.people b where b.name = a.name and b.surname = a.surname);
This assumes that the id field is a serial/identity/auto increment column. That is a best practice anyway.
You can also write this as:
insert into b.people(name, surname)
select name, surname
from a.people a
except
select name, surname
from b.people b;

Related

Sql querying Ids of a table inner joined with a 'list' table

In Sqlite I have the following tables:
CREATE TABLE "Person" (Id INTEGER PRIMARY KEY,
"Age" INTEGER, "Email" TEXT)
CREATE TABLE "_Person_Name" (Id INTEGER PRIMARY KEY,
Owner INTEGER NOT NULL, Name TEXT,
FOREIGN KEY(Owner) REFERENCES Person(Id))
where the second table represents a list of strings for the name of a Person.
I would like to query Person.Id by matching names such that several conditions may match for in the same row or in different rows of _Person_Name.Name. For example, suppose Person.Id 1 has 2 associated rows _Person_Name.Name "John" and "Smith", both with _Person_Name.Owner=1. Then I'd like to have a query that returns exactly this Person.Id 1 based on searching for "John" and for "Smith". "John Wilson" or "Jonas Smith" should not be returned, but "John Theodore Smith" should be returned.
I tried the following:
SELECT Person.Id FROM Person
INNER JOIN _Person_Name ON Person.Id = _Person_Name.Owner
WHERE (Name LIKE 'John') AND (Name LIKE 'Smith');
But this doesn't work. It finds the person with each of the conditions separately, but the conjunction of both seems to apply to the same row only, so nothing is returned.
How can I search for both conditions such that they must both apply to the same person Id, but may match in different rows of the list table?
Edit: Here is an example of the schema with data. It's just an example, this is for an automated tool that deals with arbitrary schemas and associated 'list' tables.
Table Person
Id Age Email
==================
1 30 john#test.com
2 28 lucie#gmail.com
3 47 bob#gmail.com
Table _Person_Names
Id Name Owner (Foreign Key references Person.Id)
1 John 1
2 C. 1
3 Smith 1
4 Lucie 2
5 Smith 2
6 Bob 3
7 Smith 3
The query should return only Id 1, because only Person.Id 1 has both "John" and "Smith" in the table _Person_Names.
The problem is finding if there are 2 rows inside _Person_Names containing the values John and Smith in the column Name and having the same value in column Owner.
This has nothing to do with the table Person.
If 2 such rows can be found, then the value in column Owner is the Id in the table Person. Right?
Check this code:
SELECT Owner FROM
(SELECT pn.Owner AS Owner, pn.Name AS Name1, p.Name AS Name2
FROM _Person_Names AS pn
INNER JOIN _Person_Names AS p ON (pn.Owner = p.Owner) AND (Name1 <> Name2))
WHERE (Name1 = 'John') AND (Name2 = 'Smith')
Since the first, middle, and last names are all in the same column, you could also try modifying your WHERE clause to:
WHERE Name LIKE 'John % Smith'
Same result as forpas and Namandeep_Kaur methods just less bulky
Using an AND operator in WHERE clause is not retrieving the correct result. You should use an OR operator
Edited part starts here
select Person.ID, Dusra_table.name
from person, dusra_table
where Person.ID = Dusra_Table.Owner
and (Dusra_Table.Name = 'John'
OR Dusra_Table.Name = 'Smith'
)
and Person.ID = ANY(Select Dusra_Table.Owner from Dusra_table where Name = 'John');
Dusra_Table is _Person_Names table

SQL Insert with value from different table

I have 2 tables storing information. For example:
Table 1 contains persons:
ID NAME CITY
1 BOB 1
2 JANE 1
3 FRED 2
The CITY is a id to a different table:
ID NAME
1 Amsterdam
2 London
The problem is that i want to insert data that i receive in the format:
ID NAME CITY
1 PETER Amsterdam
2 KEES London
3 FRED London
Given that the list of Cities is complete (i never receive a city that is not in my list) how can i insert the (new/received from outside)persons into the table with the right ID for the city?
Should i replace them before I try to insert them, or is there a performance friendly (i might have to insert thousands of lines at one) way to make the SQL do this for me?
The SQL server i'm using is Microsoft SQL Server 2012
First, load the data to be inserted into a table.
Then, you can just use a join:
insert into persons(id, name, city)
select st.id, st.name, c.d
from #StagingTable st left join
cities c
on st.city = c.name;
Note: The persons.id should probably be an identity column so it wouldn't be necessary to insert it.
insert into persons (ID,NAME,CITY) //you dont need to include ID if it is auto increment
values
(1,'BOB',(select Name from city where ID=1)) //another select query is getting Name from city table
if you want to add 1000 rows at a time that'd be great if you use stored procedure like this link

SQL to list data from 2 tables joined by a foreign key

Sorry for the very simple question, I have tried researching, but the examples are with too specific to a particular person's issue or, sites only explain foreign key constraints for Creating,altering or dropping in a table.
Anyway, I have 2 tables, 1 containing 2 columns being the Unique primary key and the other post codes:
PCID postCode
1 CB1 4PY
2 CB2 9GH
3 CB23 4DG
and the second is people, 4 columns, first PK, second FK from PostCodes, then forename and surename.
PId PCID firstName lastName
1 1 Fred Bloggs
2 2 Arthur Brown
3 1 Mary Bloggs
4 4 Nigel Wilson
I just want to be able to list postcodes and the names of people who live there.
Try this:
SELECT n.firstName, n.lastName FROM Names n JOIN PostCode USING(PCID)
Name and PostCode here is the table names, change to yours.
Try this
SELECT t2.FirstName,t2.LastName , t1.PostCode
FROM postcodetablename t1
JOIN namestablename t2 on t1.PcId=t2.PcId

SQL to normalize existing (many-to-many) data

Summary:
See below for Details. I'm copying the [unanswered] many-to-many question here to the top for readability:
Given the "Input" table, what is the SQL to generate the 3rd "Output"
table (Person_plays_Instrument)?
Current input (1 table):
OriginalTable:
PersonId PersonName Instrument_1 Instrument_2 Instrument_3 MailingAddress HomePhone
--------|----------|------------|------------|------------|--------------|------------
1 Bob Violin Viola Trumpet someplace 111-111-1111
2 Suzie Cello Flute <null> otherplace 222-222-2222
3 Jim Violin <null> <null> thirdplace 333-333-3333
Desired output (3 tables):
Person:
Id Name MailingAddress HomePhone
--|------|--------------|------------
1 Bob someplace 111-111-1111
2 Suzie otherplace 222-222-2222
3 Jim thirdplace 333-333-3333
Instrument:
Id Name
--|-------
1 Violin
2 Cello
3 Viola
4 Flute
5 Trumpet
Person_plays_Instrument:
PersonId InstrumentId
--------|------------
1 1
1 3
1 5
2 2
2 4
3 1
Details:
I have a single flat SQL table which started out as a spreadsheet. I'd like to normalize it. I'll split this into 1 question for each table.
Questions 1 and 2 have been answered, but I am leaving them in in case others find them helpful.
Questions:
Question #1: [answered]
How do I generate Person table?
Answer #1:
This wonderful post gets me 2/3rds of the way there. For the one-to-many tables, I'm set. Here's the code:
[add autonumber field to OriginalTable, name it PersonId]
[create empty Person table with Id, Name, MailingAddress, HomePhone fields]
INSERT INTO Person (Id, Name, MailingAddress, HomePhone)
SELECT o.PersonID, o.PersonName, o.MailingAddress, o.HomePhone
FROM OriginalTable as o
WHERE o.PersonName Is Not Null;
Question #2: [attempted] (better version by #Branko in Accepted Answer)
How do I generate Instrument table?
Answer #2:
Again, one-to-many. At first, the multiple columns had me stumped.
The solution came in two parts:
I'd just have to repeat the INSERT command, once for each column.
Using this post and the IN operator, I can check each time to confirm I hadn't already inserted that value.
Here's the code:
[create empty Instrument table with Id[autonumber], Name fields]
INSERT INTO Instrument (Name)
SELECT Distinct o.Instrument_1
FROM OriginalTable as o
WHERE o.Instrument_1 Is Not Null
AND o.Instrument_1 Not In (SELECT Name from Instrument);
INSERT INTO Instrument (Name)
SELECT Distinct o.Instrument_2
FROM OriginalTable as o
WHERE o.Instrument_2 Is Not Null
AND o.Instrument_2 Not In (SELECT Name from Instrument);
INSERT INTO Instrument (Name)
SELECT Distinct o.Instrument_3
FROM OriginalTable as o
WHERE o.Instrument_3 Is Not Null
AND o.Instrument_3 Not In (SELECT Name from Instrument);
Question #3: [unanswered]
How do I generate Person_plays_Instrument table?
Assuming there is OriginalTable.PersonID, which you haven't shown us, but is implied by your own answer #1, the answer #3 can be expressed simply as:
INSERT INTO Person_plays_Instrument (PersonId, InstrumentId)
SELECT PersonID, Instrument.Id
FROM
OriginalTable
JOIN Instrument
ON OriginalTable.Instrument_1 = Instrument.Name
OR OriginalTable.Instrument_2 = Instrument.Name
OR OriginalTable.Instrument_3 = Instrument.Name;
BTW, there is a more concise way to express the answer #2:
INSERT INTO Instrument (Name)
SELECT *
FROM (
SELECT o.Instrument_1 I
FROM OriginalTable as o
UNION
SELECT o.Instrument_2
FROM OriginalTable as o
UNION
SELECT o.Instrument_3
FROM OriginalTable as o
) Q
WHERE I IS NOT NULL;
And here is a fully working SQL Fiddle example for MS SQL Server. Other DBMSes should behave similarly. BTW, you should tag your question appropriately to indicate your DBMS.

UPDATE query that fixes orphaned records

I have an Access database that has two tables that are related by PK/FK. Unfortunately, the database tables have allowed for duplicate/redundant records and has made the database a bit screwy. I am trying to figure out a SQL statement that will fix the problem.
To better explain the problem and goal, I have created example tables to use as reference:
alt text http://img38.imageshack.us/img38/9243/514201074110am.png
You'll notice there are two tables, a Student table and a TestScore table where StudentID is the PK/FK.
The Student table contains duplicate records for students John, Sally, Tommy, and Suzy. In other words the John's with StudentID's 1 and 5 are the same person, Sally 2 and 6 are the same person, and so on.
The TestScore table relates test scores with a student.
Ignoring how/why the Student table allowed duplicates, etc - The goal I'm trying to accomplish is to update the TestScore table so that it replaces the StudentID's that have been disabled with the corresponding enabled StudentID. So, all StudentID's = 1 (John) will be updated to 5; all StudentID's = 2 (Sally) will be updated to 6, and so on. Here's the resultant TestScore table that I'm shooting for (Notice there is no longer any reference to the disabled StudentID's 1-4):
alt text http://img163.imageshack.us/img163/1954/514201091121am.png
Can you think of a query (compatible with MS Access's JET Engine) that can accomplish this goal? Or, maybe, you can offer some tips/perspectives that will point me in the right direction.
Thanks.
The only way to do this is through a series of queries and temporary tables.
First, I would create the following Make Table query that you would use to create a mapping of the bad StudentID to correct StudentID.
Select S1.StudentId As NewStudentId, S2.StudentId As OldStudentId
Into zzStudentMap
From Student As S1
Inner Join Student As S2
On S2.Name = S1.Name
Where S1.Disabled = False
And S2.StudentId <> S1.StudentId
And S2.Disabled = True
Next, you would use that temporary table to update the TestScore table with the correct StudentID.
Update TestScore
Inner Join zzStudentMap
On zzStudentMap.OldStudentId = TestScore.StudentId
Set StudentId = zzStudentMap.NewStudentId
The most common technique to identify duplicates in a table is to group by the fields that represent duplicate records:
ID FIRST_NAME LAST_NAME
1 Brian Smith
3 George Smith
25 Brian Smith
In this case we want to remove one of the Brian Smith Records, or in your case, update the ID field so they both have the value of 25 or 1 (completely arbitrary which one to use).
SELECT min(id)
FROM example
GROUP BY first_name, last_name
Using min on ID will return:
ID FIRST_NAME LAST_NAME
1 Brian Smith
3 George Smith
If you use max you would get
ID FIRST_NAME LAST_NAME
25 Brian Smith
3 George Smith
I usually use this technique to delete the duplicates, not update them:
DELETE FROM example
WHERE ID NOT IN (SELECT MAX (ID)
FROM example
GROUP BY first_name, last_name)