Ambiguity in an SQL query involving two joins - mysql

I have three tables that are structured as follows:
results:
id | url_id
foo
id | url_id | url
bar
id | url_id | url
I want to be able to select the URL in a single query knowing that it could be in either table.
My plan was to do a LEFT JOIN on both of the tables and then return something like IFNULL(foo.url, bar.url) as url.
It is important that the result is called url.
However, I cannot use this same url column name in my WHERE clause because of the ambiguity. Here is my query and the error message I get:
SELECT r.id,
COALESCE(foo.url, bar.url) as url
FROM results r
LEFT JOIN foo USING (url_id)
LEFT JOIN bar USING (url_id)
WHERE url IS NOT NULL;
Column 'url' in where clause is ambiguous
It would be fairly trivial to select the column under a different name and rename it in my code, but it would be nicer to do it in SQL.
Here is an SQL Fiddle: http://sqlfiddle.com/#!9/32abc6/4
Cheers

You cannot use an alias name declared in the SELECT clause in your WHERE clause, because WHERE happens before SELECT.
Hence:
SELECT r.id, COALESCE(foo.url, bar.url) as url
FROM results r
LEFT JOIN foo USING (url_id)
LEFT JOIN bar USING (url_id)
WHERE COALESCE(foo.url, bar.url) IS NOT NULL;
or
SELECT r.id, COALESCE(foo.url, bar.url) as url
FROM results r
LEFT JOIN foo USING (url_id)
LEFT JOIN bar USING (url_id)
WHERE foo.url IS NOT NULL OR bar.url IS NOT NULL;

The direct answer to your question is to use table aliases when referring to columns. I would write this as a series of left joins:
SELECT
r.id,
r.url_id,
COALESCE(f.url, b.url) AS url
FROM results r
LEFT JOIN foo f
ON r.url_id = f.url_id
LEFT JOIN bar b
ON r.url_id = b.url_id;
This answer assumes that the actual url match could be in either table, or, if it matches to both, then you don't mind taking the version from the foo table.

Your error suggests to use table alias if same column name available with more than one table :
select f.id, ifnull(b.url, f.url) as url
from foo f left join
bar b
on b.id = f.id
where f.url_id = ?;
This answers your -> Column 'url' in where clause is ambiguous error, JOINs may not same as you want if so then adjust the on clause or provide one other conditions with JOIN. But the idea would be same to use alias to make it easier to understand the query or to compiler.

if you want url on where you can use sub-query cause your both table has url column but you make one so either you have to use table.column name in where
select * from
(
SELECT r.id,
COALESCE(foo.url, bar.url) as url
FROM results r
LEFT JOIN foo USING (url_id)
LEFT JOIN bar USING (url_id)
)as t where t.url is NOT NULL

So you have
SELECT ..., IFNULL(foo.url, bar.url) AS url
...
WHERE url LIKE ? *** Error: "url" ambiguous
The sorry solution is to use:
SELECT ..., IFNULL(foo.url, bar.url) AS url
...
WHERE IFNULL(foo.url, bar.url) LIKE ?
It should not be less efficient. It is what one pays.
Maybe the following would work:
SELECT ..., z.url
FROM (SELECT IFNULL(foo.url, bar.url) AS url FROM DUAL AS z)
JOIN ...
WHERE z.url LIKE ?
Introducing a table alias for disambiguation.

Related

Left join with calculated column and different schemas?

I would like to perform a left join on the following tables:
Vehicles.boats,
vehicle_details.colors
With columns
vehicles.boats.yacht
color_id
where color_id is computed from vehicle_details.colors in a calculation that involves
vehicle_details.colors.sequence
and
vehicle_details.colors.name
I assume the following would serve as my skeleton, but I am unsure of where to put the calculations that define color_id:
SELECT vehicles.boats.yacht, vehicle_details.colors.sequence
FROM vehicles.boats
LEFT JOIN vehicle_details.colors
ON vehicle.boats.colorIdentifier = color_id;
Would it be something like the following, where the calculation is used in the ON portion?
SELECT vehicles.boats.yacht, vehicle_details.colors.sequence
FROM vehicles.boats
LEFT JOIN vehicle_details.colors
ON vehicle.boats.colorIdentifier = *calculations* AS color_id;
In that format you need to do the calculation twice, once for the join condition, once for the display.
SELECT vehicles.boats.yacht, vehicle_details.colors.sequence,*calculations* AS color_id;
FROM vehicles.boats
LEFT JOIN vehicle_details.colors
ON vehicles.boats.colorIdentifier = *calculations*;
You could use a subquery and do it once, something like:
SELECT vehicles.boats.yacht, vehicle_details.colors.sequence, color_id;
FROM vehicles.boats
LEFT JOIN ( Select vehicle_details.colors, *calculations* as colour_id from vehicle_details) as Details_subquery
ON vehicles.boats.colorIdentifier = colour_id ;

How to use a self join on this table instead of the subquery being used when a concatenation is taking place?

I have the following query
Select DISTINCT a.code,a.Code_group,a.value,a.code_auth FROM AEO.CODE_CM a WHERE a.CODE_GROUP IN
(SELECT CONCAT (b.code,'_PART') FROM AEO.CODE_CM b WHERE b.CODE_GROUP ='EPE_AUTHTYPE');
So based on the code_group value it receives it picks each code and concatenates the string to it and returns it as a code_group. I need to avoid using subquery to make it less complex and since its the same table I tried to use self join as
Select DISTINCT a.code,a.Code_group,a.value,a.code_auth FROM AEO.CODE_CM a INNER JOIN AEO.CODE_CM b
ON a.code_group =b.code_group WHERE a.code_group = CONCAT(b.code,'_PART') AND b.code_group ='EPE_AUTHTYPE';
But I am getting a blank result in this case
The queries are not equivalent, since you have wrong additional a.code_group = b.code_group predicate in the 2-nd query.
It should be something like this:
WITH AEO_CODE_CM (CODE, CODE_GROUP) AS
(
VALUES
('code1', 'EPE_AUTHTYPE')
, ('code2', 'code1_PART')
)
Select DISTINCT a.code, a.Code_group
FROM AEO_CODE_CM a
/*
WHERE a.CODE_GROUP IN
(
SELECT CONCAT (b.code,'_PART')
FROM AEO_CODE_CM b
WHERE b.CODE_GROUP ='EPE_AUTHTYPE'
)
*/
--/*
JOIN AEO_CODE_CM b ON a.code_group = CONCAT(b.code,'_PART')
WHERE b.code_group ='EPE_AUTHTYPE'
--*/
;

SQL query result within IN

SELECT ids_horarios_adicionales from adicionales WHERE id_adicionales=1
So this query returns as result 1,3, the row ids_horarios_adicionales will contain ids separated with commas.
What im intending to do is this:
SELECT *
FROM adicionales a
LEFT JOIN horarios b ON b.id_horarios IN (1,3)
WHERE id_adicionales=1
but when I use this query, results are not the same:
SELECT *
FROM adicionales a
LEFT JOIN horarios b ON b.id_horarios IN (SELECT ids_horarios_adicionales from adicionales WHERE id_adicionales=1)
WHERE id_adicionales=1
any idea how to make SELECT query inside IN() to print as 1,3
This is the schema and sql query result I want, any other approach sugested will be helpful: http://sqlfiddle.com/#!9/714a50/2
You should not be storing values in a comma-separated list. That is the problem you are facing. I would recommend figuring out how to change your data structure.
But, sometimes, you are stuck with other people's really bad designs (such as storing integer values in strings). In that case, you can use find_in_set():
SELECT *
FROM adicionales a LEFT JOIN
horarios h
ON EXISTS (SELECT 1
FROM adicionales a2
WHERE find_in_set(h.id_horarios , a2) > 0 AND
a2.id_adicionales = 1
)
WHERE id_adicionales = 1
you can use FIND_IN_SET by this way
SELECT *
FROM adicionales a
LEFT JOIN horarios b ON
FIND_IN_SET(a.ids_horarios_adicionales,b.id_horarios)
WHERE id_adicionales=1
I'm not sure of your schema but in general when using LEFT JOIN you need to detail how the join between the tables us done. For example, LEFT JOIN horarios b ON b.index = adicionales.index and then use the where statement to limit rows

mysql syntax for IFNULL with subquery

I want to use subquery inside of IFNULL statement
SELECT t.col1
, IFNULL(t.col2, (SELECT an.col_11
FROM another_table an
WHERE an.col1 = t.col5)) as alias_name
, t.col3
FROM table t;
In IFNULL statement second expression should be subquery.
Please give me proper syntax
My actual query is
SELECT u.username, up.gender, d.name, desg.name,
IFNULL(up.creative_lead_id,
(SELECT au.username FROM auth_user au
WHERE au.id=up.creative_lead_id)) as creative_lead, up.image
FROM user_profile up, department d, designation, auth_user
WHERE up.department_id=d.id
AND up.designation_id = desg.id up.auth_uesr_id = u.id;
This query is giving syntax error because of IFNULL statement.
You can rewrite your query with join,Correlated query will execute for each row in your table and it might affect the performance
SELECT
t.col1,
IFNULL(t.col2, an.col_11) AS alias_name,
t.col3
FROM
`table` t
LEFT JOIN another_table an
ON an.col1 = t.col5
Don't use a subquery for this situation, try a query like that instead (use of jointure):
SELECT t.col1
,IFNULL(t.col2, an.col_11) AS alias_name
,t.col3
FROM your_table t
LEFT JOIN another_table an ON an.col1 = t.col5
In your full query, your using twice up.creative_lead_id for your IFNULL clause (once as first parameter and then in the subquery). That make no sense because if the first param is NULL, your subquery will return no result!
In order to show you the principe that will solve your problem, i just replaced the first param by a fictive one that i called up.creative_lead. This fictive column is the name of the creative lead stored in your table user_profile and if this value is null, i'm looking to the username of the user corresponding to creative_lead_id.
Here is the full query that'll solve your problem with the correction mentioned above:
SELECT u.username
,up.gender
,d.name
,desg.name
,IFNULL(up.creative_lead, cl.username) AS creative_lead
,up.image
FROM user_profile up
INNER JOIN department d ON d.id = up.department_id
INNER JOIN designation desg ON desg.id = up.designation_id
INNER JOIN auth_user u ON u.id = up.auth_user_id
INNER JOIN auth_user cl ON cl.id = up.creative_lead_id
Notice that i changed the syntax of your query, it's highly recommended to avoid the use of old syntax for jointures (use explicit JOIN clause instead).
Hope this will help you.

MySQL: why does GROUP_CONCAT lose rows in my multiple join query?

I'm trying to fetch all the rows from table_m which also have an index in table_mi and I'm expecting to get 2 rows as a result (with m.id=3 and m.id=9) - but if I add GROUP_CONCAT to my select then I only get one row returned. Am I having a misshap somewhere within those joins of mine?
Query:
SELECT
m.id,
m.name,
m.keyword,
IFNULL(GROUP_CONCAT(r.keyword),'TEST') AS restrictions
FROM
table_m AS m
INNER JOIN
table_mi as mi ON m.id=mi.m_id
LEFT JOIN
table_ri as ri ON m.id=ri.m_id
LEFT JOIN
table_r AS r ON ri.r_id=r.id
WHERE
(
m.id>0
AND m.active=1
AND mi.p_id=0
AND (mi.pa_id="11" OR (mi.pa_id=0 AND mi.id!=0))
AND mi.u_id=IF((SELECT id FROM table_mi WHERE p_id=0 AND pa_id="11" AND u_id="2")>0,"2",0)
) OR mi.id=0
ORDER BY
mi.priority;
This is what I'm getting as a result:
ID NAME KEYWORD RESTRICTIONS
9 test_a key_a r_key_2,r_key_3,r_key_4
This is what I'm expecting:
ID NAME KEYWORD RESTRICTIONS
9 test_a key_a r_key_2,r_key_3,r_key_4
3 test_b key_b TEST
Please see my full example with schema on sql fiddle: http://sqlfiddle.com/#!2/359d9/1
GROUP_CONCAT is an aggregate function. It will bring back a single row UNLESS you specify a GROUP BY clause (with any fields that are not in the GROUP BY being aggregate fields)
Before the ORDER BY add the following:-
GROUP BY m.id, m.name, m.keyword
That said it looks like you might want to use CONCAT to join 2 values together rather than GROUP_CONCAT
As an aside, your SQL might be easier to read if you eliminate the subselect. Assuming it is bringing back a single record then possibly as follows
SELECT
m.id,
m.name,
m.keyword,
IFNULL(GROUP_CONCAT(r.keyword),'TEST') AS restrictions
FROM
table_m AS m
INNER JOIN
table_mi as mi ON m.id=mi.m_id
LEFT JOIN
table_ri as ri ON m.id=ri.m_id
LEFT JOIN
table_r AS r ON ri.r_id=r.id
LEFT OUTER JOIN
table_mi AS mi2 ON mi2.p_id=0 AND mi2.pa_id="11" AND mi2.u_id="2"
WHERE
(
m.id>0
AND m.active=1
AND mi.p_id=0
AND (mi.pa_id="11" OR (mi.pa_id=0 AND mi.id!=0))
AND mi.u_id=IF(mi2.id >0,"2",0)
) OR mi.id=0
ORDER BY
mi.priority;
You do no need GROUP_CONCAT to achieve what you want.
Instead of :
IFNULL(GROUP_CONCAT(r.keyword),'TEST') AS restrictions
use
IFNULL(r.keyword,'TEST') AS restrictions
OR:
Keep the query as it is and add GROUP BY m.id before ORDER BY