Return t/f on existence of a join

Started by Madison Kellyover 18 years ago6 messagesgeneral
Jump to latest
#1Madison Kelly
linux@alteeve.com

... Or something like that. :)

Sorry for so many questions! I have another "how do I create this
query?" question, if it's okay.

I've got three tables; 'foo', 'bar' and 'baz'.

In 'foo' I've got 'foo_id' which is a PK. I've also got a bunch of
other info, but in essence this is the "parent" table that all others
reference in some way.

In 'bar' I've got 'bar_id' which is also a PK. I also have
'bar_foo_id' which is a FK pointing to 'foo' -> 'foo_id', to show what
'foo' row it (primarily) belongs to.

Lastly, I've got a table called 'baz' which has 'baz_id'. In it, there
are just two columns;

- 'baz_foo_id' which is a FK pointing to 'foo' -> 'foo_id'.
- 'baz_bar_id' which is a FK pointing to 'bar' -> 'bar_id'.

This last table, 'baz' is used as a way for saying 'bar *also* belongs
to a given 'foo' row,

So now my question;

I want to create a query that will allow me to say "show me all 'foo'
rows and tell me if a specific 'baz_id' belongs to it". Normally, I
would do this:

SELECT foo_id FROM foo;
(for each returned row)
{
# Where '$foo_id' is the current 'foo_id' and '$bar_id' is
# the specific/static 'bar_id' we are checking.
SELECT COUNT(*) FROM baz z, bar r WHERE baz_foo_id=$foo_id AND
baz_bar_id=$bar_id;
( if count > 0 ) { # TRUE } else { # FALSE }
}

This is pretty inefficient, obviously. How could I create a query that
returned a TRUE/FALSE column that checks if there is a 'baz' record for
a specified 'bar_id' in all 'foo_id's in one query?

I hope this isn't too muddy. I think part of my problem is I am having
trouble even visualizing my question...

Thanks as always!

Madi

#2Erik Jones
erik@myemma.com
In reply to: Madison Kelly (#1)
Re: Return t/f on existence of a join

On Sep 21, 2007, at 2:17 PM, Madison Kelly wrote:

... Or something like that. :)

Sorry for so many questions! I have another "how do I create this
query?" question, if it's okay.

I've got three tables; 'foo', 'bar' and 'baz'.

In 'foo' I've got 'foo_id' which is a PK. I've also got a bunch of
other info, but in essence this is the "parent" table that all others
reference in some way.

In 'bar' I've got 'bar_id' which is also a PK. I also have
'bar_foo_id' which is a FK pointing to 'foo' -> 'foo_id', to show what
'foo' row it (primarily) belongs to.

Lastly, I've got a table called 'baz' which has 'baz_id'. In it,
there
are just two columns;

- 'baz_foo_id' which is a FK pointing to 'foo' -> 'foo_id'.
- 'baz_bar_id' which is a FK pointing to 'bar' -> 'bar_id'.

This last table, 'baz' is used as a way for saying 'bar *also*
belongs
to a given 'foo' row,

So now my question;

I want to create a query that will allow me to say "show me all
'foo'
rows and tell me if a specific 'baz_id' belongs to it". Normally, I
would do this:

SELECT foo_id FROM foo;
(for each returned row)
{
# Where '$foo_id' is the current 'foo_id' and '$bar_id' is
# the specific/static 'bar_id' we are checking.
SELECT COUNT(*) FROM baz z, bar r WHERE baz_foo_id=$foo_id AND
baz_bar_id=$bar_id;
( if count > 0 ) { # TRUE } else { # FALSE }
}

This is pretty inefficient, obviously. How could I create a query
that
returned a TRUE/FALSE column that checks if there is a 'baz' record
for
a specified 'bar_id' in all 'foo_id's in one query?

I hope this isn't too muddy. I think part of my problem is I am
having
trouble even visualizing my question...

Thanks as always!

Madi

*Not tested* If this isn't quite it, then it should at least get you
close

SELECT foo.foo_id, CASE WHEN baz.foo_id IS NULL THEN FALSE ELSE TRUE
as has_baz
FROM foo
LEFT JOIN baz ON (foo.foo_id=baz.baz_foo_id AND baz.baz_bar_id=$bar_id)

Erik Jones

Software Developer | Emma®
erik@myemma.com
800.595.4401 or 615.292.5888
615.292.0777 (fax)

Emma helps organizations everywhere communicate & market in style.
Visit us online at http://www.myemma.com

#3Jon Sime
jsime@mediamatters.org
In reply to: Madison Kelly (#1)
Re: Return t/f on existence of a join

Madison Kelly wrote:

I want to create a query that will allow me to say "show me all 'foo'
rows and tell me if a specific 'baz_id' belongs to it". Normally, I
would do this:

SELECT foo_id FROM foo;
(for each returned row)
{
# Where '$foo_id' is the current 'foo_id' and '$bar_id' is
# the specific/static 'bar_id' we are checking.
SELECT COUNT(*) FROM baz z, bar r WHERE baz_foo_id=$foo_id AND
baz_bar_id=$bar_id;
( if count > 0 ) { # TRUE } else { # FALSE }
}

This is pretty inefficient, obviously. How could I create a query that
returned a TRUE/FALSE column that checks if there is a 'baz' record for
a specified 'bar_id' in all 'foo_id's in one query?

What you want is a "left outer join" to do all of this in a single query.

select f.foo_id,
case when count(r.bar_id) > 0 then true else false end as tf_col
from foo f
join baz z on (z.baz_foo_id = f.foo_id)
left join bar r on (r.baz_bar_id = z.bar_id)
group by f.foo_id;

-Jon

--
Senior Systems Developer
Media Matters for America
http://mediamatters.org/

#4Madison Kelly
linux@alteeve.com
In reply to: Erik Jones (#2)
Solved! Was (Return t/f on existence of a join)

Thanks to both of you, Erik and Jon!

I had to tweak your two replies to get what I wanted (all 'foo' rows
returned, was only getting ones with a match in 'baz'). You two sent me
on the right path though and I was able to work out the rest using the
PgSQL docs on 'CASE' and 'JOIN'.

Here is the working query (where 'bar_id'=2):

SELECT
CASE z.baz_bar_id
WHEN 2
THEN TRUE
ELSE FALSE
END AS tf_col,
f.foo_id
FROM foo f
LEFT OUTER JOIN baz z
ON (f.foo_id=z.baz_foo_id)
LEFT OUTER JOIN bar b
ON (b.bar_id=z.baz_bar_id)
AND
b.bar_id=2;

Thanks kindly to both! I honestly didn't expect to work this out
before then end of the day. Cool!

Madi

#5Madison Kelly
linux@alteeve.com
In reply to: Madison Kelly (#4)
Wait, not solved... Was (Return t/f on existence of a join)

Madison Kelly wrote:

Thanks to both of you, Erik and Jon!

I had to tweak your two replies to get what I wanted (all 'foo' rows
returned, was only getting ones with a match in 'baz'). You two sent me
on the right path though and I was able to work out the rest using the
PgSQL docs on 'CASE' and 'JOIN'.

Here is the working query (where 'bar_id'=2):

SELECT
CASE z.baz_bar_id
WHEN 2
THEN TRUE
ELSE FALSE
END AS tf_col,
f.foo_id
FROM foo f
LEFT OUTER JOIN baz z
ON (f.foo_id=z.baz_foo_id)
LEFT OUTER JOIN bar b
ON (b.bar_id=z.baz_bar_id)
AND
b.bar_id=2;

Thanks kindly to both! I honestly didn't expect to work this out
before then end of the day. Cool!

Madi

Doh!

It's returning a row from 'foo' for every entry in baz that has an
entry pointing to foo (possibly same problem with each pointer to an
entry in bar, not sure yet). The 'true/false' part is working though...

Back to reading. *sigh* :)

Madi

#6Madison Kelly
linux@alteeve.com
In reply to: Madison Kelly (#5)
Actually Solved! Was: (Return t/f on existence of a join)

Madison Kelly wrote:

It's returning a row from 'foo' for every entry in baz that has an
entry pointing to foo (possibly same problem with each pointer to an
entry in bar, not sure yet). The 'true/false' part is working though...

Back to reading. *sigh* :)

Madi

I'm sorry for all the line noise, but I like to post my solutions "for
the record".

Reading up a bit more of the JOIN types I was finally able to get all
rows in 'foo' returned just once with a t/f depending if a given
baz_bar_id exists. The query is:

(Where '2' is the 'baz_bar_id' I am checking on)

SELECT
f.foo_id,
f.foo_name,
CASE z.baz_foo_id
WHEN 2
THEN TRUE
ELSE FALSE
END
FROM foo f
LEFT JOIN baz z
ON f.foo_id=z.baz_foo_id
AND z.baz_bar_id=2;

Thanks again, both of you!

Madi