Alright this is my situation:
I have 2 tables: photos, gallery.
I just want to show all galleries with one photo from each gallery, but I have in photos(TABLE) column title_photo.
I want to show that image, which has title_photo='y' of course some images from other gallery doesn't have it(They have title_photo = 'n'). I have this sql
SELECT * FROM photos
RIGHT JOIN gallery
ON gallery.code = photos.gallery_code
WHERE photos.title_photo = 'y'
GROUP BY gallery.id
I have 4 galleries and in only one I set in row (photos TABLE) title_photo = 'y'. That sql shows only
one gallery, which has in photos(TABLE) set title_photo = 'y'.
My question is:
Is there any solution to show other galleries(they have photos.title_photo = 'n') and show gallery which has title_photo = 'y'?
It seems you want the "first" photo in each gallery, where "first" is defined by the value 'y' in title_photo if that is present. If a gallery has no title photo, we'll use the photo with the smallest photo.id in that gallery as the "first".
For starters, we need to find the pseudo-id for the "first" photo in each gallery. Let's try this:
SELECT photos.gallery_code,
MIN(photos.id + (100000000 * photos.title_photo <> 'y')) AS pseudoid
FROM photos
GROUP BY photos.gallery_code
This gives us either a single genuine photos.id, or one that's one hundred million too large, for each gallery. Next we need to turn that back into a usable photo id, like so.
SELECT gallery_code, (pseudoid MOD 100000000) AS id
FROM (
SELECT photos.gallery_code,
MIN(photos.id + (100000000 * photos.title_photo <> 'y')) AS pseudoid
FROM photos
GROUP BY photos.gallery_code
) AS firsts
Next, we need to join that list of first photos to the photos and gallery table.
SELECT p.whatever, g.whatever
FROM (
SELECT gallery_code, (pseudoid MOD 100000000) AS id
FROM (
SELECT photos.gallery_code,
MIN(photos.id + (100000000 * photos.title_photo <> 'y')) AS pseudoid
FROM photos
GROUP BY photos.gallery_code
) AS firsts
) AS f
JOIN gallery AS g ON f.gallery_code = g.code
JOIN photos AS p ON f.id = p.id
ORDER BY (whatever you need here)
See what we're doing here? We're using a query to generate the gallery/first-photo relationship using the specified logic.
Then we're employing that as a subquery (virtual table). We're joining it to the two data tables to retrieve the information we need, just for those first photos.
Pro-tip: Don't use SELECT * in application software. Be specific about the columns you need in your result sets.
Pro-tip: Don't use the nonstandard MySQL extension to GROUP BY unless you're really expert. http://dev.mysql.com/doc/refman/5.5/en/group-by-extensions.html
Related
I have two tables : galleries and shared galleries.
Structure of galleries: (for storing images of individual students. One student contains multiple images)
id, student_id, classroom_id, image
Structure of shared_galleries: (for storing images which are common to all students in a classroom. One classroom contains many images):
id,classroom_id,image
Other than these two tables I have students table and classrooms table. Students table store the classroom_id.
I need to get a query so that I can display the images stored in 'galleries' for a student and those stored in shared gallery of the classroom in which that student belongs in a single page. How can I achieve this ? Something like this returns duplicated results :
select galleries.id as gid,
shared_galleries.id as sid,
galleries.student_id, galleries.classroom_id
from galleries
inner join shared_galleries on galleries.classroom_id=shared_galleries.classroom_id
where galleries.student_id=31 and galleries.classroom_id=28
You will need to join the student to the shared_galleries along the relations to get the right results
SELECT
g.image AS image,
0 AS is_shared
WHERE
g.student_id = :student_id
FROM
galleries AS g
UNION
SELECT
sg.image AS image,
1 AS is_shared
FROM
shared_galleries AS sg
LEFT JOIN classrooms AS c ON c.id = sg.classroom_id
LEFT JOIN students AS s ON s.classroom_id = c.id
WHERE
s.id = :student_id
This should give you all the images for a student with :student_id,
I've also added the is_shared column in case you need to know the origin of the image
Since your images are stored on a per-record basis (in both galleries and shared galleries, using a JOIN is not needed. Use a UNION instead:
SELECT
galleries.id AS ID,
galleries.student_ID AS StudentID,
galleries.classroom_id as ClassroomID,
galleries.image as Image
WHERE
galleries.student_id = 31
UNION
SELECT
shared_galleries.id AS ID,
NULL AS StudentID,
shared_galleries.classroom_id as ClassroomID,
shared_galleries.image as Image
WHERE
shared_galleries.classroom_ID = 31
This will produce a list of records, with each record containing one image (since the number of images per student and the number if images per classroom is never consistent)
If you want do a little extra and ensure that your classroom images are always linked to the correct student, then declare a variable at the beginning to set the student_id value, and then use it in the second SELECT statement.
For the query i need to do, a user uploads videos onto an album, on their video page, it has the list of albums, and the total of videos below it.
Currently, what i am trying to do is a union, however this is not working, this is my code:
$query="SELECT albname, albcover, lid, NULL as vidcount FROM albums WHERE USERID='".mysql_real_escape_string($USERID)."' and verified='1'
UNION
SELECT NULL as albname, NULL as albcover, NULL as lid, count(*) as vidcount FROM albs_vids A LEFT JOIN albums B USING(ALBID) WHERE B.USERID='".mysql_real_escape_string($UID)."'";
So, what happens is the SQL query needs to find the data of the album, ie albname, albcover and lid from the table albums. Then find the amount of videos in the table albs_vids which correspond to the album. The album is specified by ALBID in both tables.
Hard to completely understand what you're asking ,but this will give you the count of videos for each album that has your userid:
$sql = "SELECT a.albname, a.albcover, a.lid, COUNT(*) AS vidcount
FROM albums AS a
LEFT JOIN albs_vids AS b ON b.albid = a.albid
WHERE b.userid='".mysql_real_escape_string($UID)."'
GROUP BY a.albname";
I have two table for gallery system :
gallery_cat(
gallery_cat_id PK,
gallery_cat_name
)
gallery(
gallery_id PK,
gallery_cat_id FK,
gallery_name,
gallery_file_name,
gallery_date
)
I need to write a SQL query that return one picture from gallery table for each album, the purpose of this that I need to list the albums with one picture for each.
gallery_name | gallery_cat_name| gallery_file_name
-------------+-----------------+------------------
pic1 | Album1 | pic1.jpg
This should do the trick:
SELECT g2.gallery_name, gc2.gallery_cat_name, g2.gallery_file_name
FROM gallery g2
INNER JOIN gallery_cat gc2 ON (g2.gallery_cat_id = gc2.gallery_cat_id)
WHERE g2.gallery_id IN (
SELECT g.gallery_id
FROM gallery g
GROUP BY g.gallery_cat_id)
Explanation:
At the end is a sub-select
IN (
SELECT g.gallery_id
FROM gallery g
GROUP BY g.gallery_cat_id) <<-- select 1 random g.id per gallery_cat.
Here I select all g.id, but because of the group by clause it will reduce the results to 1 row per grouped by item. I.e. 1 row (chosen more or less at random) per g.gallery_cat_id.
Next I do a normal select with a join:
SELECT g2.gallery_name, gc2.gallery_cat_name, g2.gallery_file_name
FROM gallery g2
INNER JOIN gallery_cat gc2 ON (g2.gallery_cat_id = gc2.gallery_cat_id)
WHERE g2.gallery_id IN (
Because I refer to the same table twice in the same query you have to use an alias(*).
I select all names and all catnames and all filenames.
However in the where clause I filter these so that only rows from the sub-select are shown.
I have to do it this way, because the group by mixes rows into one messed up ow, if I select from that directly I will get values from different rows mixed together, not a good thing.
By first selecting the id's I want and then matching full rows to those id I prevent this from happening.
*(in this case with this kind of subselect that's not really 100% true, but trust me on the point that it's always a good idea to alias your tables)
This attempts to select the most recent gallery_date for each category ID and join against gallery_cat
SELECT
c.gallery_cat_id,
c.gallery_cat_name,
i.lastimg
FROM
gallery_cat c
LEFT JOIN (
SELECT gallery_cat_id, gallery_filename AS lastimg, MAX(gallery_date)
FROM gallery
GROUP BY gallery_cat_id, gallery_filename
) i ON c.gallery_cat_id = i.gallery_cat_id
You can use SQL JOINS to do this, otherwise you would have to loop out all the albums and pick one random picture from each which would be less efficient.
I have three tables.They are
tb_albums---->id,title, description
tb_photos---->id,album_id, photo
tb_tags---->id,album_id, tag
Here i want to get the albums details and it photos & it tags through tb_albums.id.
How to use join query here?
Normally, you can use as many tables in JOIN, as you'd like. Just add another JOIN statement. You can refer to k102's answer for the correct syntax (which doesn't produce correct result though).
But in this particular case you don't want to use simple JOIN on all tables, unless you have only one photo per album and only one tag per album. If you have more than one photo per and more than one tag per album, JOIN both tables on album_id in single query will produce Cartesian product of both, in other words all possible combinations of tags and photos from each albums. For N photos and M tags that's N * M results, instead of N + M.
Also, there is no point of joining with tb_albums, as you do not need to repeat information about each album for each photo and each tag.
Proper approach would be to have 3 separate simple SELECTs from each table and combining their result on application level.
If for some awkward reason you'd need to do that with one query, you can do something like:
SELECT * FROM tb_albums as A JOIN
(SELECT 'photo', id, photo as value FROM tb_photos
UNION ALL
SELECT 'tag', id, tag as value FROM tb_tags) as B ON B.album_id = A.id
Note, this is way less optimal than separate SELECTs, you should only do this if you have no other choice.
select * from tb_albums a
join tb_photos p on a.id = p.album_id
join tb_tags t on a.id = t.album_id
I am trying to make a photo album system in php and mysql.
I have this code for list all photo albums:
SELECT albums.*, count(pictures.id) AS countpic
FROM albums
LEFT JOIN pictures ON (albums.id=pictures.album_id)
GROUP BY albums.id
ORDER BY albums.date DESC");
I want to list title of photo albums with photo thumbnails (thumb_id si written in table pictures) and also with number of all pictures assigned to each albums.
Dont you know how to select thumb_id and also number of all pictures in album by using one select?
Thanks
Does adding group_concat(pictures.thumb_id) to the select list do what you need?
This would work if for each album there is a single image with is_thumb=1.
SELECT
albums.*,
count(pictures.id) AS countpic,
group_concat(pictures.thumb_id) ids,
group_concat(case when picture.is_thumb then pictures.thumb_id else '' end separator '') thumb
FROM albums
LEFT JOIN pictures ON (albums.id=pictures.album_id)
GROUP BY albums.id
ORDER BY albums.date DESC");