I have two tables:-
gallery
gallery_favorite
The user_id in gallery table means the user who posted the item. The user_id in gallery_favorite means the user who added the item in his favorite list. If favorite = 0, then it means the user had initially added the item in favorite list but later removed it.
Now, I want to fetch all the gallery items along with its favorite status. Here is my query:-
Select distinct `gallery`.`id`, `gallery`.`caption`, `gallery`.`type`,
`gallery`.`video`, `gallery`.`image`, `gallery`.`type`,
`gallery`.`created_date`, `gallery`.`modified_date`,
`gallery_favorite`.`favorite`, `gallery`.`user_id`
from `gallery`
left join `gallery_favorite` on `gallery_favorite`.`gallery_id` = `gallery`.`id`
where
(`gallery`.`type` = 'i'
and `gallery`.`status` = 1
and `gallery`.`deleted` = 0)
and
((`gallery`.`user_id` != 11 and `gallery`.`private` = 0)
or `gallery`.`user_id` = 11)
limit 20 offset 0
But a syou can see, I am getting duplicate records depending upon the number of rows wrt to a gallery item in the gallery favorite table. How can I modify the query to get only one record (along with my own favorite status)?
I guess you are getting duplicate records because you have not joined both the table on user_id -
Try below query -
Select distinct `gallery`.`id`, `gallery`.`caption`, `gallery`.`type`,
`gallery`.`video`, `gallery`.`image`, `gallery`.`type`,
`gallery`.`created_date`, `gallery`.`modified_date`,
`gallery_favorite`.`favorite`, `gallery`.`user_id`
from `gallery`
left join `gallery_favorite` on `gallery_favorite`.`gallery_id` = `gallery`.`id`
and `gallery_favorite`.`user_id` = `gallery`.`user_id`
where
(`gallery`.`type` = 'i'
and `gallery`.`status` = 1
and `gallery`.`deleted` = 0)
and
((`gallery`.`user_id` != 11 and `gallery`.`private` = 0)
or `gallery`.`user_id` = 11)
limit 20 offset 0
Assuming the gallery as many favorites from different users. It makes no sense to display exclusively a hit favorite to a user and gallery alone. Counting them makes sense.
Select `gallery`.`id`, `gallery`.`caption`, `gallery`.`type`,
`gallery`.`video`, `gallery`.`image`, `gallery`.`type`,
`gallery`.`created_date`, `gallery`.`modified_date`,
sum(gallery_favorite`.`favorite`) as total_favorites -- count them group function aggregate
from `gallery`
left join `gallery_favorite` on `gallery_favorite`.`gallery_id` = `gallery`.`id`
where
(`gallery`.`type` = 'i'
and `gallery`.`status` = 1
and `gallery`.`deleted` = 0)
and
((`gallery`.`user_id` != 11 and `gallery`.`private` = 0)
or `gallery`.`user_id` = 11)
and gallery_favorite`.`favorite` = 1 -- count only the favorites
GROUP BY `gallery`.`id` -- GROUP CLAUSE
This is how a join works. You get all rows matching the condition. You can either group the result by the fields in the left table (thus eliminating duplicates in the output) or join with a table that has one entry per gallery item -- this requires joining with a (SELECT ... FROM gallery_favorite GROUP BY gallery_id)
Related
I want to obtain last update (max(bonus_records.id)) of the each bonus (bonus_records.uid - unique id) then meet this conditions:
that have never been redeemed by indicated player
that have been redemed by indicated player but then the redemption count is less than redeem_count
exceeded
The bonus redeemed and active at the said moment (is that bonus that has the fields completed and canceled at 0)
Additional information: If redeem_count is equal to 0, then there is no redemption limit for the said bonus
This is the database basic structure:
DB-FIDDLE
DB-FIDDLE v2 (With #Solarflare query)
DB-FIDDLE v3
My query that failing:
SELECT MAX(br1.id) /* Get last update of bonus */,
br1.uid,
br1.name,
rb1.instance_id,
rb1.player_id,
br1.redeem_count,
rb1.executed,
rb1.completed,
rb1.canceled
FROM
bonus_records br1
LEFT JOIN
redeemed_bonuses rb1 ON
rb1.bonus_id = br1.id
WHERE
(rb1.player_id IS NULL) OR /* never redeemed */
(rb1.player_id = 1 AND /* if redeemed then */
(
br1.redeem_count > ( /* total count of X redemed bonus is less then redeem_count but redeem_count <> 0 */
SELECT COUNT(*)
FROM redeemed_bonuses rb2
INNER JOIN bonus_records br2 ON rb2.bonus_id = br2.id
WHERE br2.uid = br1.uid AND rb2.completed = 0 AND rb2.canceled = 0
) OR
br1.redeem_count = 0 /* redeem_count = 0 means that there is no established limit of redeem */
)
)
GROUP BY
br1.uid
Expected result:
If i have this bonus list:
And this redeemed bonus list:
Then the expected outcome bonus list for player_id = 1 will be:
There are some problems in your query/logic:
select max(id), name, ... group by uid will not give you the row with the maximum id. It will give you the maximum id, and the values of any row that is in that group. If there is only one row per group (e.g. if uid is unique/the primary key), that might be the one you are looking for, otherwise it is not determined (and will fail for MySQL 5.7), see MySQL Handling of GROUP BY and any question on stackoverflow about an errormessage with sql_mode=only_full_group_by.
left join ... ON bonus_id = id where rb1.player_id IS NULL will be false if there is any player that has redeemed this bonusid. If you included the playerid in the on-condition, it would be true if the player would not have redeemed all different ids for a given uid (which is probably impossible).
something similar happens since you join via rb1.bonus_id = br1.id and apply your condition to this id (but not uid): if there is some old entry with a bigger redeem_count, it evaluates to true even if there is a latest id with a lower redeem_count (that won't be part of the group by, since you filtered it out).
instead, you probably would need to apply your filter after left join, e.g using group by ... having ... or select ... from (select ... group by ...) where ...
With this said, I won't fix your query (although it may be salvageable), but write you a new one with a new structure.
Breaking it into steps, first, get a list of all active bonuses:
select * from bonus_records br
where not exists
(select 1 from bonus_records br1
where br1.uid = br.uid and br1.id > br.id);
Next step is to check how often a specific uid has been redeemed by a specific player (the uid-information is obtained by checking the bonus_records-table):
select br.uid, count(*)
from redeemed_bonuses rb
join bonus_records br on br.id = rb.bonus_id
where rb.player_id = 1
and not (rb.completed = 0 and rb.canceled = 0)
group by br.uid;
The condition not (rb.completed = 0 and rb.canceled = 0) is adepted to fit the requirements according to the comments.
Now join those two and apply your conditions about the actual count being lower than redeem_count:
select pb.*, rd.actual_count from
(select * from bonus_records br
where not exists
(select 1 from bonus_records br1
where br1.uid = br.uid and br1.id > br.id)
) pb -- active potential bonuses
left join
(select br.uid, count(*) as actual_count
from redeemed_bonuses rb
join bonus_records br on br.id = rb.bonus_id
where rb.player_id = 1
and not (rb.completed = 0 and rb.canceled = 0)
group by br.uid
) rd -- redeemed bonuses by that user
on pb.uid = rd.uid
where rd.actual_count is null -- uid never redeemed (left join empty)
or rd.actual_count < pb.redeem_count -- still some remaining
or pb.redeem_count = 0 -- unlimited bonus
It was hard to come up with a good title for this one. I have a query selecting products from my table. Each product may belong to multiple categories. So when I add in the 'category' to my DISTINCT query, it sometimes returns multiple of the same product because that product belongs to more than one category. I want my query to just pick one of the categories and return that, doesn't matter which one.
Here is my query:
SELECT DISTINCT ci.NAME,
ci.pid,
ci.description,
ci.price,
ci.saleprice,
ci.ingredients,
ci.allergens AS allergens,
ci.isfood,
ci.quantity,
ci.ismostpopular,
ci.activedate,
ci.isfrozen,
cc.NAME AS category
FROM cart_category cc
JOIN cart_item_category cic
ON cc.id = cic.catid
JOIN cart_item ci
ON cic.itemref = ci.itemref
WHERE cc.active = 1
AND ci.active = 1
AND ci.isdeleted = 0
AND ci.isfrozen = 0
AND ( ci.NAME LIKE '%dark%'
OR ci.pid = '%dark%' )
AND ci.quantity > 5
AND cc.NAME <> "nutritionals";
When I add in cc.name as category is when it returns multiple of the same product.
try just to limit it:
... LIMIT 1
i am trying to write the Query for three things .My table structure is like that
You can see Schema at http://sqlfiddle.com/#!2/56c2d/1
I am trying to write the query in MYSQL
user:- table
user_id
user_fname
This is User tabke which will save User Information
group:- "group" and "subgroup" is maintain in same table using column "group_parent_group_id"
group_id
group_title
group_parent_group_id(INT)
This is group table which will save Group and Subgroups
user_group: table
user_group_id
user_group_user_id
user_group_group_id
This ill store both User and Group relation using their Id
I am trying to write the Query for three things. Fetching Users Groups, Subgroups
1) Query to fetch list of All Groups for User Register. Query is gelow and is giving error
Query:
select user.id, user.user_fname, group.group_id, group.group_title
from `user`
inner join user_group on user_group.user_group_user_id = user.user_id
inner join group on group.group_id = user_group.user_group_group_id
where user_group.user_group_user_id = 1 and user_group.group_parent_group_id = 0
2) I am Looking the query to fetch all subgroups(For Whom user is already Register) for Group Id 1,2 or 1
3) I am Looking the query to fetch all subgroups(For Whom user is Not Register yet) for Group Id 1,2 or 1. Ideal is for giving him randomly suggest a subgroup to add
Please Help. I am a newbie in DB :(
Your query is probably failing as you have a table called group, which is a reserved word. You can use back tics to delimit the name to get away with this (as follows) but it would be a better idea to change the table name.
SELECT user.id, user.user_fname, `group`.group_id, `group`.group_title
FROM `user`
INNER JOIN user_group ON user_group.user_group_user_id = user.user_id
INNER JOIN `group` ON `group`.group_id = user_group.user_group_group_id
WHERE user_group.user_group_user_id = 1
AND user_group.group_parent_group_id = 0
EDIT updated for queries I think the OP requires.
First query will get a list of all the groups (ones that have no parent group id) that a user (in this case id 28) is a member of
SELECT y2m_user.user_id, y2m_user.user_first_name, y2m_group.group_id, y2m_group.group_title
FROM y2m_user
INNER JOIN y2m_user_group ON y2m_user_group.user_group_user_id = y2m_user.user_id
INNER JOIN y2m_group ON y2m_group.group_id = y2m_user_group.user_group_group_id
WHERE y2m_user.user_id = 28
AND y2m_group.group_parent_group_id = 0
This query will get a list of all the sub groups (ones where the parent group id is greater than 0) that a user (in this case id 28) is a member of
SELECT y2m_user.user_id, y2m_user.user_first_name, y2m_group.group_id, y2m_group.group_title
FROM y2m_user
INNER JOIN y2m_user_group ON y2m_user_group.user_group_user_id = y2m_user.user_id
INNER JOIN y2m_group ON y2m_group.group_id = y2m_user_group.user_group_group_id
WHERE y2m_user.user_id = 28
AND y2m_group.group_parent_group_id > 0
This query will get a list of all the sub groups (ones where the parent group id is greater than 0) that a user (in this case id 28) is NOT a member of
SELECT y2m_user.user_id, y2m_user.user_first_name, y2m_group.group_id, y2m_group.group_title
FROM y2m_user
CROSS JOIN y2m_group
LEFT OUTER JOIN y2m_user_group ON y2m_user_group.user_group_user_id = y2m_user.user_id AND y2m_group.group_id = y2m_user_group.user_group_group_id
WHERE y2m_user.user_id = 28
AND y2m_group.group_parent_group_id > 0
AND y2m_user_group.user_group_id IS NULL
Please excuse any typos as not tested (with your test data there are no sub groups).
I have this query:
select pl.photo_id, pl.user_id, pl.liker_id, p1.filename user_filename, p2.filename liker_filename
FROM photo_likes pl
left join photos p1 on (pl.photo_id = p1.photo_id)
left join photos p2 on (pl.liker_id = p2.user_id and p2.avatar = 1)
where pl.user_id = $id order by pl.liker_id, pl.date_liked desc
It gets the correct data, but I would like to modify it to limit the data. So, in a nut shell, this query will get all the likes from all the people that liked a photo of theirs, it works great, this can grab lots of photos for each person. But I want to limit it to get only 5 from each person:
So, say user A likes 10 of my photos, user B likes 8 of my photos, and user C likes 2 of my photos, I only want the last 5 from user A, the last 5 from user B and the last 2 from user C. If that makes sense, how can this be done?
The query you have is good, but I'm wrapping that and using MySQL variables to check each return variable and increase the sequence per each "liker". When the liker changes, set the sequence back to 1.... Then, apply HAVING < 6 for the sequence. You can't do it in the WHERE clause because you want EVERY record to be QUALIFIED which keeps updating the #likeSeq and #lastLiker. Only AFTER that is done, the HAVING says... AFTER that, if the seq is greater than you 5 cap, it throws it out.
per alternate rows being included per your print-screens...
select
AllRanks.*
from
( select
PreQualified.*,
#likeSeq := if( PreQualified.Liker_ID = #lastLiker, #likeSeq +1, 1 ) as Seq,
#lastLiker := PreQualified.Liker_ID
from
( select
pl.photo_id,
pl.user_id,
pl.liker_id,
p1.filename user_filename,
p2.filename liker_filename
FROM
photo_likes pl
left join photos p1
on pl.photo_id = p1.photo_id
left join photos p2
on pl.liker_id = p2.user_id
and p2.avatar = 1
where
pl.user_id = $id
order by
pl.liker_id,
pl.date_liked desc ) PreQualified,
( select #lastLiker := 0,
#likeSeq := 0 ) sqlvars
) AllRanks
where
AllRanks.Seq < 6
Could you wrap your joined tables in a sub query?
select ...
from photo_likes
left join photos p1 ...
left join (select p2.filename liker_filename from photos where p1.liker_id = p2.user_id and avatar = 1 LIMIT 5) p2
where ...
Have seen multiple posts on this but I can't see any which answer my question.
Basically I have 3 tables in my database which relate to members and their categorisation/classification.
members (defines list of members and associated data)
member_taxonomy (defines categories, subcategories and facilities using combination of partent id and enumerated field tax_type (CATEGORY, SUBCATEGORY, FACILITY)
member_taxonomy_map (defines mapping between members and member_taxonomy)
I have a members page within which are a number of options to refine the search by specifying one or more subcategory and one or more facility. I have been trying to search on the table using the query:
SELECT members.*
FROM (members)
JOIN member_taxonomy_map ON member_taxonomy_map.member_id = members.id
WHERE member_taxonomy_map.taxonomy_id = 1
AND member_taxonomy_map.taxonomy_id = 26
AND members.active = 1
AND members.deleted = 0;
However this returns 0 rows which is something to do with having multiple where clauses on the same column but I can't figure out how this query should look. Each time the search is refined (and there could be up to 30 different options to refine the search) I need add an additional AND clause so that only members with these mappings are returned.
An IN clause will not work as this is effectively returning any rows which match any of these particular values but this is incorrect as it needs to match exactly the values specified.
Hopefully someone can give me a few pointers in the right direction.
Thanks in advance.
UPDATE
It is possible that taxonomy_id can be 1 and 26. I prob need to include the schema for the members_taxonomy_map table.
id int
tax_name varchar
slug varchar
tax_type enum ('CATEGORY','CLASSIFICATION','FACILITY','RATING')
parent_id int
active int
Therefore any tax_type with no parent id set are top level CATEGORY. Subcategories have a parent_id CATEGORY. CLASSIFICATION's can have a parent_id of the CATEGORY and FACILITY's have a parent_id of CATEGORY.
Therefore for example a category could be accommodation, sub-category could be hotel and facility could be wifi. Therefore if a member has all three of these items they will have 3 entries in the mapping table. I need to be be able to filter these so that it builds up the query to filter depending on the accommodation types (i.e subcategories - those entries with a tax_type of CATEGORY but also have a parent id, then within this the classifications. The query may return multiple entries for the same member but I can deal with this by filter these out with extra SQL clauses.
SELECT members.*
FROM (members)
JOIN member_taxonomy_map ON member_taxonomy_map.member_id = members.id
WHERE (member_taxonomy_map.taxonomy_id = 1
OR member_taxonomy_map.taxonomy_id = 26)
AND members.active = 1
AND members.deleted = 0;
It's probably not possible for a record to have a taxonomy_id of 1 and 26; you are probably trying to get a record that contains one or the other.
SELECT mb.*
FROM members mb
JOIN member_taxonomy_map tm ON tm.member_id = mb.id
WHERE tm.taxonomy_id IN ( 1, 26)
AND mb.active = 1
AND mb.deleted = 0
;
... Or ...
SELECT mb.*
FROM members mb
WHERE EXISTS ( SELECT *
FROM member_taxonomy_map tm
WHERE ON tm.member_id = mb.id
AND tm.taxonomy_id IN ( 1, 26)
)
AND mb.active = 1
AND mb.deleted = 0
;
... Or ...
SELECT mb.*
FROM members mb
WHERE mb.id IN ( SELECT tm.member_id
FROM member_taxonomy_map tm
WHERE tm.taxonomy_id IN ( 1, 26)
)
AND mb.active = 1
AND mb.deleted = 0
;
You need to JOIN member_taxonomy_map for every taxonomy_id
SELECT members.*
FROM members
JOIN member_taxonomy_map mtm1 ON mtm1.member_id = members.id AND mtm1.taxonomy_id=1
JOIN member_taxonomy_map mtm26 ON mtm26.member_id = members.id AND mtm26.taxonomy_id=26
WHERE members.active = 1
AND members.deleted = 0;