i want to modify this SQL statement to return only distinct rows of a column - sql

select
picks.`fbid`,
picks.`time`,
categories.`name` as cname,
options.`name` as oname,
users.`name`
from
picks
left join categories
on (categories.`id` = picks.`cid`)
left join options
on (options.`id` = picks.oid)
left join users
on (users.fbid = picks.`fbid`)
order by
time desc
that query returns a result that like:
my question is.... I would like to modify the query to select only DISTINCT fbid's. (perhaps the first row only sorted by time)
can someone help with this?

select
p2.fbid,
p2.time,
c.`name` as cname,
o.`name` as oname,
u.`name`
from
( select p1.fbid,
min( p1.time ) FirstTimePerID
from picks p1
group by p1.fbid ) as FirstPerID
JOIN Picks p2
on FirstPerID.fbid = p2.fbid
AND FirstPerID.FirstTimePerID = p2.time
LEFT JOIN Categories c
on p2.cid = c.id
LEFT JOIN Options o
on p2.oid = o.id
LEFT JOIN Users u
on p2.fbid = u.fbid
order by
time desc
I don't know why you originally had LEFT JOINs, as it appears that all picks must be associated with a valid category, option and user... I would then remove the left, and change them to INNER joins instead.
The first inner query grabs for each fbid, the FIRST entry time which will result in a single entity for the FBID. From that, it re-joins to the picks table for the same ID and timeslot... then continues for the rest of the category, options, users join criteria of that single entry.

2 options, you could write a group by clause.
Or you could write a nested query joined back to itself to get pertinent info.
Nested aliased table:
SELECT
n.fBids
FROM
MyTable t
INNER JOIN
(SELECT DISTINCT fBids
FROM MyTable) n
ON n.ID = t.ID
Or group by option
SELECT fBId from MyTable
GROUP BY fBID

select picks.`fbid`, picks.`time`, categories.`name` as cname,
options.`name` as oname, users.`name` from picks left join categories
on (categories.`id` = picks.`cid`) left join options on (options.`id` = picks.oid)
left join users on (users.fbid = picks.`fbid`)
order by time desc GROUP BY picks.`fbid`

select
picks.fbid,
MIN(picks.time) as first_time,
MAX(picks.time) as last_time
from
picks
group by
picks.fbid
order by
MIN(picks.time) desc
However, if you want only distinct fbid's you cannot display cname and other columns at the same time.

Related

Group by and Having aggregation

i'm trying to determine who is the largest scorer in a world cup group (this is a personal project)
I have the data but i'm having a hard time using count, group by and having in order to accomplish what i need.
I need to count messi's goals (top scorer) and group by each one of the groups so i get the highest scorer of each group.
For now i just have the joins:
select * from zonas
left join goles_zonas on (zonas.id = goles_zonas.Id_zona)
inner join goles on (goles.id = goles_zonas.id_gol)
inner join jugadores on (goles.id_jugador = jugadores.id)
instead displaying all columns (by using SELECT * ), in order to group the data, I find it necessary to do SELECT only certain columns which are considered to be the keys to determine the difference of each group of dataset to get the aggregation (in this case COUNT) of each dataset group
SELECT Id_zona, id_gol, id_jugador, COUNT(1) as number_of_goal
FROM zonas
left join goles_zonas on (zonas.id = goles_zonas.Id_zona)
inner join goles on (goles.id = goles_zonas.id_gol)
inner join jugadores on (goles.id_jugador = jugadores.id)
GROUP BY Id_zona, id_gol, id_jugador
It has to be grouped by all columns included the select statement that does not being aggregated.
but if you expect to display other columns as well which are not part of the grouping keys, you can do it like this
SELECT goles_zonas.* , x.* FROM (
SELECT Id_zona, id_gol, id_jugador, COUNT(1) as number_of_goal
FROM zonas
left join goles_zonas on (zonas.id = goles_zonas.Id_zona)
inner join goles on (goles.id = goles_zonas.id_gol)
inner join jugadores on (goles.id_jugador = jugadores.id)
GROUP BY Id_zona, id_gol, id_jugador ) X
LEFT JOIN goles_zonas on (x.id = goles_zonas.Id_zona)

Select last record out of grouped records

i have this code and i want someone to help me to change it to a grouped query which orders froms below.
SELECT *
FROM dbo.users_pics INNER JOIN profile
ON users_pics.email = profile.email
Left Join photo_comment
On users_pics.u_pic_id = photo_comment.pic_id
WHERE users_pics.wardrobe = MMColParam
ORDER BY u_pic_id asc
what i mean is i have grouped of records which i want to select one per record only from beneath. for example if i have 10 records of the name "John" i want to select the last "John" out of the 10 and then the rest also follows
I'm going to presume that your users table contains a single user, and each user has a single profile, and your photo_comment table can contain multiple comments.
Depending on your RDBMS, you can do this a number of ways. Row_Number can often be a quick way of doing this if you're using a database which supports window functions such as SQL Server or Oracle.
A generic solution to this is to join the table back to itself using the MAX aggregate. This is dependent on having a field to determine which record is the max. Generally speaking, that would be an identity/auto number field or a time stamp field.
Here is the basic concept using photo_comment_id as your determining column:
SELECT *
FROM dbo.users_pics INNER JOIN profile
ON users_pics.email = profile.email
LEFT Join (
SELECT pic_id, MAX(photo_comment_id) max_photo_comment_id
FROM max_photo_comment
GROUP BY pic_id
) max_photo_comment On users_pics.u_pic_id = max_photo_comment.pic_id
LEFT Join photo_comment On
max_photo_comment.pic_id = photo_comment.pic_id AND
max_photo_comment.max_photo_comment_id = photo_comment.photo_comment_id
WHERE users_pics.wardrobe = MMColParam
ORDER BY u_pic_id asc
If your database supports ROW_NUMBER, then you can do this as well (still using the photo_comment_id field):
SELECT *
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY photo_comment.pic_id
ORDER BY photo_comment.photo_comment_id DESC) rn
FROM dbo.users_pics INNER JOIN profile
ON users_pics.email = profile.email
LEFT JOIN photo_comment
ON users_pics.u_pic_id = photo_comment.pic_id
WHERE users_pics.wardrobe = MMColParam
) t
WHERE rn = 1
ORDER BY u_pic_id asc

sql left outer join with a constraining column

Here is the SQL, 'aal_county_zip' has entry for 2 zipcodes whereas 'us_zip' has 15 zipcodes. The requirement is to get 15 rows with only 2 rows having data from 'aal_county_zip'. It works like a normal join. How can I make change the SQL/Table structure to make this work. I also want to add the condition that is commented below.
SELECT DISTINCT a.zcta5ce10 AS zipcode,
c.report_year,
c.aal
FROM aal_county_zip c
RIGHT OUTER JOIN us_zip a
ON ( c.zip = a.zcta5ce10 )
WHERE Lower(c.name) = Lower('alachua')
--and c.report_year=2009
ORDER BY c.report_year DESC
The WHERE Lower(c.name) = Lower('alachua') in your query turns the outer join into an inner join, since it prevents c.name from being NULL.
Consider using a left join instead, as they're often more natural to write. And in any event, apply that condition to the join clause rather than to the where clause, so as to avoid turning it into an inner join.
Borrowing and amending #dasblinkenlight's query:
SELECT DISTINCT
a.zcta5ce10 AS zipcode
, c.report_year
, c.aal
FROM us_zip a
LEFT OUTER JOIN aal_county_zip c
ON c.zip = a.zcta5ce10
AND c.report_year=2009
AND LOWER(c.name) = LOWER('alachua')
ORDER BY c.report_year DESC
That should fix your "only two rows returned" problem. That said, the query is likely missing some additional criteria (and ordering criteria) on us_zip.
SELECT DISTINCT a.zcta5ce10 AS zipcode,
c.report_year,
c.aal
FROM aal_county_zip c
RIGHT OUTER JOIN us_zip a
ON ( c.zip = a.zcta5ce10 )
WHERE Lower(c.name) = Lower('alachua')
AND COALESCE(c.report_year, 2009)=2009
ORDER BY c.report_year DESC
or
SELECT DISTINCT a.zcta5ce10 AS zipcode,
c.report_year,
c.aal
FROM aal_county_zip c
RIGHT OUTER JOIN us_zip a
ON ( c.zip = a.zcta5ce10 AND c.report_year=2009)
WHERE Lower(c.name) = Lower('alachua')
ORDER BY c.report_year DESC
You're doing a RIGHT OUTER JOIN, so your first table, aal_county_zip, may contain nulls. So either you account for those nulls by using COALESCE, or you make it part of the join condition.

First() INNER JOIN

SELECT tblT.Tick, First(tblB.BDF) AS FirstOfBDF
FROM tblT INNER JOIN tblB ON tblT.Tick = tblB.Tick
GROUP BY tblT.Tick;
My Access table (tblB) is sorted by Tick and then by BDF. How come it does not retrieve the correct data?
There is no guarantee that table is sorted unless you explicitly mention Order by.
select top 1 tblT.Tick, First(tblB.BDF) AS FirstOfBDF
from FROM tblT INNER JOIN tblB ON tblT.Tick = tblB.Tick
GROUP BY tblT.Tick
Order by tblt.Tick ;

Left outer join and group by issue

I wrote a query. this query sum fields from 2 different table. And grouped by main table id field. But second left outer join is not grouped and giving me different results.
SELECT s.*,
f.firma_adi,
sum(sd.fiyat) AS konak,
sum(ss.fiyat) AS sponsor
FROM fuar_sozlesme1 s
INNER JOIN fuar_firma_2012 f
ON ( s.cari = f.cari )
LEFT OUTER JOIN fuar_sozlesme1_detay sd
ON ( sd.sozlesme_id = s.id )
LEFT OUTER JOIN fuar_sozlesme1_sponsor ss
ON ( ss.sozlesme_id = s.id )
GROUP BY s.id
ORDER BY s.id DESC
I know, it is really complicated but I'm stucking on this issue.
My question is: why second left outer join is not correctly sum of field . If I remove second left outer join or first, everything is normal.
The problem is that you have multiple dimensions on your data, and the number of rows is multiplying beyond what you expect. I would suggest that you run the query for one id, without the group by, to see what rows the join is producing.
One way to fix this is by using correlated subqueries:
select s.*, f.firma_adi,
(select SUM(sd.fiyat)
from fuar_sozlesme1_detay fd
where sd.sozlesme_id = s.id
) as konak,
(select SUM(ss.fiyat)
from fuar_sozlesme1_sponsor ss
where (ss.sozlesme_id = s.id)
) as sponsor
from fuar_sozlesme1 s inner join
fuar_firma_2012 f
on (s.cari = f.cari)
order by s.id DESC
By the way, you appear to by using MySQL (because your query is not parsable in any other dialect). You should tag your questions with the version of the database you are using.