KBD

Keith Devens .com

Monday, October 13, 2008 Flag waving
REMEMBERS- HEEL BARES DURID! BARE DURIDS IS STORNG FREND! – Alamo
← Concealed carryTony Blair is the man →

Daily link icon Friday, March 5, 2004

SQL question

Say I have some tables such as (to be really generic):

Objects
Object_Id
more fields...

and

Properties
Object_Id
Property_Name

So, every "object" can have multiple "properties". Now, it's really easy to say "give me all the objects which have ANY of these properties" with something like "SELECT Objects.* FROM Objects INNER JOIN Properties USING(Object_Id) WHERE Property_Name IN([list of properties])"

But how can you easily get the set of objects which have ALL of the properties in the [list of properties]? You could say something like:

"SELECT * FROM Objects WHERE Object_Id IN(
INTERSECT(
(SELECT Object_Id FROM Properties WHERE Property_Name = list[0]),
(SELECT Object_Id FROM Properties WHERE Property_Name = list[1]),
(SELECT Object_Id FROM Properties WHERE Property_Name = list[2]),
etc.
)"

But that's a mess, and doesn't happen to be available to me anyway since I'm using MySQL.

Anyone know the right way to do this?

← Concealed carryTony Blair is the man →

Comments XML gif

J$ (http://alpha-geek.com) wrote:

Off of the top of my head, this may do what you want.

SELECT *
FROM Objects o
JOIN Properties p ON p. Object_Id = p. Object_Id
WHERE p.Property_Name = 'this'
AND p.Property_Name = 'that'
AND p.Property_Name = 'foo'
AND p.Property_Name = 'bar'
AND p.Property_Name = 'baz'
AND p.Property_Name = 'quux'
.
.
.
∴ J$ | 5-Mar-2004 2:04pm est | http://alpha-geek.com | #4086

J$ (http://alpha-geek.com) wrote:

Oh wait, that won't work in any way shape or form. What was I thinking?

That will teach me to write knee-jerk SQL...

∴ J$ | 5-Mar-2004 2:06pm est | http://alpha-geek.com | #4087

Goerge Schlossnagle wrote:

You can join against properties multiple times in you single query

SELECT Objects.* FROM Objects o, Properties a, Properties b WHERE o.oid = a.oid AND o.oid = b.oid AND a.pname = 'this' AND b.pname = 'that'

∴ Goerge Schlossnagle | 5-Mar-2004 3:03pm est | #4088

Keith (http://keithdevens.com/) wrote:

Eew. OK. I was hoping there'd be another way to do it besides doing many joins. Thanks though, that's at least better than what I was using. I wonder if there's still another way.

Keith | 5-Mar-2004 3:08pm est | http://keithdevens.com/ | #4089

Ned Batchelder (http://nedbatchelder.com) wrote:

You could avoid the INTERSECT but do the same sort of query with:

SELECT * FROM Objects WHERE 
Object_Id IN (SELECT Object_Id FROM Properties WHERE Property_Name = list[0]) AND
Object_Id IN (SELECT Object_Id FROM Properties WHERE Property_Name = list[1]) AND
Object_ID IN (SELECT Object_Id FROM Properties WHERE Property_Name = list[2])
)
∴ Ned Batchelder | 6-Mar-2004 6:19pm est | http://nedbatchelder.com | #4092

Keith (http://keithdevens.com/) wrote:

Here's basically what I wound up using. I normalized some more, so I had to do some more joins in there...

SELECT a.Bookmark_Id
FROM (
    Bookmark_Keywords a
    INNER JOIN Bookmark_Keyword_Info bki0
    USING ( Bookmark_Keyword_Id )
) INNER JOIN (
    Bookmark_Keywords b
    INNER JOIN Bookmark_Keyword_Info bki1
    USING ( Bookmark_Keyword_Id )
) ON (a.Bookmark_Id = b.Bookmark_Id)
    INNER JOIN (
        Bookmark_Keywords c
        INNER JOIN Bookmark_Keyword_Info bki2
        USING ( Bookmark_Keyword_Id )
    ) ON (a.Bookmark_Id = c.Bookmark_Id)
WHERE bki0.Bookmark_Keyword_Name = 'java' AND
   bki1.Bookmark_Keyword_Name = 'scripting' AND
   bki2.Bookmark_Keyword_Name = 'python'

And that's all dynamically generated based on what keywords (properties) are asked for. The base case looks like:

SELECT a.Bookmark_Id
FROM (
    Bookmark_Keywords a
    INNER JOIN Bookmark_Keyword_Info bki0
    USING ( Bookmark_Keyword_Id )
)WHERE bki0.Bookmark_Keyword_Name = 'java'
Keith | 9-Mar-2004 8:21pm est | http://keithdevens.com/ | #4101

Feel free to post a comment below. Please see my comment policy.

Formatting Rules (No HTML):

  • **bold**, *italic*, _underlined_, --strikeout--
  • "text"="url" creates a link, and URLs are auto-highlighted
  • Blockquote: Like e-mail, begin paragraph with > (greater-than sign)
  • Lists: begin paragraph with *,-, or + (unordered), or # (ordered)
  • Code block: ?!code:language=perl|php|sql|javascript|etc.{\n}...{\n}?!/code

:
(will be your IP address if blank)
: (optional)
(Will not be shown on site)

: (optional)
:

October 2008
SunMonTueWedThuFriSat
 1234
567891011
12131415161718
19202122232425
262728293031 



RSS feed RSS feed for Keith's Weblog
Atom feed Atom feed for Keith's Weblog
Weblog archive
Recent comments
  on 7 posts

Recent comments XML

new⇒Spider solitaire

I have now won, at the "Difficult"​level, 186 games of Spider​Solitaire.  I...

75.179.28.113: Oct 13, 9:34am

new⇒Girls, please don't get breast implants

Please, don't marry him.

You​want to get surgery to make​yourself more i...

gigi: Oct 12, 11:47pm

I hate PHP

Elliot Anderson,

Dude!! You the​man! The reverse replacement for​array_u...

Alex Ndungu: Oct 11, 1:35am

Call a function from a string in Python

?!code:
some_object.__getattribute​__('method_name')()
?!/code

is​the s...

Patrick Corcoran: Oct 8, 3:53pm

Sed one-liners

Hi.

I wanted to let you know​that I wrote an article "Famous Sed​One-Lin...

Peteris Krumins: Oct 8, 3:05am

Timesheet Calculator

Hadn't seen it before now, but my​company already uses a time​tracking prog...

Keith: Oct 7, 10:44am

Generated in about 0.204s.

(Used 8 db queries)

mobile phone