Home All Groups Group Topic Archive Search About

LEFT JOIN... WHERE vs AND ?

Author
25 Aug 2006 3:41 PM
"A_Michigan_User\
Ok... I give up... how do these 2 queries differ?

SELECT *    FROM Table1   LEFT JOIN Table2 ON (Table1Field = Table2Field)
WHERE (OtherField<>6)
SELECT *    FROM Table1   LEFT JOIN Table2 ON (Table1Field = Table2Field)
AND      (OtherField<>6)

(The "WHERE" is replaced with "AND")

Thanks

Author
25 Aug 2006 3:46 PM
Aaron Bertrand [SQL Server MVP]
The problem I have is that, because you didn't bother qualifying what table
OtherField is in, I have at least two different answers.




""A_Michigan_User"" <Michigan_RE_M***@ameritech.net> wrote in message
Show quote
news:%23CQiEzFyGHA.1252@TK2MSFTNGP04.phx.gbl...
>
> Ok... I give up... how do these 2 queries differ?
>
> SELECT *    FROM Table1   LEFT JOIN Table2 ON (Table1Field = Table2Field)
> WHERE (OtherField<>6)
> SELECT *    FROM Table1   LEFT JOIN Table2 ON (Table1Field = Table2Field)
> AND      (OtherField<>6)
>
> (The "WHERE" is replaced with "AND")
>
> Thanks
>
>
Author
25 Aug 2006 5:36 PM
"A_Michigan_User\
> The problem I have is that, because you didn't bother qualifying what
> table OtherField is in, I have at least two different answers.

I should have said... No table I have EVER made has EVER had identical field
names.
(Not sure why anyone would do that... and make this even MORE confusing.)

But I think you've found the problem.   It *DOES* matter which table
OtherField is in... even though it's only in 1 of the tables (and doesn't
really need to be qualified.)

Maybe I need to start qualifing *ALL* my fields when joining tables... even
though they only appear in 1 of the 2 tables.

More....

What I was trying to ultimately do was to list *ALL* the rows in Table1...
only EXCLUDING the ones that have a matching field in Table2.

List all the rows in Table1 ... EXCEPT where Table1.MyField=Table2.MyField

I was thinking it would be as easy as changing this... but it's not:

> SELECT *    FROM Table1   LEFT JOIN Table2 ON (Table1.MyField  =
> Table2.MyField)    SELECT *    FROM Table1   LEFT JOIN Table2 ON
> (Table1.MyField <> Table2.MyField)

If Table1 contains values like:
2
4
6
8
10

And Table2 contains values like:
1
4
6

The output should be:
2
8
10

(All rows in Table1 are listed... except the matching rows in Table2)

I want to thank everyone for the fast replies!





Show quote
> The problem I have is that, because you didn't bother qualifying what
> table OtherField is in, I have at least two different answers.


> ""A_Michigan_User"" <Michigan_RE_M***@ameritech.net> wrote in message
> news:%23CQiEzFyGHA.1252@TK2MSFTNGP04.phx.gbl...
>>
>> Ok... I give up... how do these 2 queries differ?
>>
>> SELECT *    FROM Table1   LEFT JOIN Table2 ON (Table1Field = Table2Field)
>> WHERE (OtherField<>6)
>> SELECT *    FROM Table1   LEFT JOIN Table2 ON (Table1Field = Table2Field)
>> AND      (OtherField<>6)
>>
>> (The "WHERE" is replaced with "AND")
>>
>> Thanks
>>
>>
>
>
Author
25 Aug 2006 6:10 PM
Aaron Bertrand [SQL Server MVP]
> I should have said... No table I have EVER made has EVER had identical
> field names.

Are you serious?

If you have a table called customers:

CREATE TABLE dbo.Customers
(
    CustomerID ...

Then you have a table called Orders, which contains a foreign key reference:

CREATE TABLE dbo.Orders
(
    ...,
    CustomerID ... FOREIGN KEY REFERENCES dbo.Customers(CustomerID)...

What else would you call that CustomerID column?  Please don't tell me you
would call Customers.ID instead of Customers.CustomerID.  They represent the
same entity, and should not have different names.

If you have a table of States that drive a picklist so you don't have people
typing in Gorja and Kantukkee, presumably you would have a table called
States, with a StateID column and a StateName column, perhaps.  So if you
put StateID in multiple other tables (such as customer's demographics, order
shipment address, manufacturer's routes, etc), you would make up a different
name for the column StateID for each table?

> Maybe I need to start qualifing *ALL* my fields when joining tables...
> even though they only appear in 1 of the 2 tables.

I always do.  Using aliases cuts down on carpal.  e.g.

SELECT
    t1.MyField -- never use SELECT * in production code!
FROM
    dbo.Table1 t1
    LEFT OUTER JOIN
    dbo.Table2 t2
    ON t1.MyField = t2.MyField
    WHERE t2.MyField IS NULL;

A
Author
25 Aug 2006 7:38 PM
"A_Michigan_User\
I would start all the field-names in the customer-table with the name "Cust"
.... and all the fields in the Order table with "Ord".
So the fields would be called: CustUserId and OrdUserId

I would think this would help *AVOID* all confusion between the 2.  (Fully
qualified or not... I instantly know which table the fields are in... and
what they refer to... and the
similar names tell me they joined keys.)  None of which can be done if you
call 2 (or 102) different fields... all by the same name.

Imagine 102 fields all with identical names.     It's interesting how "1
person's confusing nightmare"... is another person's "I do that to keep
things clear".

More......

> SELECT
>    t1.MyField -- never use SELECT * in production code!
> FROM
>    dbo.Table1 t1
>    LEFT OUTER JOIN
>    dbo.Table2 t2
>    ON t1.MyField = t2.MyField
>    WHERE t2.MyField IS NULL;

Your example works... then it breaks if I try to exclude a few addition
records from being listed.
>    WHERE (t2.MyField IS NULL) AND (t2.AnotherField = 34)

If AnotherField in Table2 is 34... then also avoid listing the matching
records in Table1.

I *DO* appreciate everyone's help with this.  You are a lifesaver!





Show quote
"Aaron Bertrand [SQL Server MVP]" <ten.xoc@dnartreb.noraa> wrote in message
news:%23OzQuGHyGHA.4240@TK2MSFTNGP03.phx.gbl...
>> I should have said... No table I have EVER made has EVER had identical
>> field names.
>
> Are you serious?
>
> If you have a table called customers:
>
> CREATE TABLE dbo.Customers
> (
>    CustomerID ...
>
> Then you have a table called Orders, which contains a foreign key
> reference:
>
> CREATE TABLE dbo.Orders
> (
>    ...,
>    CustomerID ... FOREIGN KEY REFERENCES dbo.Customers(CustomerID)...
>
> What else would you call that CustomerID column?  Please don't tell me you
> would call Customers.ID instead of Customers.CustomerID.  They represent
> the same entity, and should not have different names.
>
> If you have a table of States that drive a picklist so you don't have
> people typing in Gorja and Kantukkee, presumably you would have a table
> called States, with a StateID column and a StateName column, perhaps.  So
> if you put StateID in multiple other tables (such as customer's
> demographics, order shipment address, manufacturer's routes, etc), you
> would make up a different name for the column StateID for each table?
>
>> Maybe I need to start qualifing *ALL* my fields when joining tables...
>> even though they only appear in 1 of the 2 tables.
>
> I always do.  Using aliases cuts down on carpal.  e.g.
>
> SELECT
>    t1.MyField -- never use SELECT * in production code!
> FROM
>    dbo.Table1 t1
>    LEFT OUTER JOIN
>    dbo.Table2 t2
>    ON t1.MyField = t2.MyField
>    WHERE t2.MyField IS NULL;
>
> A
>
Author
25 Aug 2006 7:45 PM
Aaron Bertrand [SQL Server MVP]
>I would start all the field-names in the customer-table with the name
>"Cust" ... and all the fields in the Order table with "Ord".
> So the fields would be called: CustUserId and OrdUserId

Ugh, sorry, but that is just way too complex and verbose.  A user is a user
and has a UserID.  Their UserID is not different no matter which table it is
stored in.

> I would think this would help *AVOID* all confusion between the 2.

If you're returning a JOIN, you shouldn't need to know which table the
column is in.  You shouldn't be returning two columns in the join that
contain the same data.  And you shouldn't have to wonder whether you should
use CustUserID or OrdUserID or ChangePasswordLogUserID.  Have you ever
actually tried to write joins using your wacky column names?  Or does your
schema consist of only two or three tables, so it hasn't been a problem yet?

Anyway, do what you want.  But this kind of mentality would never last in
our shop.

> similar names tell me they joined keys.)  None of which can be done if you
> call 2 (or 102) different fields... all by the same name.

Again, why you would need to return 102 copies of the "same" column in a
query, I'd love to hear an explanation for that.  I only need to know the
CustomerID once.

A
Author
25 Aug 2006 10:31 PM
"A_Michigan_User\
"Aaron Bertrand [SQL Server MVP]" <ten.xoc@dnartreb.noraa> wrote in message
news:%23Azpj7HyGHA.540@TK2MSFTNGP03.phx.gbl...
> >I would start all the field-names in the customer-table with the name
> >"Cust" ... and all the fields in the Order table with "Ord".
>> So the fields would be called: CustUserId and OrdUserId
>
> Ugh, sorry, but that is just way too complex and verbose.

Writing OrdUserId instead UserId is *WAY* too complex and verbose?  (3 extra
letters)

(And it saves writing MyFullTableName.UserId and MyOtherFullTableName.UserId
many times over.)

Like I said: 1 person's "that makes 100% clearer" is another person's "that
makes it too complex and verbose".

I *LIKE* the fact that everyone has their own methods for "clarity"!    It's
actually very interesting and good to know "how the other guys do it".
Author
31 Aug 2006 11:23 AM
Bob Barrows [MVP]
Show quote
"A_Michigan_User" wrote:
> "Aaron Bertrand [SQL Server MVP]" <ten.xoc@dnartreb.noraa> wrote in
> message news:%23Azpj7HyGHA.540@TK2MSFTNGP03.phx.gbl...
>>> I would start all the field-names in the customer-table with the
>>> name "Cust" ... and all the fields in the Order table with "Ord".
>>> So the fields would be called: CustUserId and OrdUserId
>>
>> Ugh, sorry, but that is just way too complex and verbose.
>
> Writing OrdUserId instead UserId is *WAY* too complex and verbose? (3
> extra letters)
>
> (And it saves writing MyFullTableName.UserId and
> MyOtherFullTableName.UserId many times over.)

Which is what aliases are for ... think "t1" instead of "MyFullTableName"


--
Microsoft MVP - ASP/ASP.NET
Please reply to the newsgroup. This email account is my spam trap so I
don't check it very often. If you must reply off-line, then remove the
"NO SPAM"
Author
25 Aug 2006 7:52 PM
Tom Cooper
""A_Michigan_User"" <Michigan_RE_M***@ameritech.net> wrote in message
news:%23EJbD3HyGHA.4024@TK2MSFTNGP02.phx.gbl...

<snip>
Show quote
>> SELECT
>>    t1.MyField -- never use SELECT * in production code!
>> FROM
>>    dbo.Table1 t1
>>    LEFT OUTER JOIN
>>    dbo.Table2 t2
>>    ON t1.MyField = t2.MyField
>>    WHERE t2.MyField IS NULL;
>
> Your example works... then it breaks if I try to exclude a few addition
> records from being listed.
>>    WHERE (t2.MyField IS NULL) AND (t2.AnotherField = 34)
>
> If AnotherField in Table2 is 34... then also avoid listing the matching
> records in Table1.
>
> I *DO* appreciate everyone's help with this.  You are a lifesaver!

If you want to do that, then use:

SELECT
    t1.MyField -- never use SELECT * in production code!
FROM
    dbo.Table1 t1
    LEFT OUTER JOIN
    dbo.Table2 t2
    ON t1.MyField = t2.MyField
    AND t2.AnotherFIeld = 34
    WHERE t2.MyField IS NULL;

Tom

<snip>
Author
25 Aug 2006 10:23 PM
"A_Michigan_User\
Tom,

Here's some more info:

-- Table1 is a list of employees, colors, and whether this color can still
be voted on or not
IF(OBJECT_ID('dbo.Table1') IS NOT NULL) DROP TABLE dbo.Table1
GO
CREATE TABLE dbo.Table1
(
Table1Emp   Int  NOT NULL DEFAULT 0,
Table1Color   VarChar(22) NOT NULL DEFAULT '',
Table1Decided  SmallInt NOT NULL DEFAULT 0
)
GO

INSERT INTO Table1   VALUES(2 , 'Red'   , 0)
INSERT INTO Table1   VALUES(4 , 'Green' , 0)
INSERT INTO Table1   VALUES(6 , 'Red'   , 0)
INSERT INTO Table1   VALUES(8 , 'Blue'  , 0)
INSERT INTO Table1   VALUES(10, ''      , 0)
INSERT INTO Table1   VALUES(12, 'Purple', -1)
GO

-- Table2 is a list of employees, the color they voted for, and their
comments
IF(OBJECT_ID('dbo.Table2') IS NOT NULL) DROP TABLE dbo.Table2
GO
CREATE TABLE dbo.Table2
(
Table2Emp   Int  NOT NULL DEFAULT 0,
Table2Color   VarChar(22) NOT NULL DEFAULT '',
Table2Vote   VarChar(22) NOT NULL DEFAULT ''
)
GO

INSERT INTO Table2   VALUES(2, 'Blue' , 'Hate it' )
INSERT INTO Table2   VALUES(2, 'Red'  , 'Love it' )
INSERT INTO Table2   VALUES(4, 'Blue' , 'Too loud')
INSERT INTO Table2   VALUES(4, 'Green', 'Too dark')
GO

select * from Table1
select * from Table2

-- Show the rows in Table1 that employee #4 can still vote on (THIS CODE
DOES NOT WORK)
SELECT *,Table1Emp,Table2Emp FROM Table1
LEFT JOIN Table2 ON (Table1Emp = Table2Emp)
WHERE NOT (
(Table2Emp IS NULL) OR    -- His vote is NOT found in Table2
(Table1Emp=4) OR     -- He can't vote for colors if he was the 1 that
suggested it originally
(Table1Color='') OR     -- He can't vote on colors that are ""
(Table1Decided=0) OR    -- He can't vote on colors that have already been
decided (voting closed)
((Table1Emp=4) AND (Table2Emp=4)) -- He can't vote on colors that he's
already voted on
)


Show quote
"Tom Cooper" <tomcooper@comcast.no.spam.please.net> wrote in message
news:H-GdnfwZDeBxyXLZnZ2dnUVZ_qudnZ2d@comcast.com...
>
> ""A_Michigan_User"" <Michigan_RE_M***@ameritech.net> wrote in message
> news:%23EJbD3HyGHA.4024@TK2MSFTNGP02.phx.gbl...
>
> <snip>
>>> SELECT
>>>    t1.MyField -- never use SELECT * in production code!
>>> FROM
>>>    dbo.Table1 t1
>>>    LEFT OUTER JOIN
>>>    dbo.Table2 t2
>>>    ON t1.MyField = t2.MyField
>>>    WHERE t2.MyField IS NULL;
>>
>> Your example works... then it breaks if I try to exclude a few addition
>> records from being listed.
>>>    WHERE (t2.MyField IS NULL) AND (t2.AnotherField = 34)
>>
>> If AnotherField in Table2 is 34... then also avoid listing the matching
>> records in Table1.
>>
>> I *DO* appreciate everyone's help with this.  You are a lifesaver!
>
> If you want to do that, then use:
>
> SELECT
>    t1.MyField -- never use SELECT * in production code!
> FROM
>    dbo.Table1 t1
>    LEFT OUTER JOIN
>    dbo.Table2 t2
>    ON t1.MyField = t2.MyField
>    AND t2.AnotherFIeld = 34
>    WHERE t2.MyField IS NULL;
>
> Tom
>
> <snip>
>
Author
26 Aug 2006 12:32 AM
Tom Cooper
It would be better if you had told us what the primary keys of these tables
were.  And gave the desired result you want from your query for the sample
data you gave.  But thank you very much for including your table definitions
and sample data with actual CREATE TABLE and INSERT statements.  It makes it
much easier to test with your sample data.

I'm assuming the primary key of Table1 is Table1Emp and the primary key of
Table2 is Table2Emp, Table2Color.
I'm assuming the result you want is the colors that Emp 4 can vote for and
the rules are:
Emp 4 can't vote for a color he's already voted for, so he can't vote for
Blue or Green
Emp 4 can't vote for a color he proposed in Table1, so he can't vote for
Green (note that the data you gave seems to violate my understanding of this
rule since there is already a vote for Green, so perhaps I'm confused, but
that is the understanding I'm going with
Emp 4 can't vote for colors that are blank, so he can't vote for the color
proposed by Emp 10
Emp 4 can't vote for colors where Table1.Table1Decided is not 0, so he can't
vote for Purple,

Conclusion, the only color he can vote for is Red.
And I'm also assuming you want Red in the result only once even though two
different employees have suggested it in Table1.

I wouldn't use a LEFT JOIN at all for this, but instead a subquery that
checks to see if a vote exists for  each color by Emp 4, something like:

SELECT DISTINCT t1.Table1Color FROM Table1 t1
WHERE
-- He can't vote for colors if he was the 1 that suggested it originally
t1.Table1Emp<>4 AND
-- He can't vote on colors that are ""
t1.Table1Color<>'' AND
-- He can't vote on colors where voting closed
t1.Table1Decided=0 AND
-- He must not have already voted for this color
NOT EXISTS
  (SELECT 1 FROM Table2 t2
   WHERE t1.Table1Color = t2.Table2Color AND
   t2.Table2Emp = 4)
ORDER BY t1.Table1Color

That gives the result:

Table1Color
----------------------
Red

Tom

""A_Michigan_User"" <Michigan_RE_M***@ameritech.net> wrote in message
Show quote
news:uW7crWJyGHA.4336@TK2MSFTNGP06.phx.gbl...
> Tom,
>
> Here's some more info:
>
> -- Table1 is a list of employees, colors, and whether this color can still
> be voted on or not
> IF(OBJECT_ID('dbo.Table1') IS NOT NULL) DROP TABLE dbo.Table1
> GO
> CREATE TABLE dbo.Table1
> (
> Table1Emp   Int  NOT NULL DEFAULT 0,
> Table1Color   VarChar(22) NOT NULL DEFAULT '',
> Table1Decided  SmallInt NOT NULL DEFAULT 0
> )
> GO
>
> INSERT INTO Table1   VALUES(2 , 'Red'   , 0)
> INSERT INTO Table1   VALUES(4 , 'Green' , 0)
> INSERT INTO Table1   VALUES(6 , 'Red'   , 0)
> INSERT INTO Table1   VALUES(8 , 'Blue'  , 0)
> INSERT INTO Table1   VALUES(10, ''      , 0)
> INSERT INTO Table1   VALUES(12, 'Purple', -1)
> GO
>
> -- Table2 is a list of employees, the color they voted for, and their
> comments
> IF(OBJECT_ID('dbo.Table2') IS NOT NULL) DROP TABLE dbo.Table2
> GO
> CREATE TABLE dbo.Table2
> (
> Table2Emp   Int  NOT NULL DEFAULT 0,
> Table2Color   VarChar(22) NOT NULL DEFAULT '',
> Table2Vote   VarChar(22) NOT NULL DEFAULT ''
> )
> GO
>
> INSERT INTO Table2   VALUES(2, 'Blue' , 'Hate it' )
> INSERT INTO Table2   VALUES(2, 'Red'  , 'Love it' )
> INSERT INTO Table2   VALUES(4, 'Blue' , 'Too loud')
> INSERT INTO Table2   VALUES(4, 'Green', 'Too dark')
> GO
>
> select * from Table1
> select * from Table2
>
> -- Show the rows in Table1 that employee #4 can still vote on (THIS CODE
> DOES NOT WORK)
> SELECT *,Table1Emp,Table2Emp FROM Table1
> LEFT JOIN Table2 ON (Table1Emp = Table2Emp)
> WHERE NOT (
> (Table2Emp IS NULL) OR    -- His vote is NOT found in Table2
> (Table1Emp=4) OR     -- He can't vote for colors if he was the 1 that
> suggested it originally
> (Table1Color='') OR     -- He can't vote on colors that are ""
> (Table1Decided=0) OR    -- He can't vote on colors that have already been
> decided (voting closed)
> ((Table1Emp=4) AND (Table2Emp=4)) -- He can't vote on colors that he's
> already voted on
> )
>
>
> "Tom Cooper" <tomcooper@comcast.no.spam.please.net> wrote in message
> news:H-GdnfwZDeBxyXLZnZ2dnUVZ_qudnZ2d@comcast.com...
>>
>> ""A_Michigan_User"" <Michigan_RE_M***@ameritech.net> wrote in message
>> news:%23EJbD3HyGHA.4024@TK2MSFTNGP02.phx.gbl...
>>
>> <snip>
>>>> SELECT
>>>>    t1.MyField -- never use SELECT * in production code!
>>>> FROM
>>>>    dbo.Table1 t1
>>>>    LEFT OUTER JOIN
>>>>    dbo.Table2 t2
>>>>    ON t1.MyField = t2.MyField
>>>>    WHERE t2.MyField IS NULL;
>>>
>>> Your example works... then it breaks if I try to exclude a few addition
>>> records from being listed.
>>>>    WHERE (t2.MyField IS NULL) AND (t2.AnotherField = 34)
>>>
>>> If AnotherField in Table2 is 34... then also avoid listing the matching
>>> records in Table1.
>>>
>>> I *DO* appreciate everyone's help with this.  You are a lifesaver!
>>
>> If you want to do that, then use:
>>
>> SELECT
>>    t1.MyField -- never use SELECT * in production code!
>> FROM
>>    dbo.Table1 t1
>>    LEFT OUTER JOIN
>>    dbo.Table2 t2
>>    ON t1.MyField = t2.MyField
>>    AND t2.AnotherFIeld = 34
>>    WHERE t2.MyField IS NULL;
>>
>> Tom
>>
>> <snip>
>>
>
>
Author
26 Aug 2006 5:14 PM
"A_Michigan_User\
Tom,

Excellent.

Yes... you are right on all counts.

My "sample" had some typos/errors in it.

Table1Emp and Table2Emp are the joining keys.

I apparently didn't need a "join" at all.   (I was VERY surprised by that.
I thought that was the whole point of having linked tables!)

Your code works!

(I owe you 1, buddy.)

Thanks again.



Show quote
"Tom Cooper" <tomcooper@comcast.no.spam.please.net> wrote in message
news:jMWdnbrEGcY6C3LZnZ2dnUVZ_vydnZ2d@comcast.com...
> It would be better if you had told us what the primary keys of these
> tables were.  And gave the desired result you want from your query for the
> sample data you gave.  But thank you very much for including your table
> definitions and sample data with actual CREATE TABLE and INSERT
> statements.  It makes it much easier to test with your sample data.
>
> I'm assuming the primary key of Table1 is Table1Emp and the primary key of
> Table2 is Table2Emp, Table2Color.
> I'm assuming the result you want is the colors that Emp 4 can vote for and
> the rules are:
> Emp 4 can't vote for a color he's already voted for, so he can't vote for
> Blue or Green
> Emp 4 can't vote for a color he proposed in Table1, so he can't vote for
> Green (note that the data you gave seems to violate my understanding of
> this rule since there is already a vote for Green, so perhaps I'm
> confused, but that is the understanding I'm going with
> Emp 4 can't vote for colors that are blank, so he can't vote for the color
> proposed by Emp 10
> Emp 4 can't vote for colors where Table1.Table1Decided is not 0, so he
> can't vote for Purple,
>
> Conclusion, the only color he can vote for is Red.
> And I'm also assuming you want Red in the result only once even though two
> different employees have suggested it in Table1.
>
> I wouldn't use a LEFT JOIN at all for this, but instead a subquery that
> checks to see if a vote exists for  each color by Emp 4, something like:
>
> SELECT DISTINCT t1.Table1Color FROM Table1 t1
> WHERE
> -- He can't vote for colors if he was the 1 that suggested it originally
> t1.Table1Emp<>4 AND
> -- He can't vote on colors that are ""
> t1.Table1Color<>'' AND
> -- He can't vote on colors where voting closed
> t1.Table1Decided=0 AND
> -- He must not have already voted for this color
> NOT EXISTS
>  (SELECT 1 FROM Table2 t2
>   WHERE t1.Table1Color = t2.Table2Color AND
>   t2.Table2Emp = 4)
> ORDER BY t1.Table1Color
>
> That gives the result:
>
> Table1Color
> ----------------------
> Red
>
> Tom
>
> ""A_Michigan_User"" <Michigan_RE_M***@ameritech.net> wrote in message
> news:uW7crWJyGHA.4336@TK2MSFTNGP06.phx.gbl...
>> Tom,
>>
>> Here's some more info:
>>
>> -- Table1 is a list of employees, colors, and whether this color can
>> still be voted on or not
>> IF(OBJECT_ID('dbo.Table1') IS NOT NULL) DROP TABLE dbo.Table1
>> GO
>> CREATE TABLE dbo.Table1
>> (
>> Table1Emp   Int  NOT NULL DEFAULT 0,
>> Table1Color   VarChar(22) NOT NULL DEFAULT '',
>> Table1Decided  SmallInt NOT NULL DEFAULT 0
>> )
>> GO
>>
>> INSERT INTO Table1   VALUES(2 , 'Red'   , 0)
>> INSERT INTO Table1   VALUES(4 , 'Green' , 0)
>> INSERT INTO Table1   VALUES(6 , 'Red'   , 0)
>> INSERT INTO Table1   VALUES(8 , 'Blue'  , 0)
>> INSERT INTO Table1   VALUES(10, ''      , 0)
>> INSERT INTO Table1   VALUES(12, 'Purple', -1)
>> GO
>>
>> -- Table2 is a list of employees, the color they voted for, and their
>> comments
>> IF(OBJECT_ID('dbo.Table2') IS NOT NULL) DROP TABLE dbo.Table2
>> GO
>> CREATE TABLE dbo.Table2
>> (
>> Table2Emp   Int  NOT NULL DEFAULT 0,
>> Table2Color   VarChar(22) NOT NULL DEFAULT '',
>> Table2Vote   VarChar(22) NOT NULL DEFAULT ''
>> )
>> GO
>>
>> INSERT INTO Table2   VALUES(2, 'Blue' , 'Hate it' )
>> INSERT INTO Table2   VALUES(2, 'Red'  , 'Love it' )
>> INSERT INTO Table2   VALUES(4, 'Blue' , 'Too loud')
>> INSERT INTO Table2   VALUES(4, 'Green', 'Too dark')
>> GO
>>
>> select * from Table1
>> select * from Table2
>>
>> -- Show the rows in Table1 that employee #4 can still vote on (THIS CODE
>> DOES NOT WORK)
>> SELECT *,Table1Emp,Table2Emp FROM Table1
>> LEFT JOIN Table2 ON (Table1Emp = Table2Emp)
>> WHERE NOT (
>> (Table2Emp IS NULL) OR    -- His vote is NOT found in Table2
>> (Table1Emp=4) OR     -- He can't vote for colors if he was the 1 that
>> suggested it originally
>> (Table1Color='') OR     -- He can't vote on colors that are ""
>> (Table1Decided=0) OR    -- He can't vote on colors that have already been
>> decided (voting closed)
>> ((Table1Emp=4) AND (Table2Emp=4)) -- He can't vote on colors that he's
>> already voted on
>> )
>>
>>
>> "Tom Cooper" <tomcooper@comcast.no.spam.please.net> wrote in message
>> news:H-GdnfwZDeBxyXLZnZ2dnUVZ_qudnZ2d@comcast.com...
>>>
>>> ""A_Michigan_User"" <Michigan_RE_M***@ameritech.net> wrote in message
>>> news:%23EJbD3HyGHA.4024@TK2MSFTNGP02.phx.gbl...
>>>
>>> <snip>
>>>>> SELECT
>>>>>    t1.MyField -- never use SELECT * in production code!
>>>>> FROM
>>>>>    dbo.Table1 t1
>>>>>    LEFT OUTER JOIN
>>>>>    dbo.Table2 t2
>>>>>    ON t1.MyField = t2.MyField
>>>>>    WHERE t2.MyField IS NULL;
>>>>
>>>> Your example works... then it breaks if I try to exclude a few addition
>>>> records from being listed.
>>>>>    WHERE (t2.MyField IS NULL) AND (t2.AnotherField = 34)
>>>>
>>>> If AnotherField in Table2 is 34... then also avoid listing the matching
>>>> records in Table1.
>>>>
>>>> I *DO* appreciate everyone's help with this.  You are a lifesaver!
>>>
>>> If you want to do that, then use:
>>>
>>> SELECT
>>>    t1.MyField -- never use SELECT * in production code!
>>> FROM
>>>    dbo.Table1 t1
>>>    LEFT OUTER JOIN
>>>    dbo.Table2 t2
>>>    ON t1.MyField = t2.MyField
>>>    AND t2.AnotherFIeld = 34
>>>    WHERE t2.MyField IS NULL;
>>>
>>> Tom
>>>
>>> <snip>
>>>
>>
>>
>
>
Author
26 Aug 2006 7:17 PM
Tom Cooper
""A_Michigan_User"" <Michigan_RE_M***@ameritech.net> wrote in message
Show quote
news:OPYuPLTyGHA.4176@TK2MSFTNGP06.phx.gbl...
> Tom,
>
> Excellent.
>
> Yes... you are right on all counts.
>
> My "sample" had some typos/errors in it.
>
> Table1Emp and Table2Emp are the joining keys.
>
> I apparently didn't need a "join" at all.   (I was VERY surprised by that.
> I thought that was the whole point of having linked tables!)
>
> Your code works!
>
> (I owe you 1, buddy.)
>
> Thanks again.
>
>
>
> "Tom Cooper" <tomcooper@comcast.no.spam.please.net> wrote in message
> news:jMWdnbrEGcY6C3LZnZ2dnUVZ_vydnZ2d@comcast.com...
>> It would be better if you had told us what the primary keys of these
>> tables were.  And gave the desired result you want from your query for
>> the sample data you gave.  But thank you very much for including your
>> table definitions and sample data with actual CREATE TABLE and INSERT
>> statements.  It makes it much easier to test with your sample data.
>>
>> I'm assuming the primary key of Table1 is Table1Emp and the primary key
>> of Table2 is Table2Emp, Table2Color.
>> I'm assuming the result you want is the colors that Emp 4 can vote for
>> and the rules are:
>> Emp 4 can't vote for a color he's already voted for, so he can't vote for
>> Blue or Green
>> Emp 4 can't vote for a color he proposed in Table1, so he can't vote for
>> Green (note that the data you gave seems to violate my understanding of
>> this rule since there is already a vote for Green, so perhaps I'm
>> confused, but that is the understanding I'm going with
>> Emp 4 can't vote for colors that are blank, so he can't vote for the
>> color proposed by Emp 10
>> Emp 4 can't vote for colors where Table1.Table1Decided is not 0, so he
>> can't vote for Purple,
>>
>> Conclusion, the only color he can vote for is Red.
>> And I'm also assuming you want Red in the result only once even though
>> two different employees have suggested it in Table1.
>>
>> I wouldn't use a LEFT JOIN at all for this, but instead a subquery that
>> checks to see if a vote exists for  each color by Emp 4, something like:
>>
>> SELECT DISTINCT t1.Table1Color FROM Table1 t1
>> WHERE
>> -- He can't vote for colors if he was the 1 that suggested it originally
>> t1.Table1Emp<>4 AND
>> -- He can't vote on colors that are ""
>> t1.Table1Color<>'' AND
>> -- He can't vote on colors where voting closed
>> t1.Table1Decided=0 AND
>> -- He must not have already voted for this color
>> NOT EXISTS
>>  (SELECT 1 FROM Table2 t2
>>   WHERE t1.Table1Color = t2.Table2Color AND
>>   t2.Table2Emp = 4)
>> ORDER BY t1.Table1Color
>>
>> That gives the result:
>>
>> Table1Color
>> ----------------------
>> Red
>>
>> Tom
>>
>> ""A_Michigan_User"" <Michigan_RE_M***@ameritech.net> wrote in message
>> news:uW7crWJyGHA.4336@TK2MSFTNGP06.phx.gbl...
>>> Tom,
>>>
>>> Here's some more info:
>>>
>>> -- Table1 is a list of employees, colors, and whether this color can
>>> still be voted on or not
>>> IF(OBJECT_ID('dbo.Table1') IS NOT NULL) DROP TABLE dbo.Table1
>>> GO
>>> CREATE TABLE dbo.Table1
>>> (
>>> Table1Emp   Int  NOT NULL DEFAULT 0,
>>> Table1Color   VarChar(22) NOT NULL DEFAULT '',
>>> Table1Decided  SmallInt NOT NULL DEFAULT 0
>>> )
>>> GO
>>>
>>> INSERT INTO Table1   VALUES(2 , 'Red'   , 0)
>>> INSERT INTO Table1   VALUES(4 , 'Green' , 0)
>>> INSERT INTO Table1   VALUES(6 , 'Red'   , 0)
>>> INSERT INTO Table1   VALUES(8 , 'Blue'  , 0)
>>> INSERT INTO Table1   VALUES(10, ''      , 0)
>>> INSERT INTO Table1   VALUES(12, 'Purple', -1)
>>> GO
>>>
>>> -- Table2 is a list of employees, the color they voted for, and their
>>> comments
>>> IF(OBJECT_ID('dbo.Table2') IS NOT NULL) DROP TABLE dbo.Table2
>>> GO
>>> CREATE TABLE dbo.Table2
>>> (
>>> Table2Emp   Int  NOT NULL DEFAULT 0,
>>> Table2Color   VarChar(22) NOT NULL DEFAULT '',
>>> Table2Vote   VarChar(22) NOT NULL DEFAULT ''
>>> )
>>> GO
>>>
>>> INSERT INTO Table2   VALUES(2, 'Blue' , 'Hate it' )
>>> INSERT INTO Table2   VALUES(2, 'Red'  , 'Love it' )
>>> INSERT INTO Table2   VALUES(4, 'Blue' , 'Too loud')
>>> INSERT INTO Table2   VALUES(4, 'Green', 'Too dark')
>>> GO
>>>
>>> select * from Table1
>>> select * from Table2
>>>
>>> -- Show the rows in Table1 that employee #4 can still vote on (THIS CODE
>>> DOES NOT WORK)
>>> SELECT *,Table1Emp,Table2Emp FROM Table1
>>> LEFT JOIN Table2 ON (Table1Emp = Table2Emp)
>>> WHERE NOT (
>>> (Table2Emp IS NULL) OR    -- His vote is NOT found in Table2
>>> (Table1Emp=4) OR     -- He can't vote for colors if he was the 1 that
>>> suggested it originally
>>> (Table1Color='') OR     -- He can't vote on colors that are ""
>>> (Table1Decided=0) OR    -- He can't vote on colors that have already
>>> been decided (voting closed)
>>> ((Table1Emp=4) AND (Table2Emp=4)) -- He can't vote on colors that he's
>>> already voted on
>>> )
>>>
>>>
>>> "Tom Cooper" <tomcooper@comcast.no.spam.please.net> wrote in message
>>> news:H-GdnfwZDeBxyXLZnZ2dnUVZ_qudnZ2d@comcast.com...
>>>>
>>>> ""A_Michigan_User"" <Michigan_RE_M***@ameritech.net> wrote in message
>>>> news:%23EJbD3HyGHA.4024@TK2MSFTNGP02.phx.gbl...
>>>>
>>>> <snip>
>>>>>> SELECT
>>>>>>    t1.MyField -- never use SELECT * in production code!
>>>>>> FROM
>>>>>>    dbo.Table1 t1
>>>>>>    LEFT OUTER JOIN
>>>>>>    dbo.Table2 t2
>>>>>>    ON t1.MyField = t2.MyField
>>>>>>    WHERE t2.MyField IS NULL;
>>>>>
>>>>> Your example works... then it breaks if I try to exclude a few
>>>>> addition records from being listed.
>>>>>>    WHERE (t2.MyField IS NULL) AND (t2.AnotherField = 34)
>>>>>
>>>>> If AnotherField in Table2 is 34... then also avoid listing the
>>>>> matching records in Table1.
>>>>>
>>>>> I *DO* appreciate everyone's help with this.  You are a lifesaver!
>>>>
>>>> If you want to do that, then use:
>>>>
>>>> SELECT
>>>>    t1.MyField -- never use SELECT * in production code!
>>>> FROM
>>>>    dbo.Table1 t1
>>>>    LEFT OUTER JOIN
>>>>    dbo.Table2 t2
>>>>    ON t1.MyField = t2.MyField
>>>>    AND t2.AnotherFIeld = 34
>>>>    WHERE t2.MyField IS NULL;
>>>>
>>>> Tom
>>>>
>>>> <snip>
>>>>
>>>
>>>
>>
>>
>
>
Author
26 Aug 2006 7:30 PM
Tom Cooper
Sorry, I clicked the wrong button and sent a blank message.

But I just wanted to say that I'm glad I could be of help and you don't owe
me one.  For every answer I given on this newsgroup, I've recieved 10 in
return, either answers to my own questions or reading answers to other
people's questions or reading corrections or improvements on answers I have
provided.

If you arre interested in SQL Server, come back to this newsgroup often,
reading other people's questions and answers will help you with both
avoiding "reinventing the wheel"  and avoiding problems before they happen
to you.  It won't be long before you will be reading questions and realize
"I know the answer to that" and providing answers yourself.

Good luck,

Tom

Show quote
"Tom Cooper" <tomcooper@comcast.no.spam.please.net> wrote in message
news:T-Odnbys6IyqA23ZnZ2dnUVZ_tydnZ2d@comcast.com...
>
> ""A_Michigan_User"" <Michigan_RE_M***@ameritech.net> wrote in message
> news:OPYuPLTyGHA.4176@TK2MSFTNGP06.phx.gbl...
>> Tom,
>>
>> Excellent.
>>
>> Yes... you are right on all counts.
>>
>> My "sample" had some typos/errors in it.
>>
>> Table1Emp and Table2Emp are the joining keys.
>>
>> I apparently didn't need a "join" at all.   (I was VERY surprised by
>> that. I thought that was the whole point of having linked tables!)
>>
>> Your code works!
>>
>> (I owe you 1, buddy.)
>>
>> Thanks again.
>>
>>
>>
>> "Tom Cooper" <tomcooper@comcast.no.spam.please.net> wrote in message
>> news:jMWdnbrEGcY6C3LZnZ2dnUVZ_vydnZ2d@comcast.com...
>>> It would be better if you had told us what the primary keys of these
>>> tables were.  And gave the desired result you want from your query for
>>> the sample data you gave.  But thank you very much for including your
>>> table definitions and sample data with actual CREATE TABLE and INSERT
>>> statements.  It makes it much easier to test with your sample data.
>>>
>>> I'm assuming the primary key of Table1 is Table1Emp and the primary key
>>> of Table2 is Table2Emp, Table2Color.
>>> I'm assuming the result you want is the colors that Emp 4 can vote for
>>> and the rules are:
>>> Emp 4 can't vote for a color he's already voted for, so he can't vote
>>> for Blue or Green
>>> Emp 4 can't vote for a color he proposed in Table1, so he can't vote for
>>> Green (note that the data you gave seems to violate my understanding of
>>> this rule since there is already a vote for Green, so perhaps I'm
>>> confused, but that is the understanding I'm going with
>>> Emp 4 can't vote for colors that are blank, so he can't vote for the
>>> color proposed by Emp 10
>>> Emp 4 can't vote for colors where Table1.Table1Decided is not 0, so he
>>> can't vote for Purple,
>>>
>>> Conclusion, the only color he can vote for is Red.
>>> And I'm also assuming you want Red in the result only once even though
>>> two different employees have suggested it in Table1.
>>>
>>> I wouldn't use a LEFT JOIN at all for this, but instead a subquery that
>>> checks to see if a vote exists for  each color by Emp 4, something like:
>>>
>>> SELECT DISTINCT t1.Table1Color FROM Table1 t1
>>> WHERE
>>> -- He can't vote for colors if he was the 1 that suggested it originally
>>> t1.Table1Emp<>4 AND
>>> -- He can't vote on colors that are ""
>>> t1.Table1Color<>'' AND
>>> -- He can't vote on colors where voting closed
>>> t1.Table1Decided=0 AND
>>> -- He must not have already voted for this color
>>> NOT EXISTS
>>>  (SELECT 1 FROM Table2 t2
>>>   WHERE t1.Table1Color = t2.Table2Color AND
>>>   t2.Table2Emp = 4)
>>> ORDER BY t1.Table1Color
>>>
>>> That gives the result:
>>>
>>> Table1Color
>>> ----------------------
>>> Red
>>>
>>> Tom
>>>
>>> ""A_Michigan_User"" <Michigan_RE_M***@ameritech.net> wrote in message
>>> news:uW7crWJyGHA.4336@TK2MSFTNGP06.phx.gbl...
>>>> Tom,
>>>>
>>>> Here's some more info:
>>>>
>>>> -- Table1 is a list of employees, colors, and whether this color can
>>>> still be voted on or not
>>>> IF(OBJECT_ID('dbo.Table1') IS NOT NULL) DROP TABLE dbo.Table1
>>>> GO
>>>> CREATE TABLE dbo.Table1
>>>> (
>>>> Table1Emp   Int  NOT NULL DEFAULT 0,
>>>> Table1Color   VarChar(22) NOT NULL DEFAULT '',
>>>> Table1Decided  SmallInt NOT NULL DEFAULT 0
>>>> )
>>>> GO
>>>>
>>>> INSERT INTO Table1   VALUES(2 , 'Red'   , 0)
>>>> INSERT INTO Table1   VALUES(4 , 'Green' , 0)
>>>> INSERT INTO Table1   VALUES(6 , 'Red'   , 0)
>>>> INSERT INTO Table1   VALUES(8 , 'Blue'  , 0)
>>>> INSERT INTO Table1   VALUES(10, ''      , 0)
>>>> INSERT INTO Table1   VALUES(12, 'Purple', -1)
>>>> GO
>>>>
>>>> -- Table2 is a list of employees, the color they voted for, and their
>>>> comments
>>>> IF(OBJECT_ID('dbo.Table2') IS NOT NULL) DROP TABLE dbo.Table2
>>>> GO
>>>> CREATE TABLE dbo.Table2
>>>> (
>>>> Table2Emp   Int  NOT NULL DEFAULT 0,
>>>> Table2Color   VarChar(22) NOT NULL DEFAULT '',
>>>> Table2Vote   VarChar(22) NOT NULL DEFAULT ''
>>>> )
>>>> GO
>>>>
>>>> INSERT INTO Table2   VALUES(2, 'Blue' , 'Hate it' )
>>>> INSERT INTO Table2   VALUES(2, 'Red'  , 'Love it' )
>>>> INSERT INTO Table2   VALUES(4, 'Blue' , 'Too loud')
>>>> INSERT INTO Table2   VALUES(4, 'Green', 'Too dark')
>>>> GO
>>>>
>>>> select * from Table1
>>>> select * from Table2
>>>>
>>>> -- Show the rows in Table1 that employee #4 can still vote on (THIS
>>>> CODE DOES NOT WORK)
>>>> SELECT *,Table1Emp,Table2Emp FROM Table1
>>>> LEFT JOIN Table2 ON (Table1Emp = Table2Emp)
>>>> WHERE NOT (
>>>> (Table2Emp IS NULL) OR    -- His vote is NOT found in Table2
>>>> (Table1Emp=4) OR     -- He can't vote for colors if he was the 1 that
>>>> suggested it originally
>>>> (Table1Color='') OR     -- He can't vote on colors that are ""
>>>> (Table1Decided=0) OR    -- He can't vote on colors that have already
>>>> been decided (voting closed)
>>>> ((Table1Emp=4) AND (Table2Emp=4)) -- He can't vote on colors that he's
>>>> already voted on
>>>> )
>>>>
>>>>
>>>> "Tom Cooper" <tomcooper@comcast.no.spam.please.net> wrote in message
>>>> news:H-GdnfwZDeBxyXLZnZ2dnUVZ_qudnZ2d@comcast.com...
>>>>>
>>>>> ""A_Michigan_User"" <Michigan_RE_M***@ameritech.net> wrote in message
>>>>> news:%23EJbD3HyGHA.4024@TK2MSFTNGP02.phx.gbl...
>>>>>
>>>>> <snip>
>>>>>>> SELECT
>>>>>>>    t1.MyField -- never use SELECT * in production code!
>>>>>>> FROM
>>>>>>>    dbo.Table1 t1
>>>>>>>    LEFT OUTER JOIN
>>>>>>>    dbo.Table2 t2
>>>>>>>    ON t1.MyField = t2.MyField
>>>>>>>    WHERE t2.MyField IS NULL;
>>>>>>
>>>>>> Your example works... then it breaks if I try to exclude a few
>>>>>> addition records from being listed.
>>>>>>>    WHERE (t2.MyField IS NULL) AND (t2.AnotherField = 34)
>>>>>>
>>>>>> If AnotherField in Table2 is 34... then also avoid listing the
>>>>>> matching records in Table1.
>>>>>>
>>>>>> I *DO* appreciate everyone's help with this.  You are a lifesaver!
>>>>>
>>>>> If you want to do that, then use:
>>>>>
>>>>> SELECT
>>>>>    t1.MyField -- never use SELECT * in production code!
>>>>> FROM
>>>>>    dbo.Table1 t1
>>>>>    LEFT OUTER JOIN
>>>>>    dbo.Table2 t2
>>>>>    ON t1.MyField = t2.MyField
>>>>>    AND t2.AnotherFIeld = 34
>>>>>    WHERE t2.MyField IS NULL;
>>>>>
>>>>> Tom
>>>>>
>>>>> <snip>
>>>>>
>>>>
>>>>
>>>
>>>
>>
>>
>
>
Author
25 Aug 2006 10:24 PM
Mike C#
Agree with Aaron.  You can tell the difference between Customer.CustomerID
and Orders.CustomerID by qualifying them.  Ditto for the other 102 columns
(if you have two tables with 102 identical columns, you might consider
combining them into one table).  If all that extra typing of table names
gets on your nerves (it does get on my nerves), alias your tables and use
the alias to qualify the columns in queries.

""A_Michigan_User"" <Michigan_RE_M***@ameritech.net> wrote in message
Show quote
news:%23EJbD3HyGHA.4024@TK2MSFTNGP02.phx.gbl...
>I would start all the field-names in the customer-table with the name
>"Cust" ... and all the fields in the Order table with "Ord".
> So the fields would be called: CustUserId and OrdUserId
>
> I would think this would help *AVOID* all confusion between the 2.  (Fully
> qualified or not... I instantly know which table the fields are in... and
> what they refer to... and the
> similar names tell me they joined keys.)  None of which can be done if you
> call 2 (or 102) different fields... all by the same name.
>
> Imagine 102 fields all with identical names.     It's interesting how "1
> person's confusing nightmare"... is another person's "I do that to keep
> things clear".
>
> More......
>
>> SELECT
>>    t1.MyField -- never use SELECT * in production code!
>> FROM
>>    dbo.Table1 t1
>>    LEFT OUTER JOIN
>>    dbo.Table2 t2
>>    ON t1.MyField = t2.MyField
>>    WHERE t2.MyField IS NULL;
>
> Your example works... then it breaks if I try to exclude a few addition
> records from being listed.
>>    WHERE (t2.MyField IS NULL) AND (t2.AnotherField = 34)
>
> If AnotherField in Table2 is 34... then also avoid listing the matching
> records in Table1.
>
> I *DO* appreciate everyone's help with this.  You are a lifesaver!
>
>
>
>
>
> "Aaron Bertrand [SQL Server MVP]" <ten.xoc@dnartreb.noraa> wrote in
> message news:%23OzQuGHyGHA.4240@TK2MSFTNGP03.phx.gbl...
>>> I should have said... No table I have EVER made has EVER had identical
>>> field names.
>>
>> Are you serious?
>>
>> If you have a table called customers:
>>
>> CREATE TABLE dbo.Customers
>> (
>>    CustomerID ...
>>
>> Then you have a table called Orders, which contains a foreign key
>> reference:
>>
>> CREATE TABLE dbo.Orders
>> (
>>    ...,
>>    CustomerID ... FOREIGN KEY REFERENCES dbo.Customers(CustomerID)...
>>
>> What else would you call that CustomerID column?  Please don't tell me
>> you would call Customers.ID instead of Customers.CustomerID.  They
>> represent the same entity, and should not have different names.
>>
>> If you have a table of States that drive a picklist so you don't have
>> people typing in Gorja and Kantukkee, presumably you would have a table
>> called States, with a StateID column and a StateName column, perhaps.  So
>> if you put StateID in multiple other tables (such as customer's
>> demographics, order shipment address, manufacturer's routes, etc), you
>> would make up a different name for the column StateID for each table?
>>
>>> Maybe I need to start qualifing *ALL* my fields when joining tables...
>>> even though they only appear in 1 of the 2 tables.
>>
>> I always do.  Using aliases cuts down on carpal.  e.g.
>>
>> SELECT
>>    t1.MyField -- never use SELECT * in production code!
>> FROM
>>    dbo.Table1 t1
>>    LEFT OUTER JOIN
>>    dbo.Table2 t2
>>    ON t1.MyField = t2.MyField
>>    WHERE t2.MyField IS NULL;
>>
>> A
>>
>
>
Author
25 Aug 2006 7:05 PM
Tom Cooper
Yes, qualifying all references to columns is a good practice.  (Although, I
will admit that when I write a query that has no joins at all, I often
don't, but I approve of anyone who does.)  But if I have more than one table
in the query I believe you should qualify all columns.  If nothing else, it
allows anyone who is looking at your query and isn't completely familiar
with your database to know where each column came from.

Also, you should use an alias for each table in your query.  It makes it
easier to read and saves you from typing the whoe table name over and over
again.

Finding rows in one table which don't have matches in another table is easy.

Suppose you have a Customers table declared as
Create Table Customers (CustomerID int Primary Key, State char(2) Not Null)
and an Orders table declared as
Create Table Orders (OrderID int Primary Key, CustomerID int Not Null,
OrderDate datetime Not Null)
with, of course, a foreign key between the tables on CustomerID.

BTW, many database designers will do what I did  above, call the same
attribute the same name in every table where it exists.  I think it's less
confusing than calling one CustomerID and one something like
OrderCustomerID.  But to each his own, just make sure your site has a
standard on this and that the standard is followed by everybody.

So, now the query to find all customers who have no orders would be:

Select c.CustomerID
From Customers c
Left Join Orders o On c.CustomerID = o.CustomerID
Where o.CustomerID Is Null

(The reason I use o.OrderID Is Null is OrderID is in the primary key of the
Orders table, so I know that if this was a real row from Orders, OrderID
can't be Null.  So, if it is Null, this is a row from Customers which had no
match in Orders.)

And, to go back to a form of your original question, why would you put
additional tests in the On clause and why would you put it in the Where
clause, that depends on what kind of result you are looking for (and, almost
always, which table the additional test is to be done on).

For example, to find all customers who have no orders since Jan 1, 2006, you
could use:

Select c.CustomerID
From Customers c
Left Join Orders o On c.CustomerID = o.CustomerID
  And o.OrderDate >= '20060101'
Where o.OrderID Is Null

But to find customers from New York who have no orders, you would use

Select c.CustomerID
From Customers c
Left Join Orders o On c.CustomerID = o.CustomerID
Where o.OrderID Is Null
  And c.State = 'NY'

Finally, to find customers from New York who had no orders since Jan 1,
2006, you could use:

Select c.CustomerID
From Customers c
Left Join Orders o On c.CustomerID = o.CustomerID
  And o.OrderDate >= '20060101'
Where o.OrderID Is Null
  And c.State = 'NY'

Tom

""A_Michigan_User"" <Michigan_RE_M***@ameritech.net> wrote in message
Show quote
news:uW%23eOzGyGHA.4204@TK2MSFTNGP04.phx.gbl...
>> The problem I have is that, because you didn't bother qualifying what
>> table OtherField is in, I have at least two different answers.
>
> I should have said... No table I have EVER made has EVER had identical
> field names.
> (Not sure why anyone would do that... and make this even MORE confusing.)
>
> But I think you've found the problem.   It *DOES* matter which table
> OtherField is in... even though it's only in 1 of the tables (and doesn't
> really need to be qualified.)
>
> Maybe I need to start qualifing *ALL* my fields when joining tables...
> even though they only appear in 1 of the 2 tables.
>
> More....
>
> What I was trying to ultimately do was to list *ALL* the rows in Table1...
> only EXCLUDING the ones that have a matching field in Table2.
>
> List all the rows in Table1 ... EXCEPT where Table1.MyField=Table2.MyField
>
> I was thinking it would be as easy as changing this... but it's not:
>
>> SELECT *    FROM Table1   LEFT JOIN Table2 ON (Table1.MyField  =
>> Table2.MyField)    SELECT *    FROM Table1   LEFT JOIN Table2 ON
>> (Table1.MyField <> Table2.MyField)
>
> If Table1 contains values like:
> 2
> 4
> 6
> 8
> 10
>
> And Table2 contains values like:
> 1
> 4
> 6
>
> The output should be:
> 2
> 8
> 10
>
> (All rows in Table1 are listed... except the matching rows in Table2)
>
> I want to thank everyone for the fast replies!
>
>
>
>
>
>> The problem I have is that, because you didn't bother qualifying what
>> table OtherField is in, I have at least two different answers.
>
>
>> ""A_Michigan_User"" <Michigan_RE_M***@ameritech.net> wrote in message
>> news:%23CQiEzFyGHA.1252@TK2MSFTNGP04.phx.gbl...
>>>
>>> Ok... I give up... how do these 2 queries differ?
>>>
>>> SELECT *    FROM Table1   LEFT JOIN Table2 ON (Table1Field =
>>> Table2Field) WHERE (OtherField<>6)
>>> SELECT *    FROM Table1   LEFT JOIN Table2 ON (Table1Field =
>>> Table2Field) AND      (OtherField<>6)
>>>
>>> (The "WHERE" is replaced with "AND")
>>>
>>> Thanks
>>>
>>>
>>
>>
>
>
Author
25 Aug 2006 8:09 PM
"A_Michigan_User\
> Also, you should use an alias for each table in your query.  It makes it
> easier to read and saves you from typing the whoe table name over and over
> again.

I think my mind works a very odd way.  To me "alias saves typing" but that's
all.... It actually makes it HARDER for me to remember what's what.
Instead of just using the 5 table names... I now have to remember I've
"aliased" them into 5 *MORE* names.  (A total of 10)

Since I only type this query once (and put it in my code) there's really not
much point in "saving a little typing".
The reason I gave all my tables their original "clear, easier to use, easy
to remember names" was because I *WANT* to use them in my code.
(Not alias them into t1 and t2 or o or c references that have no meaning to
me.... or make myself remember MORE table names.)



This might shed more light on what I'm trying to do:

The "Uniforms table" contains a list of proposed colors for new uniforms and
which employees suggested the colors.
(Some of the colors have already been decided and can no longer be voted
on.)
Emp=17          Color=Red             Decided=False
Emp=4            Color= Blue            Decided=False
Emp=7            Color=Green          Decided=True
Emp=5            Color=Orange        Decided=False
Emp=88         Color=""                  Decided=False

Each employee gives their thoughts on a color and they are stored in a
separate "Votes Table":
Emp=2            Color=Red                Votes=Too bright
Emp=5            Color=Red                Votes=Too dark
Emp=7            Color=Red                Votes=Too bright
Emp=5            Color=Green             Votes=Too loud

I need to show each employee all the colors available in the "Uniforms
table"... but
EXCLUDE the colors where:
    This employee has already voted on it.  (His record is in the Votes
Table.)
    He suggested the color himself.             (As listed in the Uniforms
Table.)
    Don't list colors that have already been decided.   (As listed in the
Uniforms Table.)
    Don't list colors that are "".   (As listed in the Uniforms Table.)

(After a color has been "decided" (in the Uniforms Table)... all the
matching votes in the Votes Table really aren't needed any longer.)

I guess what I'm asking is.... Doing a table-join is pretty simple.   But
then what if you have a long list of additional
qualifiers... which include (or exclude) certain records based on all kinds
of additional criteria.

Or... should this whole mess been designed differently????

Thank again!


Show quote
> Finding rows in one table which don't have matches in another table is
> easy.
>
> Suppose you have a Customers table declared as
> Create Table Customers (CustomerID int Primary Key, State char(2) Not
> Null)
> and an Orders table declared as
> Create Table Orders (OrderID int Primary Key, CustomerID int Not Null,
> OrderDate datetime Not Null)
> with, of course, a foreign key between the tables on CustomerID.
>
> BTW, many database designers will do what I did  above, call the same
> attribute the same name in every table where it exists.  I think it's less
> confusing than calling one CustomerID and one something like
> OrderCustomerID.  But to each his own, just make sure your site has a
> standard on this and that the standard is followed by everybody.
>
> So, now the query to find all customers who have no orders would be:
>
> Select c.CustomerID
> From Customers c
> Left Join Orders o On c.CustomerID = o.CustomerID
> Where o.CustomerID Is Null
>
> (The reason I use o.OrderID Is Null is OrderID is in the primary key of
> the Orders table, so I know that if this was a real row from Orders,
> OrderID can't be Null.  So, if it is Null, this is a row from Customers
> which had no match in Orders.)
>
> And, to go back to a form of your original question, why would you put
> additional tests in the On clause and why would you put it in the Where
> clause, that depends on what kind of result you are looking for (and,
> almost always, which table the additional test is to be done on).
>
> For example, to find all customers who have no orders since Jan 1, 2006,
> you could use:
>
> Select c.CustomerID
> From Customers c
> Left Join Orders o On c.CustomerID = o.CustomerID
>  And o.OrderDate >= '20060101'
> Where o.OrderID Is Null
>
> But to find customers from New York who have no orders, you would use
>
> Select c.CustomerID
> From Customers c
> Left Join Orders o On c.CustomerID = o.CustomerID
> Where o.OrderID Is Null
>  And c.State = 'NY'
>
> Finally, to find customers from New York who had no orders since Jan 1,
> 2006, you could use:
>
> Select c.CustomerID
> From Customers c
> Left Join Orders o On c.CustomerID = o.CustomerID
>  And o.OrderDate >= '20060101'
> Where o.OrderID Is Null
>  And c.State = 'NY'
>
> Tom
>
> ""A_Michigan_User"" <Michigan_RE_M***@ameritech.net> wrote in message
> news:uW%23eOzGyGHA.4204@TK2MSFTNGP04.phx.gbl...
>>> The problem I have is that, because you didn't bother qualifying what
>>> table OtherField is in, I have at least two different answers.
>>
>> I should have said... No table I have EVER made has EVER had identical
>> field names.
>> (Not sure why anyone would do that... and make this even MORE confusing.)
>>
>> But I think you've found the problem.   It *DOES* matter which table
>> OtherField is in... even though it's only in 1 of the tables (and doesn't
>> really need to be qualified.)
>>
>> Maybe I need to start qualifing *ALL* my fields when joining tables...
>> even though they only appear in 1 of the 2 tables.
>>
>> More....
>>
>> What I was trying to ultimately do was to list *ALL* the rows in
>> Table1...
>> only EXCLUDING the ones that have a matching field in Table2.
>>
>> List all the rows in Table1 ... EXCEPT where
>> Table1.MyField=Table2.MyField
>>
>> I was thinking it would be as easy as changing this... but it's not:
>>
>>> SELECT *    FROM Table1   LEFT JOIN Table2 ON (Table1.MyField  =
>>> Table2.MyField)    SELECT *    FROM Table1   LEFT JOIN Table2 ON
>>> (Table1.MyField <> Table2.MyField)
>>
>> If Table1 contains values like:
>> 2
>> 4
>> 6
>> 8
>> 10
>>
>> And Table2 contains values like:
>> 1
>> 4
>> 6
>>
>> The output should be:
>> 2
>> 8
>> 10
>>
>> (All rows in Table1 are listed... except the matching rows in Table2)
>>
>> I want to thank everyone for the fast replies!
>>
>>
>>
>>
>>
>>> The problem I have is that, because you didn't bother qualifying what
>>> table OtherField is in, I have at least two different answers.
>>
>>
>>> ""A_Michigan_User"" <Michigan_RE_M***@ameritech.net> wrote in message
>>> news:%23CQiEzFyGHA.1252@TK2MSFTNGP04.phx.gbl...
>>>>
>>>> Ok... I give up... how do these 2 queries differ?
>>>>
>>>> SELECT *    FROM Table1   LEFT JOIN Table2 ON (Table1Field =
>>>> Table2Field) WHERE (OtherField<>6)
>>>> SELECT *    FROM Table1   LEFT JOIN Table2 ON (Table1Field =
>>>> Table2Field) AND      (OtherField<>6)
>>>>
>>>> (The "WHERE" is replaced with "AND")
>>>>
>>>> Thanks
>>>>
>>>>
>>>
>>>
>>
>>
>
>
Author
25 Aug 2006 8:32 PM
Jim Underwood
This shouldn't be too difficult really, some inner and outer joins, or
exists / not exists subqueries will do this for you.

As for aliases, T1, T2, or a,b,c are terrible to read and understand, but
using meaningful aliases that are 3 or 4 characters can help make it more
readable.  i.e. EMPLOYEE_JOB_DATA could be aliased as JOB.  Personally, I
find it much easier to read a query with short, meaningful aliases than with
15 to 20 character table names.  I do prefer the table names over the
T1,T1,a,b,c aliases however.  Mind you I still use a,b,c for quick test
code, but never for production code that someone else needs to make sense of
later.

Anyway, back to your question, something like this might work...

declare @Emp as varchar(10)

set @Emp = 7

select unif.color
from Uniforms as Unif
where not exists
(
select 1 from Votes as Votes
where Votes.emp = @emp
and Votes.color = Unif.color
)
and Unif.emp <> @Emp
and Unif.Decided = 'False'



""A_Michigan_User"" <Michigan_RE_M***@ameritech.net> wrote in message
Show quote
news:OyVAeIIyGHA.2220@TK2MSFTNGP02.phx.gbl...
> > Also, you should use an alias for each table in your query.  It makes it
> > easier to read and saves you from typing the whoe table name over and
over
> > again.
>
> I think my mind works a very odd way.  To me "alias saves typing" but
that's
> all.... It actually makes it HARDER for me to remember what's what.
> Instead of just using the 5 table names... I now have to remember I've
> "aliased" them into 5 *MORE* names.  (A total of 10)
>
> Since I only type this query once (and put it in my code) there's really
not
> much point in "saving a little typing".
> The reason I gave all my tables their original "clear, easier to use, easy
> to remember names" was because I *WANT* to use them in my code.
> (Not alias them into t1 and t2 or o or c references that have no meaning
to
> me.... or make myself remember MORE table names.)
>
>
>
> This might shed more light on what I'm trying to do:
>
> The "Uniforms table" contains a list of proposed colors for new uniforms
and
> which employees suggested the colors.
> (Some of the colors have already been decided and can no longer be voted
> on.)
> Emp=17          Color=Red             Decided=False
> Emp=4            Color= Blue            Decided=False
> Emp=7            Color=Green          Decided=True
> Emp=5            Color=Orange        Decided=False
> Emp=88         Color=""                  Decided=False
>
> Each employee gives their thoughts on a color and they are stored in a
> separate "Votes Table":
> Emp=2            Color=Red                Votes=Too bright
> Emp=5            Color=Red                Votes=Too dark
> Emp=7            Color=Red                Votes=Too bright
> Emp=5            Color=Green             Votes=Too loud
>
> I need to show each employee all the colors available in the "Uniforms
> table"... but
> EXCLUDE the colors where:
>     This employee has already voted on it.  (His record is in the Votes
> Table.)
>     He suggested the color himself.             (As listed in the Uniforms
> Table.)
>     Don't list colors that have already been decided.   (As listed in the
> Uniforms Table.)
>     Don't list colors that are "".   (As listed in the Uniforms Table.)
>
> (After a color has been "decided" (in the Uniforms Table)... all the
> matching votes in the Votes Table really aren't needed any longer.)
>
> I guess what I'm asking is.... Doing a table-join is pretty simple.   But
> then what if you have a long list of additional
> qualifiers... which include (or exclude) certain records based on all
kinds
> of additional criteria.
>
> Or... should this whole mess been designed differently????
>
> Thank again!
>
>
> > Finding rows in one table which don't have matches in another table is
> > easy.
> >
> > Suppose you have a Customers table declared as
> > Create Table Customers (CustomerID int Primary Key, State char(2) Not
> > Null)
> > and an Orders table declared as
> > Create Table Orders (OrderID int Primary Key, CustomerID int Not Null,
> > OrderDate datetime Not Null)
> > with, of course, a foreign key between the tables on CustomerID.
> >
> > BTW, many database designers will do what I did  above, call the same
> > attribute the same name in every table where it exists.  I think it's
less
> > confusing than calling one CustomerID and one something like
> > OrderCustomerID.  But to each his own, just make sure your site has a
> > standard on this and that the standard is followed by everybody.
> >
> > So, now the query to find all customers who have no orders would be:
> >
> > Select c.CustomerID
> > From Customers c
> > Left Join Orders o On c.CustomerID = o.CustomerID
> > Where o.CustomerID Is Null
> >
> > (The reason I use o.OrderID Is Null is OrderID is in the primary key of
> > the Orders table, so I know that if this was a real row from Orders,
> > OrderID can't be Null.  So, if it is Null, this is a row from Customers
> > which had no match in Orders.)
> >
> > And, to go back to a form of your original question, why would you put
> > additional tests in the On clause and why would you put it in the Where
> > clause, that depends on what kind of result you are looking for (and,
> > almost always, which table the additional test is to be done on).
> >
> > For example, to find all customers who have no orders since Jan 1, 2006,
> > you could use:
> >
> > Select c.CustomerID
> > From Customers c
> > Left Join Orders o On c.CustomerID = o.CustomerID
> >  And o.OrderDate >= '20060101'
> > Where o.OrderID Is Null
> >
> > But to find customers from New York who have no orders, you would use
> >
> > Select c.CustomerID
> > From Customers c
> > Left Join Orders o On c.CustomerID = o.CustomerID
> > Where o.OrderID Is Null
> >  And c.State = 'NY'
> >
> > Finally, to find customers from New York who had no orders since Jan 1,
> > 2006, you could use:
> >
> > Select c.CustomerID
> > From Customers c
> > Left Join Orders o On c.CustomerID = o.CustomerID
> >  And o.OrderDate >= '20060101'
> > Where o.OrderID Is Null
> >  And c.State = 'NY'
> >
> > Tom
> >
> > ""A_Michigan_User"" <Michigan_RE_M***@ameritech.net> wrote in message
> > news:uW%23eOzGyGHA.4204@TK2MSFTNGP04.phx.gbl...
> >>> The problem I have is that, because you didn't bother qualifying what
> >>> table OtherField is in, I have at least two different answers.
> >>
> >> I should have said... No table I have EVER made has EVER had identical
> >> field names.
> >> (Not sure why anyone would do that... and make this even MORE
confusing.)
> >>
> >> But I think you've found the problem.   It *DOES* matter which table
> >> OtherField is in... even though it's only in 1 of the tables (and
doesn't
> >> really need to be qualified.)
> >>
> >> Maybe I need to start qualifing *ALL* my fields when joining tables...
> >> even though they only appear in 1 of the 2 tables.
> >>
> >> More....
> >>
> >> What I was trying to ultimately do was to list *ALL* the rows in
> >> Table1...
> >> only EXCLUDING the ones that have a matching field in Table2.
> >>
> >> List all the rows in Table1 ... EXCEPT where
> >> Table1.MyField=Table2.MyField
> >>
> >> I was thinking it would be as easy as changing this... but it's not:
> >>
> >>> SELECT *    FROM Table1   LEFT JOIN Table2 ON (Table1.MyField  =
> >>> Table2.MyField)    SELECT *    FROM Table1   LEFT JOIN Table2 ON
> >>> (Table1.MyField <> Table2.MyField)
> >>
> >> If Table1 contains values like:
> >> 2
> >> 4
> >> 6
> >> 8
> >> 10
> >>
> >> And Table2 contains values like:
> >> 1
> >> 4
> >> 6
> >>
> >> The output should be:
> >> 2
> >> 8
> >> 10
> >>
> >> (All rows in Table1 are listed... except the matching rows in Table2)
> >>
> >> I want to thank everyone for the fast replies!
> >>
> >>
> >>
> >>
> >>
> >>> The problem I have is that, because you didn't bother qualifying what
> >>> table OtherField is in, I have at least two different answers.
> >>
> >>
> >>> ""A_Michigan_User"" <Michigan_RE_M***@ameritech.net> wrote in message
> >>> news:%23CQiEzFyGHA.1252@TK2MSFTNGP04.phx.gbl...
> >>>>
> >>>> Ok... I give up... how do these 2 queries differ?
> >>>>
> >>>> SELECT *    FROM Table1   LEFT JOIN Table2 ON (Table1Field =
> >>>> Table2Field) WHERE (OtherField<>6)
> >>>> SELECT *    FROM Table1   LEFT JOIN Table2 ON (Table1Field =
> >>>> Table2Field) AND      (OtherField<>6)
> >>>>
> >>>> (The "WHERE" is replaced with "AND")
> >>>>
> >>>> Thanks
> >>>>
> >>>>
> >>>
> >>>
> >>
> >>
> >
> >
>
>
Author
31 Aug 2006 11:27 AM
Bob Barrows [MVP]
Jim Underwood wrote:
> This shouldn't be too difficult really, some inner and outer joins, or
> exists / not exists subqueries will do this for you.
>
> As for aliases, T1, T2, or a,b,c are terrible to read and understand,
> but using meaningful aliases that are 3 or 4 characters can help make
> it more readable.  i.e. EMPLOYEE_JOB_DATA could be aliased as JOB.

Right. Even though I used "t1" in my earlier reply, I stopped using tN long
ago in favor of meaingful aliases.


--
Microsoft MVP - ASP/ASP.NET
Please reply to the newsgroup. This email account is my spam trap so I
don't check it very often. If you must reply off-line, then remove the
"NO SPAM"
Author
25 Aug 2006 8:47 PM
Aaron Bertrand [SQL Server MVP]
> I think my mind works a very odd way.  To me "alias saves typing" but
> that's all.... It actually makes it HARDER for me to remember what's what.
> Instead of just using the 5 table names... I now have to remember I've
> "aliased" them into 5 *MORE* names.  (A total of 10)

If you can't keep track of Customers as c and Orders as o, then I suppose
your way is better for you.  :-/

> Since I only type this query once (and put it in my code) there's really
> not much point in "saving a little typing".

Maybe a good point, if your entire codebase consists of one query.

> The reason I gave all my tables their original "clear, easier to use, easy
> to remember names" was because I *WANT* to use them in my code.
> (Not alias them into t1 and t2 or o or c references that have no meaning
> to me.... or make myself remember MORE table names.)

That's fine, it was just a suggestion so that you aren't staring at
BigLongTableName constantly.  Nobody is saying you have to do it, just that
most of us with the experience we have find it a much easier way to work.

A
Author
25 Aug 2006 3:54 PM
Alexander Kuznetsov
A_Michigan_User wrote:
> Ok... I give up... how do these 2 queries differ?
>
> SELECT *    FROM Table1   LEFT JOIN Table2 ON (Table1Field = Table2Field)
> WHERE (OtherField<>6)
> SELECT *    FROM Table1   LEFT JOIN Table2 ON (Table1Field = Table2Field)
> AND      (OtherField<>6)
>
> (The "WHERE" is replaced with "AND")
>
> Thanks

Please be specific if it is Table1.OtherField or Table2.OtherField.

If it is actually
WHERE      (Table2.OtherField<>6)
then the query is in fact an inner join in disguise

If it is actually
AND      (Table1.OtherField<>6)
it means "select all the rows from Table1. For those with
(Table1.OtherField<>6) also display matching ones from Table2 if they
exist

On the other hand
WHERE      (Table1.OtherField<>6)
means "select only the rows from Table1 for which
(Table1.OtherField<>6). Also display matching ones from Table2 if they
exist

and so on.
Author
25 Aug 2006 4:10 PM
WebBuilder451
As a rule i try to say away from queries w/o a where clause. however,
if they product the same results now and i'd guess they do that's why you
are asking the question, it may not make that much of a difference here.
However, if you join other tables you are limiting the result set to-be
joined to the next table. and depending on the tables, and we don't know
cause not all info was provided, there you may get different results if you
join table3 on table on Table1Field = Table3Field
--
thanks (as always)
some day i''m gona pay this forum back for all the help i''m getting
kes


""A_Michigan_User"" wrote:

Show quote
>
> Ok... I give up... how do these 2 queries differ?
>
> SELECT *    FROM Table1   LEFT JOIN Table2 ON (Table1Field = Table2Field)
> WHERE (OtherField<>6)
> SELECT *    FROM Table1   LEFT JOIN Table2 ON (Table1Field = Table2Field)
> AND      (OtherField<>6)
>
> (The "WHERE" is replaced with "AND")
>
> Thanks
>
>
>
Author
25 Aug 2006 4:33 PM
Tom Cooper
The first query says match up every row in Table1 with all the rows in
Table2 where Table1Field = Table2Field.  If a row in Table1 has no matching
rows in Table2, include that row from Table1 with all the columns from
Table2 set to NULL.  Then, AFTER matching up the rows using the ON clause,
the WHERE clause discards any row from this intermediate result where
OtherField<>6.  It then returns the remaining rows.

The second query says match up every row in Table1 with all the rows in
Table2 where Table1Field = Table2Field And OtherField<>6.  If a row in
Table1 has no matching rows in Table2, include that row from Table1 with all
the columns from Table2 set to NULL.  It then returns all of these rows.

It makes a big difference which table OtherField is in (which is not clear
from your question).

If OtherField is in Table1 then the first query is just a LEFT JOIN where
you only want rows in Table1 Where OtherField<>6.  But, if OtherField is in
Table2, the first query is the same as an INNER join, since any rows in the
intermediate result which are from rows in Table1 which do not have a match
in Table2 will have NULL in OtherField, and the where clause testing whether
NULL<>6 will not return true, so the row will be discarded.

If OtherField is in Table1, then the second query will match up rows from
Table2 only for those rows which have OtherField<>6 and Table1Field =
Table2Field.  But if it can't do the match, it will still return the row
from Table1, just with the columns from Table2 set to NULL.  That is, you
will have all the rows from Table1, including those with OtherField=6, it's
just that those rows will have the columns from Table2 set to NULL.  But if
OtherField is in Table2, then none of the rows from Table2 with OtherField=6
will be in the result set.

So, while both of these are legal syntax, in 999,999 out of 1,000,000 cases
when OtherField is in Table1, you will want
SELECT *    FROM Table1   LEFT JOIN Table2 ON (Table1Field = Table2Field)
WHERE (OtherField<>6)

and when OtherField is in Table2, you will want

SELECT *    FROM Table1   LEFT JOIN Table2 ON (Table1Field = Table2Field)
AND      (OtherField<>6)

If this is still confusing, try creating some tables and sample data will
some rows that have matching values in Table1Field and Table2Field and some
rows with values in OtherField = 6 and some rows with values in
OtherField<>6.  Run both queries and examine the results.  Do this process
both with tables wher OtherField is in Table1, then do it again where
OtherField is in Table2.

I know OUTER JOINS can be confusing at first, but with a little practice
they will become second nature.

Good luck,
Tom

""A_Michigan_User"" <Michigan_RE_M***@ameritech.net> wrote in message
Show quote
news:%23CQiEzFyGHA.1252@TK2MSFTNGP04.phx.gbl...
>
> Ok... I give up... how do these 2 queries differ?
>
> SELECT *    FROM Table1   LEFT JOIN Table2 ON (Table1Field = Table2Field)
> WHERE (OtherField<>6)
> SELECT *    FROM Table1   LEFT JOIN Table2 ON (Table1Field = Table2Field)
> AND      (OtherField<>6)
>
> (The "WHERE" is replaced with "AND")
>
> Thanks
>
>
Author
25 Aug 2006 7:04 PM
--CELKO--
>> Ok... I give up... how do these 2 queries differ? <<

Here is how OUTER JOINs work in SQL-92.  Assume you are given:

Table1       Table2
a   b        a   c
======       ======
1   w        1   r
2   x        2   s
3   y        3   t
4   z

and the outer join expression:

Table1
LEFT OUTER JOIN
Table2
ON Table1.a = Table2.a      <== join condition
    AND Table2.c = 't';      <== single table condition

We call Table1 the "preserved table" and Table2 the "unpreserved table"
in the query.  What I am going to give you is a little different, but
equivalent to the ANSI/ISO standards.

1) We build the CROSS JOIN of the two tables.  Scan each row in the
result set.

2) If the predicate tests TRUE for that row, then you keep it. You also
remove all rows derived from it from the CROSS JOIN

3) If the predicate tests FALSE or UNKNOWN for that row, then keep the
columns from the preserved table, convert all the columns from the
unpreserved table to NULLs and remove the duplicates.

So let us execute this by hand:

Let @ = passed the first predicate
Let * = passed the second predicate

Table1 CROSS JOIN Table2
a   b        a   c
=========================
1   w       1   r @
1   w       2   s
1   w       3   t *
2   x       1   r
2   x       2   s @
2   x       3   t *
3   y       1   r
3   y       2   s
3   y       3   t @* <== the TRUE set
4   z       1   r
4   z       2   s
4   z       3   t *

Table1 LEFT OUTER JOIN Table2
a   b        a   c
=========================
3   y     3      t      <= only TRUE row
-----------------------
1   w     NULL   NULL   Sets of duplicates
1   w     NULL   NULL
1   w     NULL   NULL
-----------------------
2   x     NULL   NULL
2   x     NULL   NULL
2   x     NULL   NULL
3   y     NULL   NULL  <== derived from the TRUE set - Remove
3   y     NULL   NULL
-----------------------
4   z     NULL   NULL
4   z     NULL   NULL
4   z     NULL   NULL

the final results:

Table1 LEFT OUTER JOIN Table2
a   b        a   c
=========================
1   w     NULL   NULL
2   x     NULL   NULL
3   y     3      t
4   z     NULL   NULL

The basic rule is that every row in the preserved table is represented
in the results in at least one result row.

There are limitations and very serious problems with the extended
equality version of an outer join used in some diseased mutant
products.  Consider the two Chris Date tables

Suppliers        SupParts
supno             supno partno qty
=========        ==============
S1               S1   P1    100
S2               S1   P2    250
S3               S2   P1    100
                  S2   P2    250

and let's do an extended equality outer join like this:

SELECT *
  FROM Supplier, SupParts
WHERE Supplier.supno *= SupParts.supno
   AND qty < 200;

If I do the outer first, I get:

Suppliers LOJ SupParts
supno supno partno qty
=======================
S1     S1   P1    100
S1     S1   P2    250
S2     S2   P1    100
S2     S2   P2    250
S3   NULL  NULL   NULL

Then I apply the (qty < 200) predicate and get

Suppliers LOJ SupParts
supno supno partno qty
===================
S1   S1   P1    100
S2   S2   P1    100

Doing it in the opposite order

Suppliers LOJ SupParts
supno supno partno qty
===================
S1   S1   P1    100
S2   S2   P1    100
S3   NULL NULL  NULL

Sybase does it one way, Oracle does it the other and Centura (nee
Gupta) lets you pick which one -- the worst of both non-standard
worlds!  In SQL-92, you have a choice and can force the order of
execution. Either do the predicates after the join ...

SELECT *
   FROM Supplier
        LEFT OUTER JOIN
        SupParts
        ON Supplier.supno = SupParts.supno
WHERE qty < 200;

... or do it in the joining:

SELECT *
  FROM Supplier
       LEFT OUTER JOIN
       SupParts
       ON Supplier.supno = SupParts.supno
          AND qty < 200;

Another problem is that you cannot show the same table as preserved and
unpreserved in the extended equality version, but it is easy in SQL-92.
For example to find the students who have taken Math 101 and might
have taken Math 102:

SELECT C1.student, C1.math, C2.math
  FROM (SELECT * FROM Courses WHERE math = 101) AS C1
       LEFT OUTER JOIN
       (SELECT * FROM Courses WHERE math = 102) AS C2
       ON C1.student = C2.student;

AddThis Social Bookmark Button