Home All Groups Group Topic Archive Search About

How many sub-selects and better options?

Author
9 Jul 2005 3:35 PM
J Rieggle
Hi.

I am working on an ecommerce website, and I recently implemented paging of
product items from a chosen category.  The first approach was to keep the
SQL simple, so I link all products to a single category.  However my client
is asking that it be possible to browse all items that exist within a
category, rather than having to click the final leaf category, E.g.

Category: Mind, Body, Spirit
    Sub-Cat: Spiritualism
        Sub-Cat: Meditation Techniques

Now, if the user clicks Mind, Body, Spirit I need to show ALL products that
fall underneath, including everything from Spiritualism and Meditation
Techniques.  This SQL is a snippet of the main query to return a set of
results based on paging - the paging code has been omitted, and the inner
select deals with choosing the correct set of results to support paging:

Select  P.Name Publisher, Z.ProductID, Z.Name, Z.Authors, Z.Price,
Z.DateOfPub,
  LEFT(Z.Description, 500) Description, Z.SaleIndex, Z.ImageLink,
Z.PreviewImageLink
From
Publishers P INNER JOIN (
  Products Z Inner Join (
   Select top 5 A.ProductID
   from (
     Select top 5 B1.ProductID, B1.Name
     from
      Products B1, categoryProducts B2
     where
      B2.CategoryID = 1 and B1.ProductID = B2.ProductID
     Order By B1.Name  ASC
   ) A
  order by A.Name DESC)
  Y On Z.ProductID = Y.ProductID
) ON P.PublisherID = Z.PublisherID
Order by Z.Name ASC

First question - there are a number of inner joins going on - is there a
better way to do this?

In the code above the CategoryID = 1, so if Mind, Body, Spirit had an ID of
1, then only books with a category of 1 would be chosen, and books
underneath this category would not be chosen.  After some research I have
worked out how to set my catgories up to allow a hierarchical
representation.  Assuming I have the following table structures:

Products
========
ProductID
Name

Categories
==========
CategoryID
Name
Linkage

CategoryProducts
================
CategoryID
ProductID

And the linkage column for the categories mentioned are:

Mind, Body, Spirit = 1.1
    Sub-Cat: Spiritualism = 1.1.1
        Sub-Cat: Meditation Techniques = 1.1.2

Then I can find out all books underneath Mind Body and Spirt using:

SELECT P.*
FROM
products P INNER JOIN
(
  SELECT ProductID
  FROM categoryproducts CP
  WHERE CP.CategoryID in (
     SELECT categoryID
     FROM
      Categories
     WHERE
      Linkage LIKE (SELECT Linkage+'%' FROM Categories WHERE CategoryID=4)
  )
) A
ON A.ProductID = p.ProductID

However, to support paging, I need to link this query with the previous
query.  I feel there might be too many selects going on when I do this (but
I am no expert), and secondly, I havent got a clue how to incorporate this
query above with the original higher up!

Help!

jr.

Author
9 Jul 2005 6:38 PM
David Portas
For paging solutions:
http://www.aspfaq.com/show.asp?id=2120

For browsing your categories, joins are good if the hierarchy is of a known,
fixed depth. For trees of arbitrary depth you should consider a hierarchy
model other than a simple adjacency list. Google for "trees", "nested sets"
and "materialized path" in the archives of this group, this is an FAQ.

--
David Portas
SQL Server MVP
--
Author
9 Jul 2005 7:34 PM
--CELKO--
Might want to get a copy of TREES & HIERARCHIES IN SQL for the database
side.  I don't do paging -- much too front end :)
Author
10 Jul 2005 8:49 AM
J Rieggle
Thanks David and Celko.  I have introduced the materialized path concept,
which is shown in the original post - I named the path field Linkage, which
I admit isnt a very good name.

jr.

Show quote
"--CELKO--" <jcelko***@earthlink.net> wrote in message
news:1120937699.723212.112000@g14g2000cwa.googlegroups.com...
> Might want to get a copy of TREES & HIERARCHIES IN SQL for the database
> side.  I don't do paging -- much too front end :)
>
Author
9 Jul 2005 8:04 PM
Colin Dawson
Looking at this, there is only a finite number of levels (i.e. 3)  A quick
answer for is to make use of an indexed view.
They work with all versions of SQL Server (except the Desktop Engine I
think).  However for all versions except enterprise you need to add the
NoExpand table hint in order to get SQL to use the index ;-)

OK, the basic idea if that you create a massive table which performs the
joins, not at select time, but at insert time.  However, as it's only ever
one row being altered at a time, the amount of overhead to updating the
indexed view is alot lower than performing the join every time that you do
the select.  Also as it's only one row, it won't take long to update.


Show quote
"J Rieggle" <jrieg***@hotmail.co.uk> wrote in message
news:OWb7WvJhFHA.3936@tk2msftngp13.phx.gbl...
> Hi.
>
> I am working on an ecommerce website, and I recently implemented paging of
> product items from a chosen category.  The first approach was to keep the
> SQL simple, so I link all products to a single category.  However my
> client is asking that it be possible to browse all items that exist within
> a category, rather than having to click the final leaf category, E.g.
>
> Category: Mind, Body, Spirit
>    Sub-Cat: Spiritualism
>        Sub-Cat: Meditation Techniques
>
> Now, if the user clicks Mind, Body, Spirit I need to show ALL products
> that fall underneath, including everything from Spiritualism and
> Meditation Techniques.  This SQL is a snippet of the main query to return
> a set of results based on paging - the paging code has been omitted, and
> the inner select deals with choosing the correct set of results to support
> paging:
>
> Select  P.Name Publisher, Z.ProductID, Z.Name, Z.Authors, Z.Price,
> Z.DateOfPub,
>  LEFT(Z.Description, 500) Description, Z.SaleIndex, Z.ImageLink,
> Z.PreviewImageLink
> From
> Publishers P INNER JOIN (
>  Products Z Inner Join (
>   Select top 5 A.ProductID
>   from (
>     Select top 5 B1.ProductID, B1.Name
>     from
>      Products B1, categoryProducts B2
>     where
>      B2.CategoryID = 1 and B1.ProductID = B2.ProductID
>     Order By B1.Name  ASC
>   ) A
>  order by A.Name DESC)
>  Y On Z.ProductID = Y.ProductID
> ) ON P.PublisherID = Z.PublisherID
> Order by Z.Name ASC
>
> First question - there are a number of inner joins going on - is there a
> better way to do this?
>
> In the code above the CategoryID = 1, so if Mind, Body, Spirit had an ID
> of 1, then only books with a category of 1 would be chosen, and books
> underneath this category would not be chosen.  After some research I have
> worked out how to set my catgories up to allow a hierarchical
> representation.  Assuming I have the following table structures:
>
> Products
> ========
> ProductID
> Name
>
> Categories
> ==========
> CategoryID
> Name
> Linkage
>
> CategoryProducts
> ================
> CategoryID
> ProductID
>
> And the linkage column for the categories mentioned are:
>
> Mind, Body, Spirit = 1.1
>    Sub-Cat: Spiritualism = 1.1.1
>        Sub-Cat: Meditation Techniques = 1.1.2
>
> Then I can find out all books underneath Mind Body and Spirt using:
>
> SELECT P.*
> FROM
> products P INNER JOIN
> (
>  SELECT ProductID
>  FROM categoryproducts CP
>  WHERE CP.CategoryID in (
>     SELECT categoryID
>     FROM
>      Categories
>     WHERE
>      Linkage LIKE (SELECT Linkage+'%' FROM Categories WHERE CategoryID=4)
>  )
> ) A
> ON A.ProductID = p.ProductID
>
> However, to support paging, I need to link this query with the previous
> query.  I feel there might be too many selects going on when I do this
> (but I am no expert), and secondly, I havent got a clue how to incorporate
> this query above with the original higher up!
>
> Help!
>
> jr.
>
>
>
Author
10 Jul 2005 8:51 AM
J Rieggle
Colin,

Thanks for this answer.  Could you elaborate more on this, because I am not
very good with SQL? Also, the example has 3 levels, but in reality it may
well be more complicated and deeper - would this break the indexed view
approach?

jr.

Show quote
"Colin Dawson" <newsgro***@cjdawson.com> wrote in message
news:45Wze.66340$G8.22679@text.news.blueyonder.co.uk...
> Looking at this, there is only a finite number of levels (i.e. 3)  A quick
> answer for is to make use of an indexed view.
> They work with all versions of SQL Server (except the Desktop Engine I
> think).  However for all versions except enterprise you need to add the
> NoExpand table hint in order to get SQL to use the index ;-)
>
> OK, the basic idea if that you create a massive table which performs the
> joins, not at select time, but at insert time.  However, as it's only ever
> one row being altered at a time, the amount of overhead to updating the
> indexed view is alot lower than performing the join every time that you do
> the select.  Also as it's only one row, it won't take long to update.
>
>
> "J Rieggle" <jrieg***@hotmail.co.uk> wrote in message
> news:OWb7WvJhFHA.3936@tk2msftngp13.phx.gbl...
>> Hi.
>>
>> I am working on an ecommerce website, and I recently implemented paging
>> of product items from a chosen category.  The first approach was to keep
>> the SQL simple, so I link all products to a single category.  However my
>> client is asking that it be possible to browse all items that exist
>> within a category, rather than having to click the final leaf category,
>> E.g.
>>
>> Category: Mind, Body, Spirit
>>    Sub-Cat: Spiritualism
>>        Sub-Cat: Meditation Techniques
>>
>> Now, if the user clicks Mind, Body, Spirit I need to show ALL products
>> that fall underneath, including everything from Spiritualism and
>> Meditation Techniques.  This SQL is a snippet of the main query to return
>> a set of results based on paging - the paging code has been omitted, and
>> the inner select deals with choosing the correct set of results to
>> support paging:
>>
>> Select  P.Name Publisher, Z.ProductID, Z.Name, Z.Authors, Z.Price,
>> Z.DateOfPub,
>>  LEFT(Z.Description, 500) Description, Z.SaleIndex, Z.ImageLink,
>> Z.PreviewImageLink
>> From
>> Publishers P INNER JOIN (
>>  Products Z Inner Join (
>>   Select top 5 A.ProductID
>>   from (
>>     Select top 5 B1.ProductID, B1.Name
>>     from
>>      Products B1, categoryProducts B2
>>     where
>>      B2.CategoryID = 1 and B1.ProductID = B2.ProductID
>>     Order By B1.Name  ASC
>>   ) A
>>  order by A.Name DESC)
>>  Y On Z.ProductID = Y.ProductID
>> ) ON P.PublisherID = Z.PublisherID
>> Order by Z.Name ASC
>>
>> First question - there are a number of inner joins going on - is there a
>> better way to do this?
>>
>> In the code above the CategoryID = 1, so if Mind, Body, Spirit had an ID
>> of 1, then only books with a category of 1 would be chosen, and books
>> underneath this category would not be chosen.  After some research I have
>> worked out how to set my catgories up to allow a hierarchical
>> representation.  Assuming I have the following table structures:
>>
>> Products
>> ========
>> ProductID
>> Name
>>
>> Categories
>> ==========
>> CategoryID
>> Name
>> Linkage
>>
>> CategoryProducts
>> ================
>> CategoryID
>> ProductID
>>
>> And the linkage column for the categories mentioned are:
>>
>> Mind, Body, Spirit = 1.1
>>    Sub-Cat: Spiritualism = 1.1.1
>>        Sub-Cat: Meditation Techniques = 1.1.2
>>
>> Then I can find out all books underneath Mind Body and Spirt using:
>>
>> SELECT P.*
>> FROM
>> products P INNER JOIN
>> (
>>  SELECT ProductID
>>  FROM categoryproducts CP
>>  WHERE CP.CategoryID in (
>>     SELECT categoryID
>>     FROM
>>      Categories
>>     WHERE
>>      Linkage LIKE (SELECT Linkage+'%' FROM Categories WHERE CategoryID=4)
>>  )
>> ) A
>> ON A.ProductID = p.ProductID
>>
>> However, to support paging, I need to link this query with the previous
>> query.  I feel there might be too many selects going on when I do this
>> (but I am no expert), and secondly, I havent got a clue how to
>> incorporate this query above with the original higher up!
>>
>> Help!
>>
>> jr.
>>
>>
>>
>
>
Author
10 Jul 2005 8:08 PM
Colin Dawson
I'm not sure about how to implement using the example SQL query that you
provided.   The reason is that you're using Select Top and Order By's in the
inline views.

I know that you are not allowed to perform any aggregate type functions i.e.
group by's, counts and stuff like that.  I'd spend some time, maybe a couple
of days re-working that Select statement to see if it can be flattened
first.   I'd also break it down into it's component parts, so that I could
fully understand it.  I'd then once the Query is simplified as much as
possible....  that includes making sure that all joins are using the same
syntax, not using an inline view if it's really not needed, etc.

It would also be worthwhile playing about with indexed views so that you get
to see how they work, even if they're not useful this exact scenario, there
will always be another time that they'll get you out of a jam.

Show quote
"J Rieggle" <jrieg***@hotmail.co.uk> wrote in message
news:eNdQByShFHA.3300@TK2MSFTNGP15.phx.gbl...
> Colin,
>
> Thanks for this answer.  Could you elaborate more on this, because I am
> not very good with SQL? Also, the example has 3 levels, but in reality it
> may well be more complicated and deeper - would this break the indexed
> view approach?
>
> jr.
>
> "Colin Dawson" <newsgro***@cjdawson.com> wrote in message
> news:45Wze.66340$G8.22679@text.news.blueyonder.co.uk...
>> Looking at this, there is only a finite number of levels (i.e. 3)  A
>> quick answer for is to make use of an indexed view.
>> They work with all versions of SQL Server (except the Desktop Engine I
>> think).  However for all versions except enterprise you need to add the
>> NoExpand table hint in order to get SQL to use the index ;-)
>>
>> OK, the basic idea if that you create a massive table which performs the
>> joins, not at select time, but at insert time.  However, as it's only
>> ever one row being altered at a time, the amount of overhead to updating
>> the indexed view is alot lower than performing the join every time that
>> you do the select.  Also as it's only one row, it won't take long to
>> update.
>>
>>
>> "J Rieggle" <jrieg***@hotmail.co.uk> wrote in message
>> news:OWb7WvJhFHA.3936@tk2msftngp13.phx.gbl...
>>> Hi.
>>>
>>> I am working on an ecommerce website, and I recently implemented paging
>>> of product items from a chosen category.  The first approach was to keep
>>> the SQL simple, so I link all products to a single category.  However my
>>> client is asking that it be possible to browse all items that exist
>>> within a category, rather than having to click the final leaf category,
>>> E.g.
>>>
>>> Category: Mind, Body, Spirit
>>>    Sub-Cat: Spiritualism
>>>        Sub-Cat: Meditation Techniques
>>>
>>> Now, if the user clicks Mind, Body, Spirit I need to show ALL products
>>> that fall underneath, including everything from Spiritualism and
>>> Meditation Techniques.  This SQL is a snippet of the main query to
>>> return a set of results based on paging - the paging code has been
>>> omitted, and the inner select deals with choosing the correct set of
>>> results to support paging:
>>>
>>> Select  P.Name Publisher, Z.ProductID, Z.Name, Z.Authors, Z.Price,
>>> Z.DateOfPub,
>>>  LEFT(Z.Description, 500) Description, Z.SaleIndex, Z.ImageLink,
>>> Z.PreviewImageLink
>>> From
>>> Publishers P INNER JOIN (
>>>  Products Z Inner Join (
>>>   Select top 5 A.ProductID
>>>   from (
>>>     Select top 5 B1.ProductID, B1.Name
>>>     from
>>>      Products B1, categoryProducts B2
>>>     where
>>>      B2.CategoryID = 1 and B1.ProductID = B2.ProductID
>>>     Order By B1.Name  ASC
>>>   ) A
>>>  order by A.Name DESC)
>>>  Y On Z.ProductID = Y.ProductID
>>> ) ON P.PublisherID = Z.PublisherID
>>> Order by Z.Name ASC
>>>
>>> First question - there are a number of inner joins going on - is there a
>>> better way to do this?
>>>
>>> In the code above the CategoryID = 1, so if Mind, Body, Spirit had an ID
>>> of 1, then only books with a category of 1 would be chosen, and books
>>> underneath this category would not be chosen.  After some research I
>>> have worked out how to set my catgories up to allow a hierarchical
>>> representation.  Assuming I have the following table structures:
>>>
>>> Products
>>> ========
>>> ProductID
>>> Name
>>>
>>> Categories
>>> ==========
>>> CategoryID
>>> Name
>>> Linkage
>>>
>>> CategoryProducts
>>> ================
>>> CategoryID
>>> ProductID
>>>
>>> And the linkage column for the categories mentioned are:
>>>
>>> Mind, Body, Spirit = 1.1
>>>    Sub-Cat: Spiritualism = 1.1.1
>>>        Sub-Cat: Meditation Techniques = 1.1.2
>>>
>>> Then I can find out all books underneath Mind Body and Spirt using:
>>>
>>> SELECT P.*
>>> FROM
>>> products P INNER JOIN
>>> (
>>>  SELECT ProductID
>>>  FROM categoryproducts CP
>>>  WHERE CP.CategoryID in (
>>>     SELECT categoryID
>>>     FROM
>>>      Categories
>>>     WHERE
>>>      Linkage LIKE (SELECT Linkage+'%' FROM Categories WHERE
>>> CategoryID=4)
>>>  )
>>> ) A
>>> ON A.ProductID = p.ProductID
>>>
>>> However, to support paging, I need to link this query with the previous
>>> query.  I feel there might be too many selects going on when I do this
>>> (but I am no expert), and secondly, I havent got a clue how to
>>> incorporate this query above with the original higher up!
>>>
>>> Help!
>>>
>>> jr.
>>>
>>>
>>>
>>
>>
>
>
Author
11 Jul 2005 7:45 AM
J Rieggle
Colin,

Thanks for your helpful mail.  I will spend soetime looking at indexed
views, because I admit I know nothing of them.

Thanks

jr.

Show quote
"Colin Dawson" <newsgro***@cjdawson.com> wrote in message
news:PefAe.66986$G8.31364@text.news.blueyonder.co.uk...
> I'm not sure about how to implement using the example SQL query that you
> provided.   The reason is that you're using Select Top and Order By's in
> the inline views.
>
> I know that you are not allowed to perform any aggregate type functions
> i.e. group by's, counts and stuff like that.  I'd spend some time, maybe a
> couple of days re-working that Select statement to see if it can be
> flattened first.   I'd also break it down into it's component parts, so
> that I could fully understand it.  I'd then once the Query is simplified
> as much as possible....  that includes making sure that all joins are
> using the same syntax, not using an inline view if it's really not needed,
> etc.
>
> It would also be worthwhile playing about with indexed views so that you
> get to see how they work, even if they're not useful this exact scenario,
> there will always be another time that they'll get you out of a jam.
>
> "J Rieggle" <jrieg***@hotmail.co.uk> wrote in message
> news:eNdQByShFHA.3300@TK2MSFTNGP15.phx.gbl...
>> Colin,
>>
>> Thanks for this answer.  Could you elaborate more on this, because I am
>> not very good with SQL? Also, the example has 3 levels, but in reality it
>> may well be more complicated and deeper - would this break the indexed
>> view approach?
>>
>> jr.
>>
>> "Colin Dawson" <newsgro***@cjdawson.com> wrote in message
>> news:45Wze.66340$G8.22679@text.news.blueyonder.co.uk...
>>> Looking at this, there is only a finite number of levels (i.e. 3)  A
>>> quick answer for is to make use of an indexed view.
>>> They work with all versions of SQL Server (except the Desktop Engine I
>>> think).  However for all versions except enterprise you need to add the
>>> NoExpand table hint in order to get SQL to use the index ;-)
>>>
>>> OK, the basic idea if that you create a massive table which performs the
>>> joins, not at select time, but at insert time.  However, as it's only
>>> ever one row being altered at a time, the amount of overhead to updating
>>> the indexed view is alot lower than performing the join every time that
>>> you do the select.  Also as it's only one row, it won't take long to
>>> update.
>>>
>>>
>>> "J Rieggle" <jrieg***@hotmail.co.uk> wrote in message
>>> news:OWb7WvJhFHA.3936@tk2msftngp13.phx.gbl...
>>>> Hi.
>>>>
>>>> I am working on an ecommerce website, and I recently implemented paging
>>>> of product items from a chosen category.  The first approach was to
>>>> keep the SQL simple, so I link all products to a single category.
>>>> However my client is asking that it be possible to browse all items
>>>> that exist within a category, rather than having to click the final
>>>> leaf category, E.g.
>>>>
>>>> Category: Mind, Body, Spirit
>>>>    Sub-Cat: Spiritualism
>>>>        Sub-Cat: Meditation Techniques
>>>>
>>>> Now, if the user clicks Mind, Body, Spirit I need to show ALL products
>>>> that fall underneath, including everything from Spiritualism and
>>>> Meditation Techniques.  This SQL is a snippet of the main query to
>>>> return a set of results based on paging - the paging code has been
>>>> omitted, and the inner select deals with choosing the correct set of
>>>> results to support paging:
>>>>
>>>> Select  P.Name Publisher, Z.ProductID, Z.Name, Z.Authors, Z.Price,
>>>> Z.DateOfPub,
>>>>  LEFT(Z.Description, 500) Description, Z.SaleIndex, Z.ImageLink,
>>>> Z.PreviewImageLink
>>>> From
>>>> Publishers P INNER JOIN (
>>>>  Products Z Inner Join (
>>>>   Select top 5 A.ProductID
>>>>   from (
>>>>     Select top 5 B1.ProductID, B1.Name
>>>>     from
>>>>      Products B1, categoryProducts B2
>>>>     where
>>>>      B2.CategoryID = 1 and B1.ProductID = B2.ProductID
>>>>     Order By B1.Name  ASC
>>>>   ) A
>>>>  order by A.Name DESC)
>>>>  Y On Z.ProductID = Y.ProductID
>>>> ) ON P.PublisherID = Z.PublisherID
>>>> Order by Z.Name ASC
>>>>
>>>> First question - there are a number of inner joins going on - is there
>>>> a better way to do this?
>>>>
>>>> In the code above the CategoryID = 1, so if Mind, Body, Spirit had an
>>>> ID of 1, then only books with a category of 1 would be chosen, and
>>>> books underneath this category would not be chosen.  After some
>>>> research I have worked out how to set my catgories up to allow a
>>>> hierarchical representation.  Assuming I have the following table
>>>> structures:
>>>>
>>>> Products
>>>> ========
>>>> ProductID
>>>> Name
>>>>
>>>> Categories
>>>> ==========
>>>> CategoryID
>>>> Name
>>>> Linkage
>>>>
>>>> CategoryProducts
>>>> ================
>>>> CategoryID
>>>> ProductID
>>>>
>>>> And the linkage column for the categories mentioned are:
>>>>
>>>> Mind, Body, Spirit = 1.1
>>>>    Sub-Cat: Spiritualism = 1.1.1
>>>>        Sub-Cat: Meditation Techniques = 1.1.2
>>>>
>>>> Then I can find out all books underneath Mind Body and Spirt using:
>>>>
>>>> SELECT P.*
>>>> FROM
>>>> products P INNER JOIN
>>>> (
>>>>  SELECT ProductID
>>>>  FROM categoryproducts CP
>>>>  WHERE CP.CategoryID in (
>>>>     SELECT categoryID
>>>>     FROM
>>>>      Categories
>>>>     WHERE
>>>>      Linkage LIKE (SELECT Linkage+'%' FROM Categories WHERE
>>>> CategoryID=4)
>>>>  )
>>>> ) A
>>>> ON A.ProductID = p.ProductID
>>>>
>>>> However, to support paging, I need to link this query with the previous
>>>> query.  I feel there might be too many selects going on when I do this
>>>> (but I am no expert), and secondly, I havent got a clue how to
>>>> incorporate this query above with the original higher up!
>>>>
>>>> Help!
>>>>
>>>> jr.
>>>>
>>>>
>>>>
>>>
>>>
>>
>>
>
>

AddThis Social Bookmark Button