compare strings of uneven length in TSQL - sql

I have two tables. Both of them contain (dutch) postalcodes.
Those have the format 9999AA and are stored as varchar(6).
In the left table the codes are complete
John Smith 1234AB
Drew BarryMore 3456HR
Ted Bundy 3456TX
Henrov 8995RE
My mother 8995XX
In the right table the codes can be incomplete
1234AB Normal neigbourhood
3456 Bad neighbourhood
8995R Very good neighbourhood
I need to join these tables on the postalcodes. In this example the output would have to be
John Smith Normal neighbourhood
Drew BarryMore Bad neighbourhood
Ted Bundy Bad neighbourhood
Henrov Very good neighbourhood
My mother -unknown-
So I have to join the two tables based on the length of the postal code in the right table.
Any suggestions as to how to do this? I could only come up with a CASE in the ON statement but that was not so smart ;)

If you have no "duplicates" in the second table, you could use like:
SELECT t1.*, t2.col2
FROM table1 AS t1
JOIN table2 AS t2
ON t1.postalcode LIKE t2.postalcode + '%';
However, this is not going to be efficient. Instead, an index on table2(postalcode) and a series of LEFT JOINs is probably faster:
SELECT t1.*, COALESCE(t2a.col2, t2b.col2, t2c.col2)
FROM table1 t1
LEFT JOIN table2 t2a ON t2a.postalcode = t1.postalcode
LEFT JOIN table2 t2b ON t2b.postalcode = LEFT(t1.postalcode, LEN(t1.postalcode) - 1)
LEFT JOIN table2 t2c ON t2c.postalcode = LEFT(t1.postalcode, LEN(t1.postalcode) - 2)
This can take advantage of an index on table2(postalcode). In addition, it only returns one row, even when there are multiple matches in table2, returning the best match.

Use JOIN.
Query
SELECT t1.col1 as name,
coalesce(t2.col2,'-unknown-') as col2
FROM table_1 t1
LEFT JOIN table_2 t2
ON t1.pcode LIKE t2.col1 + '%';
SQL Fiddle

You can Use LEFT(column,4)
select t1.*, t2.col2
from table1 t1 join
table2 t2
on LEFT(t1.postalcode,4)=t2.postalcode

You can use:
on '1234AB' like '1234'+'%'
on firstTable.code like secondTable.code+'%'
In you Join search condition.

Related

SQL join to return a table with multiple columns from other tables replacing its own

I am trying to write an SQL query that will return Table1, which has 10 columns. This table consists of a primary key id, 4 foreign key Id columns, and 5 other columns that I want to return but not change. The goal is to do a join to replace the foreign key Ids with their descriptions that are held in other tables.
Here is one attempt with the first FK Id:
Select * from Table1 t1
left join Table2 t2
on t1.BranchId = t2.BranchId;
This left join returns the description from table2, but does not replace it.
Here is another with the first FK Id:
Select t2.BranchName from Table1 t1
left join Table2 t2
on t1.BranchId = t2.BranchId;
This returns the name I want, but does not return table1 fully.
For the sake of an example you could pretend that OtherName3, OtherName4, OtherName5 are in tables Table3, Table4, Table5, respectively.
This may seem trivial for experienced SQL devs, but I am having a hard time figuring out the syntax.
Thanks!
I'm not sure what you mean by replace it.
I think you just need to list out all the columns you want:
Select t1.col1, t1.col2, t1.col3, . . .,
t2.name
from Table1 t1 left join
Table2 t2
on t1.BranchId = t2.BranchId;
I don't know what you mean by 'replace' but you just need to qualify what columns from which table you want. That goes for all tables you are joined to, especially if they have the same column name in multiple tables. I put junk columns in since I don't know your tables but you should get the general idea.
Select t2.BranchName, t1.BranchId, t1.Name, t1.Amount, t2.BranchLocation from Table1 t1
left join Table2 t2
on t1.BranchId = t2.BranchId;
I think this is what you are looking for:
select t1.*, t2.BranchName from Table1 t1
left join Table2 t2
on t1.BranchId = t2.BranchId;
Return Table1 fully (all columns) and only the description (BranchName) from Table2.
If using SQL Server, see all syntax options for the SELECT clause here:
https://msdn.microsoft.com/en-us/library/ms176104.aspx

Left join table on tbl1.col IN tbl2.col

Is it possible to have an "IN" statement within a left join clause?
I have two tables with two columns:
Table 1: Table 2:
Column1: Column2:
192192, 192192
119202 119202
810395 810395
975643, 975643
908574,, 908574
As you can see, tbl1.col1 has entries can have entries with commas trailing or have none at all. I need to join the two tables where column 1 contains column 2 or where they are equal. It made sense to be to join where column1 includes column 2. Maybe there's a better way to accomplish the join?
I need to join the two to access data in table 2. So the columns just need to align while allowing for a potential comma or two in column 1. Any suggestions?
If this is just some sort of one-time deal or a staging table and not your real prod table:
(this one works no matter where inteh number the commas are)
select <column list>
from table1 t1
join table2 t2 on replace(t1.col1, ',','') = t2.col2
or
select <column list>
from table1 t1
join table2 t2 on cast(t2.col2 as varchar (10)) like t1.col1+'%'
(you may or may not need the cast depending onthe data types of the tow columns, I was assuming one was varchar and the other was integer)
or
(this only works if the value will always be the same length
select <column list>
from table1 t1
join table2 t2 on left(t1.col1,6) = t2.col2
If this is a real prod table, then you could have performance issues joining on a function, so fix the data instead.
I think rtrim() is perfect for this:
SELECT *
FROM table1 t1
JOIN table2 t2 ON trim(t1.col1, ',') = t2.col2;
Also you may just want to substr function to trim the first table column and use the left outer join as:
using substr:
select t1.col1, t2.col2
from table1 t1 left join table2 t2
on substr(t1.col1, 0, length(t1.col1)-1) = t2.col2;
using replace:
select t1.col1, t2.col2
from table1 t1 left join table2 t2
on replace(t1.col1, ',' , '')= t2.col2;
Both the above queries should work in MySQL and Oracle.

Join two tables containing two foreign keys

I'm pretty amateur when it comes to writing SQL, so maybe this is an easy one for someone?
I have two tables as follows:
Table1 - DeviceName, DeviceID, AlternateID
MyPhone, 333, AAA
HerPhone, 444, CCC
Table2 - PhoneID, ProgramName
333, AngryBirds
CCC, Evernote
As you can see, Table2 uses two different PhoneID types from Table1 (DeviceID and AlternateID). I'm looking a sql statement that will result in output like:
MyPhone, AngryBirds
HerPhone, Evernote
Appreciate any assistance.
Cheers,
Mark
SELECT deviceName, programName
FROM table2 t2
JOIN table1 t1
ON(t1.DeviceID=t2.PhoneID OR t1.AlternateID=t2.PhoneID)
or (less readable but shorter)
SELECT deviceName, programName
FROM table2 t2
JOIN table1 t1
ON(t2.PhoneID IN (t1.DeviceID, t1.AlternateID))
Still, if DeviceIDs and AlternateIDs are from the same set, you should consider refactoring the database: What if a device could have multiple valid IDs, not just two?
What if both 333 and AAA are defined in Table 2? I'm going to assume you only want want one row returned per DeviceName, which means you need to join to Table 2 twice using outer joins:
select DeviceName,
t2a.ProgramName,
t2b.ProgramName as AltProgramName
from table1 t1
left outer join table2 t2a
on t1.DeviceID = t2a.PhoneID
left outer join table2 t2b
on t1.AlternateID = t2b.PhoneID
If you want to list only one ProgramName, and can establish a priority as to which to use in case both are present, you could do the following: (assuming DeviceID trumps AlternateID)
select DeviceName,
coalesce(t2a.ProgramName, t2b.ProgramName) as AltProgramName
from table1 t1
left outer join table2 t2a
on t1.DeviceID = t2a.PhoneID
left outer join table2 t2b
on t1.AlternateID = t2b.PhoneID
If you want the 1st program column to always contain a value, and only list a value in the 2nd column if both are present, then
select DeviceName,
coalesce(t2a.ProgramName, t2b.ProgramName) as ProgramName1,
case when t2a.ProgramName is not null then t2b.ProgramName end as ProgramName2
from table1 t1
left outer join table2 t2a
on t1.DeviceID = t2a.PhoneID
left outer join table2 t2b
on t1.AlternateID = t2b.PhoneID
EDIT
I assumed the query was being used for reporting purposes, in which case you most likely only want one row per device.
I just realized why the OP might want multiple rows returned per device. If the query is used to define a view for looking up devices by either name, then multiple rows are desired.
Jan's answer works perfectly for the lookup view. However, it may or may not perform well depending on the database engine's query optimizer and the size of the tables. If the tables are very large, then you are going to want an indexed lookup. The join with an OR condition may preclude an indexed lookup on some systems. An equivalent query using UNION ALL may support an indexed lookup on more systems.
select DeviceName,
ProgramName
from table1 t1
join table2 t2
on t1.DeviceID = t2.PhoneID
union all
select DeviceName,
ProgramName
from table1 t1
join table2 t2
on t1.AlternateID = t2.PhoneID

sql simple 3 table join using same table?

I have two tables:
Table 1
id, name1
Table 2
id, name2a, name2b
Table 2's column names name2a, and name2b are references to table 1's id. I need to create a query that pulls both the names out of table 1 based on the id's used in Table 2.
Therefore, if Table one contained:
1 Peter
2 Paul
And Table 2 contained:
1 1 2
2 2 2
Then a select statement should give me:
Peter Paul
Paul Paul
I've gone around the bend trying to build this SQL and the best I came up with was:
SELECT table1.name AS 'name', table1.name AS 'Other name'
FROM table1, table2
WHERE table1.id = table2.name2a
Which only gives me the name2a column correctly.
Any help appreciated! I guess I need to do a join, but I'm really struggling...
Start with your 2nd table and join TWICE to table 1 (different aliases respectively), then get the name field from each aliased Table1 entry.
select
T2.ID,
TJ1.Name1 as FirstName,
TJ2.Name1 as SecondName
from
Table2 t2
join Table1 TJ1
on t2.Name2a = TJ1.ID
join Table1 TJ2
on t2.Name2b = TJ2.ID
select foo.*, t1.x, t2.y
join t1 on t1.id = foo.a
join t1 as t2 on t2.id = foo.b
If there's a chance that col a or col b is null, use a left join.
Have you tried using an INNER JOIN?
SELECT table1.name AS 'name', table1.name AS 'Other name'
FROM table1 INNER JOIN table2 ON table1.id = table2.name2a;
Sorry if I'm no help, not that great at SQL myself hehe.
Your problem is that you need to reference table1 twice: once for the plain table1.name and again to look up what table2 is pointing at. You can join one table in multiple times if you give them aliases:
SELECT t1.name1, o.name1
FROM table1 t1
JOIN table2 t2 ON t1.id = t2.name2a
JOIN table1 o ON t2.name2b = o.id -- And JOIN back to table1 to get the name1

SQL SELECT across two tables

I am a little confused as to how to approach this SQL query.
I have two tables (equal number of records), and I would like to return a column with which is the division between the two.
In other words, here is my not-working-correctly query:
SELECT( (SELECT v FROM Table1) / (SELECT DotProduct FROM Table2) );
How would I do this? All I want it a column where each row equals the same row in Table1 divided by the same row in Table2. The resulting table should have the same number of rows, but I am getting something with a lot more rows than the original two tables.
I am at a complete loss. Any advice?
It sounds like you have some kind of key between the two tables. You need an Inner Join:
select t1.v / t2.DotProduct
from Table1 as t1
inner join Table2 as t2
on t1.ForeignKey = t2.PrimaryKey
Should work. Just make sure you watch out for division by zero errors.
You didn't specify the full table structure so I will assume a common ID column to link rows in the tables.
SELECT table1.v/table2.DotProduct
FROM Table1 INNER JOIN Table2
ON (Table1.ID=Table2.ID)
You need to do a JOIN on the tables and divide the columns you want.
SELECT (Table1.v / Table2.DotProduct) FROM Table1 JOIN Table2 ON something
You need to substitue something to tell SQL how to match up the rows:
Something like: Table1.id = Table2.id
In case your fileds are both integers you need to do this to avoid integer math:
select t1.v / (t2.DotProduct*1.00)
from Table1 as t1
inner join Table2 as t2
on t1.ForeignKey = t2.PrimaryKey
If you have multiple values in table2 relating to values in table1 you need to specify which to use -here I chose the largest one.
select t1.v / (max(t2.DotProduct)*1.00)
from Table1 as t1
inner join Table2 as t2
on t1.ForeignKey = t2.PrimaryKey
Group By t1.v