Creating one new column out of two existing columns - sql

I have this table t1 with c1:old_email and c2:new_email
The goal: I want to create a new column/or query this table in a way so that I can use fields from c1 and c2 (basically merge the results from c1 and c2 into one column c3) and use it for a subquery in a where statement:
Select * from t2 where t2.email=(select c3 from t1)
name |old_email |new_email
:Johnny Go: JG#yahoo.com:
:Bertie Post: Bertie#hotmail.com: Bertie#gmail.com:

can't you join using both conditions?
select t2.* from
t2 join t1 on t2.email in (t1.old_email, t1.new_email)
or
select t2.*
from t1, t2
where t2.email = t1.old_email
or t2.email = t1.new_email

The question is a little ambiguous. I am going to infer you have a table like the one below, and you want to match either email address by joining a separate table of email addresses you have to identify matches.
ID
NAME
OLD_EMAIL
NEW_EMAIL
1
David Lin
david.lin#example.com
david#fakegoofmail.com
2
Christy Thomas
christy.thomas#example.com
christy#fakegoofmail.com
3
Erin Hill
erin.hill#example.com
erin#fakegoofmail.com
4
Noah Collins
noah.collins#example.com
noah#fakegoofmail.com
5
Andrew Salazar
andrew.salazar#example.com
andrew#fakegoofmail.com
You are going to want to put both old_email and new_email in one column. We can do this with unpivot.
select
p.*
from t1
unpivot(email for email_field in (old_email, new_email)) p;
The result would look like so.
ID
NAME
EMAIL_FIELD
EMAIL
1
David Lin
OLD_EMAIL
david.lin#example.com
1
David Lin
NEW_EMAIL
david#fakegoofmail.com
2
Christy Thomas
OLD_EMAIL
christy.thomas#example.com
2
Christy Thomas
NEW_EMAIL
christy#fakegoofmail.com
3
Erin Hill
OLD_EMAIL
erin.hill#example.com
3
Erin Hill
NEW_EMAIL
erin#fakegoofmail.com
4
Noah Collins
OLD_EMAIL
noah.collins#example.com
4
Noah Collins
NEW_EMAIL
noah#fakegoofmail.com
5
Andrew Salazar
OLD_EMAIL
andrew.salazar#example.com
5
Andrew Salazar
NEW_EMAIL
andrew#fakegoofmail.com
Now you can join your secondary table of emails to perform email matching with a query like something below.
with t1_cte as (
select
p.*
from t1
unpivot(email for email_field in (old_email, new_email)) p order by 1
)
select t1.* from t1_cte t1
inner join seperate_table_of_emails t2 -- << your secondary table
on t1.email = t2.email;

Related

Changing record values based on whether there are duplicates when two tables are combined

I know I can join Table #1 and Table #2 with a UNION and then filter out duplicate Id's using DISTINCT. However, for the duplicate contacts I'd like to change DrinkPreference to Coke/Pepsi.
Is this possible?
Starting Table #1
Id
FirstName
LastName
DrinkPreference
123
Tom
Bannon
Pepsi
124
Sarah
Smith
Pepsi
Starting Table #2
id
FirstName
LastName
DrinkPreference
125
Jim
Henry
Coke
123
Tom
Bannon
Coke
Table? #3 - combined with DrinkPreference set to Coke/Pepsi where contact exists in both tables?
Id
FirstName
LastName
DrinkPreference
125
Jim
Henry
Coke
123
Tom
Bannon
Coke/Pepsi
124
Sarah
Smith
Pepsi
You can try this one
SELECT coalesce(t1.firstname, t2.firstname) AS firstname,coalesce(t1.lastname,t2.lastname) AS lastname, CASE WHEN t1.drinkpreferences IS NULL THEN t2.drinkpreferences WHEN t2.drinkpreferences IS NULL THEN t1.drinkpreferences
ELSE t1.drinkpreferences || '/' || t2.drinkpreferences END AS drinkpreferences FROM table1 t1 FULL JOIN table2 t2 ON t1.id = t2.id
Achievable using multiple unions and joins.
select distinct FirstName, LastName, case when ct = 2 then 'Coke/Pepsi' else DrinkPreference end
from (
select FirstName, LastName, DrinkPreference, Id from table1
union all
select FirstName, LastName, DrinkPreference, Id from table2) a
left join
(
select count(1)ct, Id from
(select Id from table1
union all
select Id from table2) t1
group by Id
) b on b.Id = a.Id

How do I write a program that duplicates a row when multiple values in one column are assigned to a single value in another?

I have three tables:
table1:
MODULE
EMPLOYEE
A
Billy Bob
A
Billy Joe
B
John Doe
B
Jane Doe
C
Catey Rice
table2: Primary_Key = (MATERIAL_ID, MATERIAL_NUM)
MATERIAL_ID
MATERIAL_NUM
MODULE
11111111111
222222222222
A
11111111112
222222222223
B
11111111113
222222222224
C
and I need a query that will fill in my third table so that it looks like this:
table3: Foreign_Key = (MATERIAL_ID, MATERIAL_NUM)
MATERIAL_ID
MATERIAL_NUM
EMPLOYEE
11111111111
222222222222
Billy Bob
11111111111
222222222222
Billy Joe
11111111112
222222222223
John Doe
11111111112
222222222223
Jane Doe
11111111113
222222222224
Catey Rice
I tried this query:
INSERT INTO table3(EMPLOYEE)
SELECT t1.EMPLOYEE
FROM table1 t1
FULL OUTER JOIN table2 t2
ON t1.MODULE = t2.MODULE;
I already have MATERIAL_ID and MATERIAL_NUM filled in on table3 by inserting the data from table2. If I need to do it over with EMPLOYEE in the query I'll just empty the table and rewrite it.
The issue I am running into is this error: ORA-01400: cannot insert NULL into ("MATERIAL_ID"),
which I figure is happening because I don't have a method that duplicates the rows as multiple
names fill out the same MATERIAL_ID and MATERIAL_NUM. So I need help to create the method to
do that.
I think you want to UPDATE the employee column, not INSERT new rows:
update table3 t3
set employee = (select t1.employee
from table1 t1 join
table2 t2
on t2.module = t1.module
where t3.materialid = t2.materialid
);

SQL subquery or not?

I am trying to find a query that will select from two tables but not join those two tables as I don't want the result on one line.
Lets say I have these tables:
Persons1 Persons2
Number Name Surname Number Name Surname
----------------------- -------------------------
1 Peter Miller 1 Frank Farian
2 Hans Geige 2 Thomas Müller
And when I use this query:
SELECT
NEW.NAME,
OLD.NAME
FROM
PERSONS1 NEW,
PERSONS2 OLD
WHERE
NEW.Number = 1 AND
OLD.Number = 1
I get the following result:
Peter Frank
How do I write the query to get:
Peter
Frank
Use UNION for this:
SELECT NEW.NAME
FROM PERSONS1 NEW
WHERE NEW.Number = 1
UNION
SELECT OLD.NAME
FROM PERSONS2 OLD
WHERE OLD.Number = 1

Should I Use a Self-Join

If I have a table...
ID Name Manager
0 Joe Sue
1 Jake Tom
0 Joe Tom
2 Larry Red
2 Larry Paul
1 Jake Paul
I want the output to be....
ID Name Manager1 Manager2
0 Joe Sue Tom
1 Jake Tom Paul
2 Larry Red Paul
Thanks...
If I have understood your request properly, yes, something like would produce the results you are looking for.
SELECT
t1.Name Name,
t1.Manager Manager1,
t2.Manager Manager2
FROM
Table t1
inner join Table t2 on t1.Manager = t2.Name
Of course a foreign key back to the index column would be preferential to strong comparisons for performance.
Yeah, if your table was called 'Managers':
SELECT Mgr1.ID,Mgr1.Name,Mgr1.Manager,Mgr2.Manager
FROM Managers AS Mgr1
LEFT JOIN Managers AS Mgr2
ON Mgr1.ID=Mgr2.ID
If your keeping the tables a join would be best.
If you hate joins, you could combine the max and min managers, and even then it would work if there is always 2 managers and they can't have the same name.
The below should work if I remember how to join up 2 queries correctly. but i would advise to see if it is possible to rework your table, have a separate table linking people to each other in a manager employee relation.
SELECT DISTINCT
F.ID, F.Name, S.Manager, F.Manager
FROM
(SELECT
ID, Name, MIN(manager) manager
FROM Managers
GROUP BY ID, Name) F,
(SELECT
ID, Name, MAX(manager) manager
FROM Managers
GROUP BY ID, Name) S
WHERE
F.ID = S.ID
AND S.Manager <> F.Manager
AND F.ID < S.ID

SQL Join Ignore multiple matches (fuzzy results ok)

I don't even know what the name of my problem is called, so I'm just gonna put some sample data. I don't mind fuzzy results on this (this is the best way I can think to express it. I don't mind if I overlook some data, this is for approximated evaluation, not for detailed accounting, if that makes sense). But I do need every record in TABLE 1, and I would like to avoid the nulls case indicated below.
IS THIS POSSIBLE?
TABLE 1
acctnum sub fname lname phone
12345 1 john doe xxx-xxx-xxxx
12346 0 jane doe xxx-xxx-xxxx
12347 0 rob roy xxx-xxx-xxxx
12348 0 paul smith xxx-xxx-xxxx
TABLE 2
acctnum sub division
12345 1 EAST
12345 2 WEST
12345 3 NORTH
12346 1 TOP
12346 2 BOTTOM
12347 2 BALLOON
12348 1 NORTH
So if we do a "regular outer" join, we'd get some results like this, since the sub 0's don't match the second table:
TABLE AFTER JOIN
acctnum sub fname lname phone division
12345 1 john doe xxx-xxx-xxxx EAST
12346 0 jane doe xxx-xxx-xxxx null
12347 0 rob roy xxx-xxx-xxxx null
12348 0 paul smith xxx-xxx-xxxx null
But I would rather get
TABLE AFTER JOIN
acctnum sub fname lname phone division
12345 1 john doe xxx-xxx-xxxx EAST
12346 0 jane doe xxx-xxx-xxxx TOP
12347 0 rob roy xxx-xxx-xxxx BALLOON
12348 0 paul smith xxx-xxx-xxxx NORTH
And I'm trying to avoid:
TABLE AFTER JOIN
acctnum sub fname lname phone division
12345 1 john doe xxx-xxx-xxxx EAST
12345 1 john doe xxx-xxx-xxxx WEST
12345 1 john doe xxx-xxx-xxxx NORTH
12346 0 jane doe xxx-xxx-xxxx TOP
12346 0 jane doe xxx-xxx-xxxx BOTTOM
12347 0 rob roy xxx-xxx-xxxx BALOON
12348 0 paul smith xxx-xxx-xxxx NORTH
So I decided to go with using a union and two if conditions. I'll accept a null for conditions where the sub account is defined in table 1 but not in table 2, and for everything else, I'll just match against the min.
If I'm understanding correctly, it looks like you're trying to join on the sub column if it matches. If there's no match on sub, then you want it to select the "first" row for that acctnum. Is this correct?
If so, you'll need to left join on the full match, then perform another left join on a select statement that determines the division that corresponds to the lowest sub value for that acctnum. The row_number() function can help you with this, like this:
select
t1.acctnum,
t1.sub,
t1.fname,
t1.lname,
t1.phone,
isnull(t2_match.division, t2_first.division) as division
from table1 t1
left join table2 t2_match on t2_match.acctnum = t1.acctnum and t2_match.sub = t1.sub
left join
(
select
acctnum,
sub,
division,
row_number() over (partition by acctnum order by sub) as rownum
from table2
) t2_first on t2_first.acctnum = t1.acctnum
EDIT
If you don't care at all about which record you get back from table 2 when a matching sub doesn't exist, you could combine two different queries (one that matches the sub and one that just takes the min or max division) with a union.
select
t1.acctnum,
t1.sub,
t1.fname,
t1.lname,
t1.phone,
t2.division
from table1 t1
join table2 t2 on t2.acctnum = t1.acctnum and t2.sub = t1.sub
union
select
t1.acctnum,
t1.sub,
t1.fname,
t1.lname,
t1.phone,
min(t2.division)
from table1 t1
join table2 t2 on t2.acctnum = t1.acctnum
left join table2 t2_match on t2_match.acctnum = t1.acctnum and t2_match.sub = t1.sub
where t2_match.acctnum is null
Personally, I don't find the union syntax any more compelling and you now have to maintain the query in two places. For this reason, I'd favor the row_number() approach.
try to use
SELECT MIN(Table_1.acctnum) as acctnum , MIN(Table_1.sub) as sub,MIN( Table_1.fname) as fname, MIN(Table_1.lname) as name, MIN(Table_1.phone) as phone, MIN(Table_2.division) as division
FROM Table_1 INNER JOIN Table_2 ON Table_1.acctnum = Table_2.acctnum AND Table_1.sub = Table_2.sub
where Table_1.sub>0
group by Table_1.acctnum
union
SELECT MIN(Table_1.acctnum) as acctnum , MIN(Table_1.sub) as sub,MIN( Table_1.fname) as fname, MIN(Table_1.lname) as name, MIN(Table_1.phone) as phone, MIN(Table_2.division) as division
FROM Table_1 INNER JOIN Table_2 ON Table_1.acctnum = Table_2.acctnum
where Table_1.sub=0
group by Table_1.acctnum
this is the result
12345 1 john doe xxxxxxxxxx EAST
12346 0 jane doe xxxxxxxxxx BOTTOM
12347 0 rob roy xxxxxxxxxx BALLOON
12348 0 paul smith xxxxxxxxxx NORTH
if you change min to max TOP will be insted of BOTTOM on the second row
It may also work for you:
SELECT t1.acctnum, t1.sub, t1.fname, t1.lname, t1.phone,
ISNULL(MAX(t2.division),MAX(t3.division)) as division
FROM table_1 t1
LEFT JOIN table_2 t2 ON (t2.acctnum = t1.acctnum AND t1.sub = t2.sub)
LEFT JOIN table_2 t3 ON (t3.acctnum = t1.acctnum)
GROUP BY t1.acctnum, t1.sub, t1.fname, t1.lname, t1.phone
This will give your desired result, exactly (for the shown data):
Updated to not assume there is always a sub==1 value:
SELECT
T1.acctnum,
T1.sub,
T1.fname,
T1.lname,
T1.phone,
T2.division
FROM
TABLE_1 T1
LEFT JOIN
TABLE_2 T2 ON T1.acctnum = T2.acctnum
AND
T2.sub = (SELECT MIN(T3.sub) FROM TABLE_2 T3 WHERE T1.acctnum = T3.acctnum)
ORDER BY
T1.lname,
T1.fname,
T1.acctnum