Sorry if the title is not very clear...
I have two tables products and images,
related on products.product_id = images.product_id,
each product has several images related to it on the images table,
both tables have a column width values I wish to ORDER BY (product_order and image_order).
The result I'm looking for is a list with all the published products with only one image (and one result) per product, the image should be the one with the lowest value on the column image_order.
I put together the code below from other answers I found here and it's working, the only problem is that the column image_order allows duplicates, so where there are images for the same product with the same value in image_order I'm getting multiple results per product.
SELECT products.*, images.image_name, images.image_order
FROM products
LEFT JOIN images ON (
images.product_id = products.product_id
AND images.image_order = (
SELECT min(image_order)
FROM images
WHERE product_id = products.product_id
)
)
WHERE products.published = 1
ORDER BY products.product_order ASC
edit (My tables):
Table products
product_id | product_name | product_order
____________|________________|_________________
1 | Fist Product | 1
2 | Second Product | 2
3 | Third Product | 3
Table images
image_id | product_id | image_name | image_order
____________|________________|__________________|_________________
1 | 1 | Fist Image URL | 1
2 | 1 | Second Image URL | 1
3 | 2 | Third Image URL | 1
4 | 3 | Fourth Image URL | 1
The results I'm getting from this Query:
Firt Product + First Image
Firt Product + Second Image
Second Product + ThirdImage
Third Product + FourthImage
The results I need:
Firt Product + First Image
Second Product + ThirdImage
Third Product + FourthImage
You can use something like this, but it's not the best option. With further knowlodge of your tables a better answer might be possible:
select products.*,
(
select image_name from images
where product_id = products.product_id
order by image_order asc
limit 1
) as 'image_name'
from products
WHERE products.published = 1
ORDER BY products.product_order ASC
Related
Looking to display results based on 'relevance' of the users search along with the price of the seller that ranks highest. A live example to what i'm after is Amazons search results, now I understand their algorithm is extremely complicated, but i'm after a simplified version.
Lets say we search for 'Jumper' the results that are returned are products related to 'Jumper' but then the price is not always the cheapest is based on the sellers rank. The seller with the highest rank gets his/hers prices displayed.
Heres what I have been working on but not giving me the expected results at mentioned above, and to be honest I don't think this is very efficient.
SELECT a.catalogue_id, a.productTitle, a.prod_rank, b.catalogue_id, b.display_price, b.sellers_rank
FROM
(
SELECT c.catalogue_id,
c.productTitle,
MATCH(c.productTitle) AGAINST ('+jumper*' IN BOOLEAN MODE) AS prod_rank
FROM catalogue AS c
WHERE c.catalogue_id IN (1, 2, 3)
) a
JOIN
(
SELECT inventory.catalogue_id,
inventory.amount AS display_price,
(accounts.comsn + inventory.quantity - inventory.amount) AS sellers_rank
FROM inventory
JOIN accounts ON inventory.account_id = accounts.account_id
WHERE inventory.catalogue_id IN (1, 2, 3)
) AS b
ON a.catalogue_id = b.catalogue_id
ORDER BY a.prod_rank DESC
LIMIT 100;
Sample Tables:
Accounts:
----------------------------
account_id | comsn
----------------------------
1 | 100
2 | 9999
Catalogue:
----------------------------
catalogue_id | productTitle
----------------------------
1 | blue jumper
2 | red jumper
3 | green jumper
Inventory:
-----------------------------------------------
product_id | catalogue_id | account_id | quantity | amount |
-----------------------------------------------
1 | 2 | 1 | 6 | 699
2 | 2 | 2 | 2 | 2999
Expected Results:
Product Title:
red jumper
Amount:
29.99 (because he/she has sellers rank of: 7002)
First, you should limit the results only to the matches for the first subquery:
Second, you should eliminate the second subquery:
SELECT p.catalogue_id, p.productTitle, p.prod_rank,
i.amount as display_price,
(a.comsn + i.quantity - i.amount)
FROM (SELECT c.catalogue_id, c.productTitle,
MATCH(c.productTitle) AGAINST ('+jumper*' IN BOOLEAN MODE) AS prod_rank
FROM catalogue AS c
WHERE c.catalogue_id IN (1, 2, 3)
HAVING prod_rank > 0
) p JOIN
inventory i
ON i.catalogue_id = c.catalogue_id join
accounts a
ON i.account_id = a.account_id
ORDER BY c.prod_rank DESC
LIMIT 100;
I'm not sure if you can get rid of the final ORDER BY. MATCH with JOIN can be a bit tricky in that respect. But only ordering by the matches should help.
I have one shop table and one item table. Shop table has many item, and my problem is I want to search multiple items that available in one shop.
shop table
id | name
---------
1 | Shop 1
2 | Shop 2
Item table
id | name | shop_id
----------------------
1 | JRC | 1
2 | sukhoy | 1
3 | sukhoy | 2
When I want to find item jrc and sukhoy, so it must showing Shop 1, because both two items are ready on Shop 1.
My expected output is
Output table
id | shopName | itemName
------------------------
1 | Shop 1 | JRC
2 | Shop 1 | sukhoy
My query is
select * from shops
inner join products as produk2 on produk2.shopId = shops.id and (produk2.name like "%sukhoy%")
inner join products as produk on produk.shopId = shops.id and (produk.name like "%jrc%")
It works because it using different alias per inner join.
But what I want is, how to combine the output from that 2 join without define different alias. Or how I can combine join result into one same column ?
I think this does what you want:
select p.shop_id
from products p
group by p.shop_id
having sum(p.name like '%jrc%') > 0 and
sum(p.name like '%sukhoy%') > 0;
This returns shop ids that have both products. Of course, you can join the results to shops to get more information about the shops.
You can just use one join:
select * from shops
inner join products as produk
on produk.shopId = shops.id
and (produk.name like "%jrc%" OR produk.name like "%sukhoy%")
I have these two tables:
prt_gebouw
id | name
----+------------
1 | Building A
2 | Building B
3 | Building C
prt_image
id | building_id | name | is_primary
----+---------------+-----------+------------
1 | 1 | img1.jpg | 0
2 | 1 | img2.jpg | 0
3 | 2 | img3.jpg | 0
4 | 1 | img4.jpg | 1
5 | 2 | img5.jpg | 1
As you can see here, some buildings have more than one image and some have none. When a building has one image or more, only one image can be marked as primary; can, for this is not mandatory.
Now, what I am trying to do is list all buildings (each building once) and join this with the images table, preferrably the primary image, empty cells if no image can be found.
So first I tried this:
SELECT
pgb.id,
pgb.name,
img.id AS image_id,
img.name AS image_name,
img.is_primary AS is_primary
FROM
prt_gebouw pgb
LEFT JOIN prt_image img ON pgb.id = img.object_id AND img.kind = 'object'
GROUP BY pgb.id
ORDER BY img.is_primary DESC, pgb.id ASC;
I suspect that the grouping is done before the ordering, because the wrong image is joined with each building that has more than one image ("wrong" being here: not the primary one).
Then I tried:
SELECT
pgb.id,
pgb.name,
img.id AS image_id,
img.name AS image_name,
img.is_primary
FROM
prt_gebouw pgb
LEFT JOIN (SELECT * FROM prt_image ORDER BY is_primary DESC) AS img ON img.object_id = pgb.id
ORDER BY pgb.id ASC;
I was hoping that for each building the primary image would be listed first, but not so. I suspect this is also the problem in the previous query, but is it?
And, more importantly, how can I solve this?
I think a correlated subquery might be easier for what you want:
select pgb.*,
(select i.id
from prt_image i
where i.object_id = pgb.id and i.kind = 'object'
order by is_primary desc
limit 1
) as img_id
from prt_gebouw pgb;
If you want the other fields from the image, join them in afterwards:
select pgb.*, i.* -- I'm using `*` for inconvenience; list the columns here
from (select pgb.*,
(select i.id
from prt_image i
where i.object_id = pgb.id and i.kind = 'object'
order by is_primary desc
limit 1
) as img_id
from prt_gebouw pgb
) pgb left join
prt_image i
on pgb.img_id = i.id;
I have this table structure (I made it myself, it is free to say if you think it is bad and give better example)
Several images can be found in one room which is mapped in the table image_room. Image_room looks like
image_id | room_id
1 | 1
2 | 1
3 | 1
4 | 2
5 | 3
6 | 4
Room with id 1 contains three images
I know guid from room table. How do I select all the image_name in a room based on the GUID number I know in MySQL?
Eg I know the guid XXX. With a select I want to find out that XXX has room_id 1 in the room table. My map table says that images 1, 2 and 3 are in that room.
The normal way to do this would use an explicit join:
select i.image_name
from room r inner join
image_room ir
on r.room_id = ir.room_id inner join
image i
on ir.image_id = i.image_id
where r.guid = #GUID;
You should declare your id columns to be primary keys, probably auto-incremented primary keys, for better performance.
try below:
select image_name from image where image_id in (select image_id from image_room where room_id in (select room_id from room where room_guid = 'xxx'))
Is it possible to make multiple queries at once within the same query?
Here is an example of what I'm trying to do.
We have the following table:
| userid | price | stock | description |
----------------------------------------
1 10.00 5 some text
2 25.00 2 some text
3 15.00 3 some text
4 35.00 2 some text
5 30.00 4 some text
The queries that I'm trying to do are:
the MIN and MAX price group by description
the price set by userid 2
Stock and price of the first three results only without grouping
So the HTML table will look like this:
description | Min_Price | Max_Price | Price Set by userid 2 | 1st Price | 1st Stock | 2nd Price | 2nd Stock | 3rd Price | 3rd Stock
This solution will require a number of "sub queries" or joins.
You are probably looking at something like:
select t1.description,
t1.min_price,
t1.max_price,
t2.user_id_2_price
from
(select description, min(price) as min_price, max(price) as max_price from t group by description) t1
left join
(select price, description as user_id_2_price from t where userid = '2') t2
on
(t1.description = t2.description)
And you can add as many of these "left joins" as you need
MySQL Unions (http://dev.mysql.com/doc/refman/5.0/en/union.html) should probably put you on the right track.
You could also do most of it with sub selects, though that is probably not a great idea.
Use union or, to have everything in one row, something like that:
Select
(Select min(price) from table) as min_price,
(Select max(price) from table) as max_price,
....