MSSQL - Compound WHERE clause after INNER JOIN? - sql

I have this query:
select *
from table1 d inner join table2 s on d.SOME_ID = s.SOME_ID
where s.col1 = 'THIS' AND s.col2 = 'THAT'
Which is returning the same as this:
select *
from table1 d inner join table2 s on d.SOME_ID = s.SOME_ID
where s.col1 = 'THIS'
That is, it seems to be ignoring the second part of the WHERE.
If I run this:
select *
from table2 s
where s.col1 = 'THIS' AND s.col2 = 'THAT'
Everything works fine, and the result is filtered by both qualifications.
Am I missing something with this join thing?
EDIT:
Both tables have the 'col2', and the value is same for both (by coincidence). Interestingly, this works:
select *
from table1 d inner join table2 s on d.SOME_ID = s.SOME_ID
where s.col1 = 'THIS' AND d.col2 = 'THAT'
It returns the single row which satisfies both qualifiers. Does this help anyone figure out what is going on?
EDIT2:
This is a shot in the dark. Since both tables contain the 'col2' column, does the join discard the table2.col2 column to produce the join? So when I filter the resulting join by a qualification on a column which is not included in the new table, they all pass?

Related

I cannot get this LEFT JOIN to work (I don't understand joins)

These queries both get results:
SELECT * FROM Table1 WHERE Criteria = '5'
SELECT * FROM Table1 WHERE Criteria = '3'
This query gets results:
SELECT *
FROM Table1 p, Table2 m
WHERE p.UID = m.ID
AND Criteria = '5'
This query does not:
SELECT *
FROM Table1 p, Table2 m
WHERE p.UID = m.ID
AND Criteria = '3'
I am trying to convert these to a proper join which returns results even if there are no records in the right table.
I have tried the following
SELECT *
FROM Table1 p LEFT JOIN Table2 m ON p.UID = m.ID
WHERE p.Criteria = '3'
AND m.OtherCriteria = 'Moron'
--0 results
My limited understanding was that LEFT join is what I needed. I want data from the left table even if there is no data in the right table that matches. Since this didn't work I also tried right join, left outer join, right outer join and full join. None returned results.
What am I missing?
This is too long for a comment. Your query:
SELECT *
FROM Table1 p LEFT JOIN
Table2 m
ON p.UID = m.ID AND p.Criteria = '3';
Should be returning a row for all rows in table1. If there is no match, then the values will be NULL for table2. This is easily demonstrated: Here is a MySQL example on SQL Fiddle. Because this is standard behavior, it should work on almost any database.
Note that this query is quite different from this one:
SELECT *
FROM Table1 p LEFT JOIN
Table2 m
ON p.UID = m.ID
WHERE p.Criteria = '3';
This query returns no rows, because no rows match the WHERE clause. The filtering happens (conceptually) after the LEFT JOIN.
I changed the code in the SQL Fiddle slightly, so that query is:
select *
from (select 5 as criteria, 1 as id union all
select 6, 1 union all
select 7, 2
) table1 left join
(select 1 as id, 'x' as x
) table2
on table1.id = table2.id and criteria = 3;
As a note: you should always use explicit join syntax. Simple rule: Never use commas in the FROM clause.
If your database is returning no rows, then it is behaving in a non-standard manner or your interface has decided to filter the rows for some reason.

Returning narrowed down SELECT based on associated table

I have a join query I use to pull data from another table:
SELECT [THEME].[NAME],
[THEMETYPE].[TYPE]
FROM [THEME]
LEFT OUTER JOIN [THEMETYPE]
ON [THEME].[THEMETYPEID] = [THEMETYPE].[PK_THEMETYPE]
WHERE COALESCE([THEME].[THEMETYPEID], 'null') LIKE '%'
ORDER BY CASE
WHEN [THEMETYPE].[TYPE] IS NULL THEN 1
ELSE 0
END,
[THEMETYPE].[TYPE]
I need to add the ability to narrow it down if a 3rd tables values match up:
Where producttheme.productid = variable-paramater-here
AND producttheme.themeid = theme.pk_theme
Here is a pic of the table:
So if the 1 is chosen above, it will return all [Theme].[Name] and the associated [ThemeType].[Type] where The ThemeId is associated with ProductId = 1
Edit: to be more clear ThemeId is the Primary key in the Theme table where Theme.Name exists.
This would give you some idea, please adjust the column names accordingly:
SELECT [Theme].[Name], [ThemeType].[Type]
FROM [Theme]
Left Outer Join [ThemeType]
ON [Theme].[ThemeTypeId] = [ThemeType].[PK_ThemeType]
join ProductTheme PT
on PT.ProductID=ThemeType.ProductID
WHERE ProductTheme.ProductID = VARIABLE-PARAMATER-HERE AND ProductTheme.ThemeId = Theme.PK_Theme
ORDER BY [ThemeType].[Type]
Depending on whether or not you need the WHERE condition before you add the 3rd table, you can try one of these 2 options:
SELECT *
FROM TABLE1 T1
LEFT OUTER JOIN TABLE2 T2
ON T1.FIELDA = T2.FIELDA
INNER JOIN TABLE3 T3
ON T1.FIELDA = T3.FIELDA
WHERE T1.FIELDB = 'aaa'
AND T3.FIELDC = 12
or:
SELECT *
FROM (SELECT T1.FIELDA,
T2.FIELDB
FROM TABLE1 T1
LEFT OUTER JOIN TABLE2 T2
ON T1.FIELDA = T2.FIELDA
WHERE T1.FIELDC = 'aaa')T3
INNER JOIN TABLE3 T4
ON T3.FIELDA = T3.FIELDA
AND T4.FIELDC = 12
I hope this gives you something to work with.
If you provide some sample data, I can set up a working example.

How to simplify this query with sql joins?

my_table has 4 columns: id integer, value integer, value2 integer, name character varying
I want all the records that:
have the same value2 as a record which name is 'a_name'
have a field value inferior to the one of a record which name is 'a_name'
And I have satisfying results with the following query:
select t.id
from my_table as t
where t.value < ( select value from my_table where name = 'a_name')
and s.value2 = (select value2 from my_table where name = 'a_name');
But is it possible to simplify this query with sql joins ?
Joining on the same table is still too much intricate in my mind. And I try to understand with this example.
What I happened so far trying, is a result full of dupplicates:
select t2.id
from my_table as t
inner join my_table as t2 on t2.value2 = t.value2
where t2.value < ( select value from my_table where name = 'a_name');
I think this will solve your problem.
select t1.id
from my_table as t1
join my_table as t2
on t1.value2 = t2.value2
and t2.name = 'a_name'
and t1.value < t2.value
You should use self join instead of inner join see this
http://msdn.microsoft.com/en-us/library/ms177490%28v=sql.105%29.aspx
You can always get distinct results by calling "SELECT distinct t2.id ..."
However, that will not enhance your understanding of inner joins. If you are willing, keep reading on. Let's start by getting all records with name = 'a_name'.
SELECT a.*
FROM my_table as a
WHERE a.name = 'a.name';
A simpler way to perform your inner joins is to understand that the result for the above query is yet another table, formally known as a relation. You can think of it as joining on the same table, but an easier way to think of it is as "joining on the result of this query". Lets put this to the test.
SELECT other.id
FROM my_table as a,
INNER JOIN my_table as other ON other.value2 = a.value2
WHERE a.name = 'a_name'
AND other.value < a.value;
If the first query (all rows with name = 'a_name') has many results, you stand a good chance of the second query having duplicates, because the inner join between aliases 'a' and 'other' is a subset of their cross product.
Edits: Grammar, Clarity
please try this
select t.id
from my_table as t
inner join
(select value from my_table where name = 'a_name')t1 on t.value<t1.value
inner join
(select value2 from my_table where name = 'a_name')t2 on t.value2=t2.value2

SQL Server query - return null value if no match

I'm running into a problem that I cannot figure out for some reason. I am trying to write a query that joins two tables, in which a match may not be found in a table. Such as:
SELECT
Table1.IDField, Table2.IDField
FROM
Table1
LEFT OUTER JOIN
Table2 ON Table1.PersonID = Table2.PersonID
WHERE
(Table1.IDField = '12345')
AND (Table2.Category = 'Foo')
If there is no match in Table2, it's not returning anything. However, I need it to just return a NULL for that column if there is no match and still return the value from Table1.
I have changed up the JOIN with everything that I can think of, but to no avail.
Table2.Category can contain multiple other values, so doing a OR IS NULL type of deal won't work.
So, if there is no match for Table2.Category = 'Foo', I am still needing it to return:
Table1 | Table2
----------------
12345 | NULL
Any suggestions?
Move the condition for table2 out of your WHERE clause and into your JOIN.
SELECT
Table1.IDField, Table2.IDField
FROM
Table1
LEFT OUTER JOIN Table2
ON Table1.PersonID = Table2.PersonID
AND Table2.Category = 'Foo'
WHERE
Table1.IDField = '12345'
Try this:
LEFT OUTER JOIN
Table2 ON Table1.PesonID = Table2.PersonID
AND Table2.Category = 'Foo'
then delete the 'Foo' line from the WHERE clause
The problem isn't in the join per se, but in the requirement in the where clause that match table2. I've solved this with a where coalese(table2.category, 'Foo') = 'Foo'. That way if the table2 is null, it will still match.

Can I join to a table in ORACLE (10g) using a CASE clause in the ON statement (or even where clause as it's an inner join)

I'm trying to make the following code smaller. Is this possible?
select a.*
from table1 a
WHERE a."cola1" = 'valuea1'
UNION ALL
select a.*
from tablea1 a
inner join tablea2 b on a."cola2" = b."colb2"
WHERE a."cola1" = 'valuea2'
and b."colb3" = 'valueb3'
In effect I'm looking for records from table1 for value1 or value2, but for records matching value2 I want to apply 1 extra condition which involves a join to a 2nd table
Can this be done without a UNION clause?
A skeleton or what I'm trying to code is below....but it's not working naturally.
select a.*
from table1 a
inner join table2 b on a."cola1" = b."COLb1"
WHERE a."cola2" IN ('valuea1','valuea2')
and
CASE
WHEN a."cola2" = 'valuea2' THEN b."colb1" = 'valueb3'
ELSE 1=1
END CASE
I think CASE statements work in join conditions, but I'm not sure. But would this work for you?
select *
from table1 a
where a.cola1 = 'valuea1'
or (a.cola1 = 'valuea2'
and Exists(select 1
from table2 b
where a.cola2 = b.colb2
and b.colb3 = 'valueb3'
)
)
Edit: Wouldn't this simply work?
select a.*
from table1 a
Left Outer Join table2 b On (a.cola2 = b.colb2)
where a.cola1 = 'valuea1'
or (a.cola1 = 'valuea2' and b.colb3 = 'valueb3')
Overall you should follow Hosam's suggestion of rewriting the predicate entirely. But to explain your original problem further, the issue is that in SQL, CASE .. END is an expression and can only be used where any other expression could be used. A condition like "a=b" is two expressions connected by a logical operator. You may want to think of it as a boolean expression but that's not the way SQL views it.
You could accomplish what you want with CASE by using it as one of the two expressions in the condition, like so:
WHERE a."cola2" IN ('valuea1','valuea2')
and
b."colb1" = CASE
WHEN a."cola2" = 'valuea2' THEN 'valueb3'
ELSE b."colb1"
END CASE
(If it is possible for colb1 to include NULLs you would need to modify to handle that.)
You can achieve this by using left join and where condition
select a.*
from table1 a
left join tablea2 b on a."cola2" = b."colb2"
WHERE a."cola1" = 'valuea2'
and ( b."colb2" is null or b."colb3" = 'valueb3' )
OP: I've got a mini-workaround which goes close (This may only work given this is an inner join.)
select a.* from table1 a
inner join table2 b on a."cola1" = b."COLb1"
WHERE
(a."cola2" = 'valuea1')
OR (a."cola2" = 'valuea2' and b."colb1" = 'valueb3')
Sometimes writing code out can prompt some alternative thinking. Self-Therapy sort of. Thanks for your input.