Where count is exact not more or less mysql - mysql

I have one_to_many relationship where i have 3 tables images, items and image_items .. every image may have one or many items, i wanna make a query where i pass the item/items id/ids and get a specific image (exactly one image) based on the count of items inside this image ...
Here is what i have tried so far but it has a problem, it gives me images with that count or more, i'm not sure if this logic or structure is valid in the first place:
SELECT `image_items`.`image_id`
FROM `image_items`
WHERE `image_items`.`item_id` IN(1, 2)
GROUP BY `image_items`.`image_id`
HAVING count(image_items.image_id) = 2
Here is the fiddle
Lets say image (1) has items (1,2,3), image (2) has items (1,3) and image (3) has items (1,2) .. lets say i want the image that has exactly (1,2) .. with my query even with distinct it gives me images (1,3) when i want only image (3).

Remove the WHERE clause and add in the HAVING clause a condition :
SELECT image_id
FROM image_items
GROUP BY image_id
HAVING
COUNT(DISTINCT item_id) = 2
AND
SUM(item_id NOT IN (1, 2)) = 0
See the demo.
Result:
| image_id |
| -------- |
| 4 |

Forpas's solution is a good solution. A slightly simpler having clause is:
SELECT image_id
FROM image_items
GROUP BY image_id
HAVING GROUP_CONCAT(item_id ORDER BY item_id) = '1,2';
If you are constructing this query in an application, this is simpler because you only need to pass in one value, the string '1,2'.

I hope you need to use DISTINCT in the HAVING clause as HAVING COUNT(DISTINCTimage_id) = 2 to get the exact count.
SELECT `image_id`
FROM `image_items`
WHERE `item_id` IN (1, 2)
GROUP BY `image_id`
HAVING COUNT(DISTINCT `image_id`) = 2

Related

Using GROUP BY to get the entry with the highest value

I need to create a product list with a preview image for each product.
I have a pretty simple data structure for products. One table is for the products, and one table for the images of a product. A product can have any number of images. The structure looks like this:
PRODUCT
id | name
1 Test Product A
2 Test Product B
3 Test Product C
PRODUCTIMAGE
id | productId | file | priority
1 1 foo.jpg 0
2 1 bar.jpg 1
3 2 something.png 1
4 2 yada.png 0
5 1 yougettheidea.gif 2
Pretty straight forward. The only thing worth mentioning about this is that productimages have a "priority", which is a TINYINT to determine the display order of images for a given product. The idea is: The higher the priority, the earlier the image should be displayed in the list of product images on the detail page. But for this product list that we are about to create, I'm only gonna need one preview image per product.
So as stated initially, my goal is to get a list of all products. So let's start pretty simple:
SELECT *
FROM product
Now I also want to display one preview image in the product page, so I need a little join:
SELECT `p`.*,
`pi`.`file` `previewImage`
FROM `product` `p`
LEFT JOIN `productImage` `pi` ON (`pi`.`productId` = `p`.`id`)
GROUP BY `p`.`id`
So far so good, this gives me one preview image per product to display on the product list. Just one more step to go: I want the preview image with the highest priority for each product as the preview image. So I tried to use a subquery to get the product images in the desired priority order:
SELECT `p`.*,
`pi`.`file` `previewImage`
FROM `product` `p`
LEFT JOIN (
SELECT *
FROM `productImage`
ORDER BY `priority` DESC
) `pi` ON (`pi`.`productId` = `p`.`id`)
GROUP BY `p`.`id`
But for some reason this doesn't (reliably) get me the product image with the highest priority for each product. Why is that? I think that GROUP BY is selecting the wrong productImage entry to keep, but why? Shouldn't it pick the first one, which due to the subquery should be the one with the highest priority?
Your group by is a partial group by. You are grouping by product.id so MySQL will group the result per product, but within each group it is free to return any row from productimage table. To get deterministic results, each column from that table needs to be wrapped inside aggregate functions (MIN, MAX, etc) but that will not give you the image with highest priority.
That being said, if you want only one column from the productimage table you can use a subquery inside select:
select product.*, (
select file
from productimage
where productimage.productid = product.id
order by priority desc
limit 1 -- this is the important bit
) as productimage_file
from product

Get a certain query result from two different mysql tables

Im having the following problem:
I try to implement an achievementsystem. I have two tables. Table 1 contains the achievement_id and achievement_info. Table 2 contains the link to the user, meaning achievement_id and player_id, so that you can tell which user has achieved certain things.
I'm trying to write a method that returns me all achievements, but additionally a flag that tells me if a certain user has achieved this row or not.
E.g.: getPlayerAchievements(playerid) --> returns a list of Achievements with id, info, and a bool flag whether the user has achieved it.
table 1:
achievement_id|achievement_info
1 |info1
2 |info2
3 |info3
table 2:
achievement_id|player_id;
1 |15
3 |15
the result I need by entering the player_id "15":
achievement_id|achievement_info|(bool)achieved
1 |info1 |true
2 |info2 |false
3 |info3 |true
I already have the achievement class so I just have to fill them with my data.
I could always use two seperate sql queries to achieve that, but I thought maybe there was a way to simplify it, since I use php to get my data and don't want two connections and queries in one php script.
You want to select all records from the achievemets table and show them. That's the easy part :-) For every record you want to show whether player 1234 has attained this achievement. You can do this with an EXISTS clause:
select
achievement_id,
achievement_info,
exists
(
select *
from players p
where p.player_id = 1234
and p.achievement_id = a.achievement_id
) as achieved
from achievements a;
Or even simpler with IN:
select
achievement_id,
achievement_info,
achievement_id in (select achievement_id from players where player_id = 1234) as achieved
from achievements;
You can use left join to get a complete list of achievements and the matching records from the user's achievements table:
select t1.achievement_id, t1.achievement_info, (t2.achievement_id is null) as achieved
from table1 t1
left join table2 t2 on t1.achievement_id=t2.achievement_id and t2.player_id=15

to fetch records by giving id and count or limit

I have two variable id and cnt.
If id = 5 and cnt=3,
then it shows three records from id=5 from xyz table.
My query:
select * from template_master
where status='active' LIMIT 3 OFFSET 5
But it is returning empty result though there are records.
Why you are using OFFSET 5?
Your query below says "return only 3 records, start on record 5.....
Try this:
select * from template_master
where status='active' and id >= 5
order by id asc LIMIT 3 OFFSET 0;
Use these query
SELECT * FROM template_master WHERE id > 5 order by id ASC LIMIT 3
i suppose that an ID must be primary key so you will take only ONE result searching for it (or zero if theres no record with this ID), we need to know your structure to answer you correctly.
i'll explain a basic example.
You wanna show 5 pictures about trees or 5 pictures about donuts if user click one or another button, ok so the database must be composed by 2 tables at least which are:
images (id, image, category);
categories (id, title);
Lets suppose that we want to show only trees, and lets suppose too that trees category id is 5. So your query must be:
SELECT i.image FROM images i, categories c WHERE i.category = c.id AND c.id = 5;
Am i explained well? Answer me if you have doubts, cheers! =)
SELECT *
FROM template_master
WHERE id=5 AND cnt=3
LIMIT 3;

Trying to determine differences in one column

I have 3 columns and I'm trying to determine the differences in one of the columns. Here is an example:
drug_id ndc item_id
1 12345678910 1234
1 12345678910 1235
There are multiple drug_id's and each drug_id has multiple ndcs. (A particular ndc could appear in multiple drug_ids). Essentially, I want to find where there is a difference in item_id based on the drug_id and ndc.
Any tips?
DISTINCT should work.
SELECT DISTINCT D.Drug_ID, D.ndc, D.item_id
FROM Table d;
If you're unfamiliar on SQL Predicates, you can learn more about them here for Access specifically.

SQL Query, get random row from a filtered selection

I use the following SQL query to get two random rows.
entry.sql
SELECT id, userID, img, points, votes
FROM entry
WHERE rotation = 1
ORDER BY RAND()
LIMIT 2
Now I would like to filter the possible rows. I do this here by rotation but I want more.
I have a second and a third table which look like this:
users.sql
ID | username
voted.sql
ID | userID | entryID | timestamp
I only want to get rows which the user hasn´t already voted on. So we should get all entryIDs for the user from voted.sql and make sure that the query above doesn´t pick them, how can I do this ?
Or would you save the data, in a different way, to make the already voted check easier ?
Use a join or subquery to do this, like:
SELECT id, user.userID, entry.img, entry.points, entry.votes
FROM entry
WHERE userID NOT IN (SELECT DISTINCT userID
FROM voted
WHERE userID = entry.userID);