Given your expected resultset, first and foremost the price_list table is
"out of the picture".
That's because you want just all the fields from products (id, name,
description), "attach" the price from product_prices (but you NEED to
choose what price (default or discount), else you'd have multiple lines of
the same product).
Then again you want either none or just the first image of product_images.
groupby isn't the answer, because you're discarding large "chunks of
universe". And boy, you chose a really complicated datamodel.
the base "universe" query would be
db(
(db.products.id == db.product_prices.product_id) &
(db.product_prices.price_list_id == db.price_lists.id) &
(db.price_lists.name == 'Default price')
).select(db.products.id, db.products.name, db.products.description, db.
product_prices.price)
This gives you all but the images. You should then store in a variable
(product_ids) the list of the products id to fetch the images separately.
Assuming you'd like to fetch only the first recurrence of an image for a
given product, this should work
first_image = db.product_images.id.min() #the image with the id that comes
first is the min() of the set
images = db(db.product_images.product_id.belongs(product_ids)).select(
first_image, groupby=db.product_images.product_id)
image_dict = {}
for row in images:
image_dict[row.product_images.product_id] = db.product_images(
first_image)
now in image_dict you have a dict holding for each product_id the row of
the first image in the product_images table.
This basically means multiple queries to fetch what you want.
Given that the thread started with you preferring to fetch this set out of
a single query, I'd advise you to add either a boolean to the
product_images table that states "main_image" (true/false) or an integer
"image_index" that will hold 1,2,3,4 etc to be able to filter the data
accordingly.
in the "boolean" case, your "image" query would be much simpler
db(
(db.product_images.product_id.belongs(product_ids)) &
(db.product_images.main_image == True) # or image_index == 1
).select()
This would mean two selects to fetch what you want. From there, combining
the two in a single select with a left join shouldn't be hard
BTW (for the kickass t-sql guys): postgresql has window
functions<http://www.postgresql.org/docs/9.3/static/tutorial-window.html>to
make these kind of complicated grouping/slicing work (fast), but:
- those syntaxes are quite backend specific
- only a subset is supported and only on a bunch of adapters (mssql has
most of them in 2008, all in 2012, mysql has very limited, oracle and
postgres in recent versions)
so DAL doesn't expose native functions supporting them.
The syntax is pretty complicated, e.g. :
select foo(field) over (partition by list_of_fields order bylist_of_other_fields
)
from table
and needs some careful planning, although the results are really (really)
fast, compared to what it would need with "standard" multiple queries.
Making a view out of a complicate query and accessing it with migrate=False
is viable and recommended (only con: your app will probably be able to run
on the single backend you choose),, but you need to be a sql-fu master.
That being said, the speedup is noticeable for the end user if you need
thousands of rows grouped/sliced. For the usual webpage showing at most a
hundreds product fetching the resulset with the above two queries doesn't
practically make a difference.
--
Resources:
- http://web2py.com
- http://web2py.com/book (Documentation)
- http://github.com/web2py/web2py (Source code)
- https://code.google.com/p/web2py/issues/list (Report Issues)
---
You received this message because you are subscribed to the Google Groups
"web2py-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.