Left Join with Partial match SQL Server - sql

I have 2 tables in SQL Server that I am trying to make a left join from so that all records from table1 are shown and any data from table2 is shown if it exists. They are as follows
Table1
id Customername Jobid
--------------------------------
2754444 Jones 123
2854233 Smith 234
Table2
key Location
-----------------------------
FD#2754444 London
FEC#2854233 Liverpool
I can get an inner join query to work as below - but I obviously get only matching records, (which I dont want - I want all records from table1 and any matching values from table2)
This works:
$query = "select distinct table1.id, table1.customername, table1.jobid, table2.location, table2.[key]
from table1
inner join table2
on table1.id= RIGHT([table2].[key],7)"
So changing it to a left join:
This does not work:
$query = "select distinct table1.id, table1.customername, table1.jobid, table2.location, table2.[key]
from table1
left join table2
on table1.id = RIGHT([table2].[key],7)"
It does not return any of the table2 data. Any advice on what I am doing wrong would be very welcome.
Thanks in advance.

I put together a SQL Fiddle to show that your query should work (based on a guess about datatypes). Given that you've wrapped your queries as strings, that raises the question of whether your problem is actually with SQL, or if the ODBC (or whatever) connection is actually returning a parser error rather than a result set. Have you looked at what the db is providing in return? Have you ensured that there is whitespace between each word, even for line breaks (copying your text as-is shows CRs and LFs, but check your code); otherwise, it's quite possible that you're sending SQL Server something like "SELECT * FROMTABLEWHERETHING" rather than "SELECT * FROM TABLE WHERE".

Thank you all for your input. For some reason the RIGHT was not returning anything so I managed to resolve with :
left JOIN [table2] ON [table1].id= substring([key],(CHARINDEX ('#',[key] , 1)+1),7)
Thanks for all your responses.
Jim

Related

SQL Server / MS Access help understanding WHERE CLAUSE in terms of NULLS and LEFT JOIN

I have the following example generated by MS Access for generating results base on table1 without matching table2 on the IP Address columns.
SELECT
Table1.ID, Table1.IP_Address, Table1.Field1
FROM
Table1
LEFT JOIN
Table2 ON Table1.[IP_Address] = Table2.[IP Address]
WHERE
(((Table2.[IP Address]) IS NULL));
While trying to analyze "WHERE (((Table2.[IP Address]) Is Null))" I do not understand how this makes sense, as I interpret it as only return results that are NULL for table2#IP Address. My understanding of WHERE clause is like a filter mechanism for your query and NULL is blank. Can someone help me understand this counter-intuitive statement?
First, a more intuitive way to write the query would use NOT EXISTS:
SELECT Table1.ID, Table1.IP_Address, Table1.Field1
FROM Table1
WHERE NOT EXISTS (SELECT 1
FROM Table2
WHERE Table1.[IP_Address] = Table2.[IP Address]
);
That said, the LEFT JOIN method is perfectly reasonable -- and sensible too.
LEFT JOIN keeps all the rows in the first table (Table1) and matching rows in the second. If there is no match, then the Table2 columns need to be filled with a value -- and for the non-matches, that value is NULL.
The WHERE clause is keeping only these NULL values. Voila! It keeps the rows in Table1 that have no matching value in Table2.
You already mentioned the answer:
generating results base on table1 without matching table2
You use a LEFT JOIN, so you get all the rows from the LEFT table and matching and empty (null) as unmatced rows from the RIGHT table.
The unmatched rows from the RIGHT table will have Table2.[IP Address] equal to Null (since they are unmatching).
So the condition:
WHERE Table2.[IP Address] Is Null
will do exactly what you need:
fetch only these rows from the LEFT table that do not have a match
on the RIGHT table
.

Joining SQL queries with where clause

I have 2 tables in a MYSQL database wich look like this:
Klant:
ID Naam Email Soort Status
6 test test test2
7 status test test test 20
8 soort test test test
9 soort test 2 test2 Museum
Mail:
ID Content Datum Titel
1 (lots of encoded HTML) 18-03-13 test
2 (lots of encoded HTML) 18-03-13 test2
4 (lots of encoded HTML) 18-03-13 alles weer testen
(yes, I'm still testing alot^^)
Now I have a SQL query that selects all from 'Klant' with a where clause which gets the ID from a previous page:
$strSQL = "SELECT * FROM Klant WHERE ID = '".$_GET["ID"]."' ";
What I want is to JOIN this query with the following query:
SELECT ID, Titel FROM Mail;
EDIT:
From all your answers and comments I think I begin to think my question maybe is totally wrong.. I'll explain where I need it for and I might not even need JOIN? I currently have a table wich includes the data from 'Klant' which looks like this:
The meaning is that I add another table which includes all the ID's and Title's from 'Mail'. I am sorry for the confusion I may have caused with you since I wasn't that clear with my question. I hope that this may clear up what I want and you guys can maybe tell me if I even need to JOIN this or can I do something else?
I am still a student and this is the first time I've had to use JOIN and I can't figure this out. If anyone can show me how to do this or push me in the right direction it would be great!
SELECT * FROM Klant t1
JOIN
SELECT ID, Titel FROM Mail t2
ON t1.ID = t2.ID
WHERE t1.Name = 'test'
To have the desired result do the following:
SELECT * FROM Klant t1
JOIN
SELECT ID, Titel FROM Mail t2
ON t1.ID = t2.ID
And if you want to have a specific row than just add the where clause:
WHERE t1.ID = 6
or
WHERE t1.Naam = 'test'
and so on
It is difficult to see how a JOIN is applicable in the example in your question.
A JOIN let's you pull information from more than one table based on a relationship. As far as I can see, your table's don't have any way to link a row in one with a row in the other, unless SteveP is correct and your id's provide that relationship.
For example, if your klant table had a mail_id column then you could do
SELECT *
FROM klant
JOIN mail ON klant.mail_id = mail.id
and this would return a row for every matching pair of rows in the two tables. Alternatively you could use a LEFT OUTER JOIN to pull back all rows from the table on the left of the JOIN and optionally data from a matching row on the right.
If there is nothing joining the table, you can use a CROSS JOIN which will return you a full cartesian of each row in table1 with every row in table2.
Something people often confuse with a JOIN is a UNION which allows you to write 2 SELECT statements and return the result set of both combined/joined together, but these should return the same columns in each query (e.g. selecting NULL in place of the column in a query if the query doesn't pull data for that column)
I'm guess that you want to join on the ID field which is common between the tables.
select * from Klant, Mail where Klant.ID = '".$_GET["ID"]."' and Klant.ID = Mail.ID
You can also do
select * from Klant
join Mail on Mail.ID = Klant.ID
where Klant.ID = '".$_GET["ID"]."'
You can do this directly by using the following query :
select k.ID,k.Naam, k.Email,k.Soort,k.Status, m.ID,m.Titel from Klant k, Mail m where k.ID = m.ID and k.ID = '".$_GET["ID"]."'

What's the best way to join on the same table twice?

This is a little complicated, but I have 2 tables. Let's say the structure is something like this:
*Table1*
ID
PhoneNumber1
PhoneNumber2
*Table2*
PhoneNumber
SomeOtherField
The tables can be joined based on Table1.PhoneNumber1 -> Table2.PhoneNumber, or Table1.PhoneNumber2 -> Table2.PhoneNumber.
Now, I want to get a resultset that contains PhoneNumber1, SomeOtherField that corresponds to PhoneNumber1, PhoneNumber2, and SomeOtherField that corresponds to PhoneNumber2.
I thought of 2 ways to do this - either by joining on the table twice, or by joining once with an OR in the ON clause.
Method 1:
SELECT t1.PhoneNumber1, t1.PhoneNumber2,
t2.SomeOtherFieldForPhone1, t3.someOtherFieldForPhone2
FROM Table1 t1
INNER JOIN Table2 t2
ON t2.PhoneNumber = t1.PhoneNumber1
INNER JOIN Table2 t3
ON t3.PhoneNumber = t1.PhoneNumber2
This seems to work.
Method 2:
To somehow have a query that looks a bit like this -
SELECT ...
FROM Table1
INNER JOIN Table2
ON Table1.PhoneNumber1 = Table2.PhoneNumber OR
Table1.PhoneNumber2 = Table2.PhoneNumber
I haven't gotten this to work yet and I'm not sure if there's a way to do it.
What's the best way to accomplish this? Neither way seems simple or intuitive... Is there a more straightforward way to do this? How is this requirement generally implemented?
First, I would try and refactor these tables to get away from using phone numbers as natural keys. I am not a fan of natural keys and this is a great example why. Natural keys, especially things like phone numbers, can change and frequently so. Updating your database when that change happens will be a HUGE, error-prone headache. *
Method 1 as you describe it is your best bet though. It looks a bit terse due to the naming scheme and the short aliases but... aliasing is your friend when it comes to joining the same table multiple times or using subqueries etc.
I would just clean things up a bit:
SELECT t.PhoneNumber1, t.PhoneNumber2,
t1.SomeOtherFieldForPhone1, t2.someOtherFieldForPhone2
FROM Table1 t
JOIN Table2 t1 ON t1.PhoneNumber = t.PhoneNumber1
JOIN Table2 t2 ON t2.PhoneNumber = t.PhoneNumber2
What i did:
No need to specify INNER - it's implied by the fact that you don't specify LEFT or RIGHT
Don't n-suffix your primary lookup table
N-Suffix the table aliases that you will use multiple times to make it obvious
*One way DBAs avoid the headaches of updating natural keys is to not specify primary keys and foreign key constraints which further compounds the issues with poor db design. I've actually seen this more often than not.
The first is good unless either Phone1 or (more likely) phone2 can be null. In that case you want to use a Left join instead of an inner join.
It is usually a bad sign when you have a table with two phone number fields. Usually this means your database design is flawed.
You could use UNION to combine two joins:
SELECT Table1.PhoneNumber1 as PhoneNumber, Table2.SomeOtherField as OtherField
FROM Table1
JOIN Table2
ON Table1.PhoneNumber1 = Table2.PhoneNumber
UNION
SELECT Table1.PhoneNumber2 as PhoneNumber, Table2.SomeOtherField as OtherField
FROM Table1
JOIN Table2
ON Table1.PhoneNumber2 = Table2.PhoneNumber
The first method is the proper approach and will do what you need. However, with the inner joins, you will only select rows from Table1 if both phone numbers exist in Table2. You may want to do a LEFT JOIN so that all rows from Table1 are selected. If the phone numbers don't match, then the SomeOtherFields would be null. If you want to make sure you have at least one matching phone number you could then do WHERE t2.PhoneNumber IS NOT NULL OR t3.PhoneNumber IS NOT NULL
The second method could have a problem: what happens if Table2 has both PhoneNumber1 and PhoneNumber2? Which row will be selected? Depending on your data, foreign keys, etc. this may or may not be a problem.
My problem was to display the record even if no or only one phone number exists (full address book). Therefore I used a LEFT JOIN which takes all records from the left, even if no corresponding exists on the right. For me this works in Microsoft Access SQL (they require the parenthesis!)
SELECT t.PhoneNumber1, t.PhoneNumber2, t.PhoneNumber3
t1.SomeOtherFieldForPhone1, t2.someOtherFieldForPhone2, t3.someOtherFieldForPhone3
FROM
(
(
Table1 AS t LEFT JOIN Table2 AS t3 ON t.PhoneNumber3 = t3.PhoneNumber
)
LEFT JOIN Table2 AS t2 ON t.PhoneNumber2 = t2.PhoneNumber
)
LEFT JOIN Table2 AS t1 ON t.PhoneNumber1 = t1.PhoneNumber;
SELECT
T1.ID
T1.PhoneNumber1,
T1.PhoneNumber2
T2A.SomeOtherField AS "SomeOtherField of PhoneNumber1",
T2B.SomeOtherField AS "SomeOtherField of PhoneNumber2"
FROM
Table1 T1
LEFT JOIN Table2 T2A ON T1.PhoneNumber1 = T2A.PhoneNumber
LEFT JOIN Table2 T2B ON T1.PhoneNumber2 = T2B.PhoneNumber
WHERE
T1.ID = 'FOO';
LEFT JOIN or JOIN also return same result. Tested success with PostgreSQL 13.1.1 .

have mysql select statement return fully qualified column names like table.field

is there a way to have a mysql select statement return fully qualified column names like "table.field" without using AS for every single field?
like so:
SELECT *
FROM table1
LEFT JOIN table2 on table1.f_ID = table2.ID
and the result would be:
"table1.ID", "table1.name", "table2.ID", "table2.name", ...
If you are using PHP you can use PDO to get this result.
$PDO->setAttribute(PDO::ATTR_FETCH_TABLE_NAMES, true);
See SQL Select * from multiple tables for more information.
Not really. You could write some dynamic SQL to accomplish this, but it wouldn't be simple. If you really want the dynamic SQL, let me know and I could try to whip something up.
You can write this as well:
SELECT table1.*, table2.*
FROM table1
LEFT JOIN table2 on table1.f_ID = table2.ID
No need to specify each column, if you want them all
Using fully qualified field names in the statement would yield fully qualified field names in the result set.
SELECT table1.ID, table1.name, table2.ID, table2.name
FROM table1
LEFT JOIN table2 on table1.f_ID = table2.ID
I realize that the burden you wished to get rid of is doing this manually. But if your application has any kind of knowledge about the layout of the database, it can be generated dynamically within the application.
Just my 2 cents
select table1.* , table1='<======'
table2.* , table2='<======'
from table1
left join table2 on table1.f_ID = table2.ID

Why doesn't this SQL statement work?

SELECT * FROM table1, table2
WHERE table1.user_id = table2.id
AND table1.content = news
AND table1.content_id = 1
that wont work. cant u have two "AND" in a sql statement??
//Tomek
you probably want to quote 'news' as a string...
You also probably want to use an inner join instead (much more efficient)
SELECT * FROM table1
INNER JOIN table2 ON table1.user_id = table2.id
WHERE table1.content = 'news'
AND table1.content_id = 1
news is what? Some sort of parameter? Value of the field? A word which should occur in the field? Most likely your syntax is wrong, see W3Schools WHERE and W3Schools AND/OR operators pages for more information.
let me rewrite that for you with a JOIN statement since it is not 1995 anymore, you also need quotes around news
SELECT * FROM table1 t1
inner join table2 t2 on t1.user_id = t2.id
AND t1.content = 'news'
AND t1.content_id = 1
First let's start with getting rid of that old-style join so that the join and where clauses are clearly separated to make understanding much easier.
SELECT * FROM table1 t1.
JOIN table2 t2
ON t1.user_id = t2.id
WHERE t1.content = news
AND t1.content_id = 1
Now let's discuss what the problem might be. First what error are you receiving as this could be perfectly acceptable syntax? Could the problem be that you have not noted which table news is to come from? If it is in both tables you could be getting an error there. If news is meant to be the value of the column you would want it to be 'news' instead of news. It could also simply be that no records meet your conditions.
Further it is a bad practice to ever use select * and it should never be used in a join as you are returning at least one field twice and that is wasteful of both database and network resources. Always specify only the columns you need. This wastes lots of resources every day when lazy programmers do this in every query.
What do table1 and table2 look like? Can you paste a create script?
I would STRONGLY recommend to use the proper JOIN syntax:
select * from table1
inner join table2 on table1.user_id = table2.id
......
what datatypes is "table1.content" ?
You can most definitely have a lot more than just 2 AND statements in a SQL query - any database that really support any of the SQL-xx standards will support this...
I liked cmartin's response. Also, you can use more than one AND, if needed.