sql left outer join with a constraining column - sql

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.

Related

Left Outer Join Without Duplicate Rows

After a lot of searching I could not solve my problem. I have the following tables:
I want to select all records from my 'product' table. but I have a problem. I got multiple rows from 'product' table when I execute the following query:
SELECT dbo.product.id, dbo.product.name, dbo.product_price.value
dbo.product_barcode.barcode
FROM dbo.product LEFT OUTER JOIN
dbo.product_price ON dbo.product.id = dbo.product_price.product_id LEFT OUTER JOIN
dbo.product_barcode ON dbo.product.id = dbo.product_barcode.product_id
My problem was solved with the following query:
SELECT dbo.product.id, dbo.product.name, dbo.product_price.value
dbo.product_barcode.barcode
FROM dbo.product LEFT OUTER JOIN
dbo.product_price ON dbo.product.id = dbo.product_price.product_id LEFT OUTER JOIN
dbo.product_barcode ON dbo.product.id = dbo.product_barcode.product_id
WHERE (dbo.product_price.id IN
(SELECT MIN(id) AS minPriceID
FROM dbo.product_price AS product_price_1
GROUP BY product_id)) AND (dbo.product_barcode.id IN
(SELECT MIN(id) AS Expr1
FROM dbo.product_barcode AS product_barcode_1
GROUP BY product_id))
Now I have just one problem. if the 'product_price' table or 'product_barcode' table does not have any record, No records will be returned. I mean if no similar record is found in 'product_price' or 'product_barcode' table, we will not have any record. while we should have records from the 'product' table with null columns of other tables.
Please help me Thanks.
I think the problem is that the conditions are in the WHERE clause - try moving the conditions from the WHERE clause and into each join:
SELECT dbo.product.id, dbo.product.name, dbo.product_price.value,
dbo.product_barcode.barcode
FROM dbo.product
LEFT OUTER JOIN dbo.product_price ON dbo.product.id = dbo.product_price.product_id
--moved from WHERE clause
AND dbo.product_price.id IN (SELECT MIN(id) AS minPriceID FROM dbo.product_price AS product_price_1 GROUP BY product_id)
LEFT OUTER JOIN dbo.product_barcode ON dbo.product.id = dbo.product_barcode.product_id
--moved from WHERE clause
AND dbo.product_barcode.id IN (SELECT MIN(id) AS Expr1 FROM dbo.product_barcode AS product_barcode_1 GROUP BY product_id)
SELECT dbo.product.id, dbo.product.name, MIN(dbo.product_price.value),MIN( dbo.product_barcode.barcode)
FROM dbo.product
LEFT OUTER JOIN dbo.product_price ON dbo.product.id = dbo.product_price.product_id
LEFT OUTER JOIN dbo.product_barcode ON dbo.product.id = dbo.product_barcode.product_id
GROUP BY dbo.product.id, dbo.product.name
While the above query should achieve your desired results - one entry for product with the minimun product_price (if one exist) and minimum product_barcode (if one exist).
I only assumed you wanted this based on the query you were writing. You need to spend more time thinking about the question you are trying to answer.
Joining will multiply your results if more than one entry per join key is present in one of the tables.
Just remember this diagram:
When you are calling LEFT JOIN and applying filtering like in the second picture from the top left, you will get only items belonging to the A table.
I want to select all records from my 'product' table. but I have a problem. I got multiple rows from 'product' table when I execute the following query:
Can you try calling DISTINCT after SELECT, like this:
SELECT DISTINCT dbo.product.id, dbo.product.name, dbo.product_price.value
dbo.product_barcode.barcode
...

how can I get the selected columns fully and the sum column separately

SELECT f_name,l_name,teachers.first_name,teachers.t_id,p_id,paid_amount,family_id,date,sum(payments.paid_amount)
FROM payments
LEFT JOIN family ON family.id = payments.family_id
LEFT JOIN teachers ON family.teacher_id = teachers.t_id
How can I get the selected columns fully and the sum column separately?
because that sum function makes all the selected result one row
SELECT f_name,l_name,teachers.first_name,teachers.t_id,p_id,paid_amount,family_id,date
FROM payments
LEFT JOIN family ON family.id = payments.family_id
LEFT JOIN teachers ON family.teacher_id = teachers.t_id
This query is working fine without the sum column
You didn't tell the database, which column to use for aggregating the data. Don't know which database you are using, but some complain, that there is no GROUP BY statement in the SQL text.
Please try with the following query:
SELECT f_name,l_name,teachers.first_name,teachers.t_id,p_id,paid_amount,family_id,date,sum(payments.paid_amount)
FROM payments
LEFT JOIN family ON family.id = payments.family_id
LEFT JOIN teachers ON family.teacher_id = teachers.t_id
GROUP BY f_name,l_name,teachers.first_name,teachers.t_id,p_id,paid_amount,family_id,date
GROUP BY tells the database, which are the key columns in the aggregation.
If you want all the payments, use a subquery or join:
SELECT f_name, l_name, t.first_name, t.t_id, p.p_id, p.paid_amount, p.family_id, date,
(select sum(p.paid_amount) from payments) as all_paid
FROM payments p LEFT JOIN
family f
ON f.id = p.family_id LEFT JOIN
teachers t
ON f.teacher_id = tetchers.t_id;
SELECT f_name,l_name,t.first_name,t.t_id,p_id,paid_amount,family_id,date,sum(p.paid_amount)
FROM payments p,family f,teachers t where f.id = p.family_id and f.teacher_id = t.t_id
Group by f_name,l_name,teachers.first_name,teachers.t_id,p_id,paid_amount,family_id
You can add date column also in Group by expression based on your requirement. Example:
f_name,l_name,teachers.first_name,teachers.t_id,p_id,paid_amount,family_id,date

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.

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

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.