My MySQL query with two JOINs does not work - mysql

I have written the following query, which does not work. I want to know how to make it work. It is a two-JOIN query which fails to work.
SELECT oc_download.download_id, oc_product_to_download.download_id, oc_download_description.download_id
FROM oc_download
LEFT JOIN oc_product_to_download
ON oc_download.download_id = oc_product_to_download.download_id
LEFT JOIN
oc_download.download_id = oc_download_description.download_id
WHERE oc_product_to_download.product_id = 89
With single JOIN it works, but adding the second JOIN it fails. here is the clean working one-JOIN query:
SELECT oc_download.download_id, oc_product_to_download.download_id, oc_download_description.download_id
FROM oc_download
LEFT JOIN oc_product_to_download
ON oc_download.download_id = oc_product_to_download.download_id
WHERE oc_product_to_download.product_id = 89
How should I use multiple JOIN in one single query?

You forgot the table name in the 2nd join
SELECT d.download_id, p.download_id, dd.download_id
FROM oc_download d
LEFT JOIN oc_product_to_download p ON d.download_id = p.download_id
LEFT JOIN oc_download_description dd ON d.download_id = dd.download_id
WHERE p.product_id = 89
And your where clause turns your left join into an inner join. If you don't want that then change your query to
SELECT d.download_id, p.download_id, dd.download_id
FROM oc_download d
LEFT JOIN oc_product_to_download p ON d.download_id = p.download_id
AND p.product_id = 89
LEFT JOIN oc_download_description dd ON d.download_id = dd.download_id

This is your query fixed up a bit, using table aliases and proper join syntax:
SELECT od.download_id, opd.download_id, odd.download_id
FROM oc_download od LEFT JOIN
oc_product_to_download opd
ON od.download_id = opd.download_id LEFT JOIN
oc_download_description odd
od.download_id = odd.download_id
WHERE opd.product_id = 89;
You are using left join, but this appears to be unnecessary. The on clause is undoing the first outer join, turning it into an inner join (unmatched rows would have a NULL value, which are filtered out by the where clause). In fact, I would guess that your data has well defined foreign key relationships among the columns being joined. If this is the case, you should use inner join (or just join) for the query:
SELECT od.download_id, opd.download_id, odd.download_id
FROM oc_download od JOIN
oc_product_to_download opd
ON od.download_id = opd.download_id JOIN
oc_download_description odd
od.download_id = odd.download_id
WHERE opd.product_id = 89;
The left join is misleading because it implies that some keys might not match. You also run the risk of confusing the optimizer.

Related

MYSQL Merge two columns from two tables and still use LEFT JOIN

So I'm having a slight problem with having to save price on a product in two different tables due to a few reasons. Is it possible to merge two columns into one? I know UNION exists but does it work with LEFT JOIN's?
Any pointers is much appreciated.
Best Regards
SELECT
si.id AS shop_item_id,
si.item_price,
s.logo_file_name,
p.cat_id AS category_id,
api.item_price AS api_price,
MAX(c.campaign_desc) AS campaignDesc,
MAX(c.campaign_type_id) AS campaignType,
MAX(c.shop_id) AS campaign_shop_id,
MAX(ct.image_name) AS campaignLogo
FROM
shop_item si
LEFT JOIN
shop s ON
s.id = si.shop_id
LEFT JOIN
product p ON
si.product_id = p.id
LEFT JOIN
campaign_category cc ON
cc.category_id = p.cat_id
LEFT JOIN
campaign c ON
c.id = cc.campaign_id AND
c.shop_id = si.shop_id AND
c.show_in_pricetable = 1 AND
NOW() BETWEEN c.date_from and c.date_to
LEFT JOIN
campaign_type ct ON
c.campaign_type_id = ct.id
LEFT JOIN
shop_api_item api ON
si.rel_feed_api = api.unique_id AND si.shop_id = api.shop_id
WHERE
si.`product_id` = 586 AND
s.`active_shop` = 1
GROUP BY
s.name,
si.id ,
si.item_price
ORDER BY
si.`item_price`,
si.`shop_id`,
c.`campaign_desc` DESC
It looks like you would benefit from the COALESCE() function.
SELECT
si.id AS shop_item_id,
COALESCE(si.item_price, api.item_price) AS coalesced_price,
...
COALESCE() takes multiple arguments, and returns the first argument that is not NULL.

Errors While Using IF statement in sql query

I am trying to make a query, which returns tipo_id from a table, depending on the value of this I want to join with another table, for example if tipo_id is 1 I want to join with table called p_read if tipo_id i want to join tv_read
this is what I tried to do.
SELECT ec.id,ec.estado,fv.id,fv.num_factura,fv.importe,fv.iva,fv.total,fv.fecha_consumo_inicio,fv.fecha_consumo_fin,
fv.fecha_factura, fv.fichero, c.total, l.tipo_id, lp.id_consumo FROM aldroges8.factura_venta fv
INNER JOIN aldroges8.lectura l ON fv.id=l.facturaVenta_id
INNER JOIN aldroges8.factura_cobro fc ON fc.facturaventa_id = fv.id
INNER JOIN aldroges8.cobros c ON c.id=fc.cobros_id
INNER JOIN aldroges8.estado_cobros ec ON ec.id = c.estado
IF (l.tipo_id=1)
INNER JOIN aldroges8.lectura_potencia lp ON l.id=lp.id
ELSE IF (l.tipo_id =3)
INNER JOIN aldroges8.lectura_tv_gas lp ON lp.id=l.id
WHERE fv.factura_enviada=1 AND fv.suministro_id=:id_contrato ORDER BY fv.fecha_factura DESC;
But i am getting this error.
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'IF (l.tipo_id==1)
INNER JOIN aldroges8.lectura_potencia lp ON l.id=lp.id
ELSE' at line 7
So I want to know if there is a way on doing this if staments on a query, or do I need to make another query with tipo_id, thanks in advance
SELECT ec.id,ec.estado,fv.id,fv.num_factura,fv.importe,fv.iva,fv.total,fv.fecha_consumo_inicio,fv.fecha_consumo_fin,
fv.fecha_factura, fv.fichero, c.total, l.tipo_id,
/* Used case when statement to get the required result in that column */
case when l.tipo_id=1 then lp_1.id_consumo
when l.tipo_id=3 then lp_3.id_consumo end as id_consumo
FROM aldroges8.factura_venta fv
INNER JOIN aldroges8.lectura l ON fv.id=l.facturaVenta_id
INNER JOIN aldroges8.factura_cobro fc ON fc.facturaventa_id = fv.id
INNER JOIN aldroges8.cobros c ON c.id=fc.cobros_id
INNER JOIN aldroges8.estado_cobros ec ON ec.id = c.estado
left join aldroges8.lectura_potencia lp_1 ON l.id=lp_1.id
left join aldroges8.lectura_tv_gas lp_3 ON lp_3.id=l.id
WHERE fv.factura_enviada=1 AND fv.suministro_id=:id_contrato ORDER BY fv.fecha_factura DESC;
I would write this with the condition in the on clause and then use coalesce() in the select:
SELECT ec.id, ec.estado, fv.id, fv.num_factura, fv.importe, fv.iva,
fv.total, fv.fecha_consumo_inicio, fv.fecha_consumo_fin,
fv.fecha_factura, fv.fichero, c.total, l.tipo_id,
coalesce(lp_1.id_conumo, lp_3.id_consumo) as id_consumo
FROM aldroges8.factura_venta fv INNER JOIN
aldroges8.lectura l
ON fv.id = l.facturaVenta_id INNER JOIN
aldroges8.factura_cobro fc
ON fc.facturaventa_id = fv.id INNER JOIN
aldroges8.cobros c
ON c.id = fc.cobros_id INNER JOIN
aldroges8.estado_cobros ec
ON ec.id = c.estado LEFT JOIN
aldroges8.lectura_potencia lp_1
ON l.id = lp_1.id AND l.tipo_id = 1 LEFT JOIN
aldroges8.lectura_tv_gas lp_3
ON lp_3.id = l.id AND l.tipo_id = 3
WHERE fv.factura_enviada = 1 AND
fv.suministro_id = :id_contrato
ORDER BY fv.fecha_factura DESC;
The difference between doing the comparison in the ON verses in a CASE expression may seem subtle, but it can be important.
If there are multiple matches in either table, then putting the condition in the SELECT will result in duplicate rows.

Not unique table/alias on join

I intend to do an update based on join, but getting an error. What is missing?
update
vna.patients,
vna.patient_observations,
vna.studies,
vna.series,
vna.instances,
vna.sop_classes,
vna.files,
vna.modalities,
vna.issuers
join patient_observations on atients.patient_id=patient_observations.patient_id
join studies
on patient_observations.study_id=studies.study_id
AND studies.patient_id=patients.patient_id
join series
on series.study_id=studies.study_id
join instances
on instances.series_id=series.series_id
join sop_classes
on sop_classes.sop_class_id=instances.sop_class_id
join files
on files.instance_id=instances.instance_id
left join modalities
on modalities.modality_id=series.modality_id
left join issuers
on (patients.issuer_of_patient_identifier=issuers.issuer_id)
set PATIENT_NAME='AAPM'
WHERE PATIENT_IDENTIFIER='TG18-2002';
ERROR 1066 (42000): Not unique table/alias: 'patient_observations'
You don't need to specify table names again which appears in join part
UPDATE
vna.patients
JOIN patient_observations
ON patients.patient_id = patient_observations.patient_id
JOIN studies
ON patient_observations.study_id = studies.study_id
AND studies.patient_id = patients.patient_id
JOIN series
ON series.study_id = studies.study_id
JOIN instances
ON instances.series_id = series.series_id
JOIN sop_classes
ON sop_classes.sop_class_id = instances.sop_class_id
JOIN files
ON files.instance_id = instances.instance_id
LEFT JOIN modalities
ON modalities.modality_id = series.modality_id
LEFT JOIN issuers
ON (patients.issuer_of_patient_identifier = issuers.issuer_id)
SET PATIENT_NAME = 'AAPM'
WHERE PATIENT_IDENTIFIER = 'TG18-2002' ;
Why are you mixing the two different JOIN syntaxes? Simple rule: Never use commas in the FROM clause (and that goes for UPDATE as well). I think you intend:
update vna.patients p
patient_observations po
on p.patient_id = po.patient_id join
studies st
on po.study_id = st.study_id AND
st.patient_id = p.patient_id join
series s
on s.study_id = st.study_id join
instances i
on i.series_id = s.series_id join
sop_classes sc
on sc.sop_class_id = i.sop_class_id join
files f
on f.instance_id = i.instance_id left join
modalities m
on m.modality_id = s.modality_id left join
issuers iss
on (p.issuer_of_patient_identifier = iss.issuer_id)
set p.PATIENT_NAME = 'AAPM'
where p.PATIENT_IDENTIFIER = 'TG18-2002';
That seems way too complicated. I'm guessing you just want:
update vna.patients p
set p.PATIENT_NAME = 'AAPM'
where p.PATIENT_IDENTIFIER = 'TG18-2002';
The error message is very clear, the table patient_observations is listed twice in the table references in your query. Give the second one a different alias if you really need to join it again in the same query:
...
vna.issuers
join patient_observations as po2 on patients. ....
Otherwise, remove one of them.
Also try to use the ANSI SQL join syntax instead of this old syntax.

conditional mysql if inner join

is possible to do a conditional join if a field is non-null?, ie if a field is null do a join and not return a value, and if a field is not null then do a join and return a value
SELECT CASE WHEN i.id_servicio is null THEN p.nombre as proveedor, origen_incidencia.nombre as origen, relativo_a.nombre as relativo, i . * , u.nombre AS usuario ELSE p.nombre as proveedor, origen_incidencia.nombre as origen, relativo_a.nombre as relativo, i . * , u.nombre AS usuario,s.nombre
end
from incidencias i
INNER JOIN usuarios AS u ON i.id_usuarios =19 AND i.id_usuarios = u.id
case when i.id_servicio is not null then
INNER JOIN servicios s ON s.id = i.id_servicio
end
INNER JOIN relativo_a ON relativo_a.id = i.id_relativo_a
INNER JOIN origen_incidencia ON origen_incidencia.id = i.id_origen_incidencia
INNER JOIN proveedores p ON p.id = i.id_proveedor
Yes, it's called an outer join.
There are a couple of flavors of those. In this particular case you can use a left outer join, often just referred to as left join.
This query will return all incidencias and will just return NULL for the name if there is no service linked to the -erm- incident (?).
SELECT
i.id,
s.nombre
FROM incidencias i
LEFT JOIN servicios s ON s.id = i.id_servicio
There is also the right join, which does the same, but the other way around (rows in first table are optional). Quite often, using right join is considered bad practice, since it is more confusing to read, especially when you combine it with left joins in the same query. I don't think there are cases where you must use it, since you can always replace it with a left join by just reversing the tables.

SQL returns incorrect data using 2 left joins

I have written a MYSQL script, that returns incorrect data. I am quite fluent in SQL, but this query is not returning correct results. Can someone have a look and see whats going on. The problem is the noOfBids, and noOfRatedTimes. The values are the same for both columns and are large values too.
select
a.user_name as userName,
coalesce(count(b.sp_user_name),0) as noOfBids,
coalesce(ROUND(AVG(b.a_amount),2),0) as avgAmount,
coalesce(count(d.sp_user_name),0) as noOfRatedTimes,
coalesce(ROUND(AVG(d.user_rate),2),0)
from users a
left join project_imds b
on b.sp_user_name = a.user_name
left join projects c
on b.project_code = c.project_code
left join sp_user_rating d
on d.sp_user_name = b.sp_user_name
where a.user_type = 'SP'
and a.active = 'Y'
group by a.user_name
order by coalesce(ROUND(AVG(d.user_rate),2),0) desc;
I have created a workaround on this, by creating a temp table to get the avg values and joining this to the main query.
Since I don't know the specifics of the data behind your query, this is only a guess. But perhaps you'd rather join "sp_user_rating" directly to "users", changing
left join sp_user_rating d
on d.sp_user_name = b.sp_user_name
to
left join sp_user_rating d
on d.sp_user_name = a.user_name
select
a.user_name as userName,
coalesce(count(b.sp_user_name),0) as noOfBids,
coalesce(ROUND(AVG(b.a_amount),2),0) as avgAmount,
coalesce(count(d.sp_user_name),0) as noOfRatedTimes,
coalesce(ROUND(AVG(d.user_rate),2),0)
from users as a
left join project_imds as b
on b.sp_user_name = a.user_name
left join projects as c
on b.project_code = c.project_code
left join sp_user_rating as d
on d.sp_user_name = b.sp_user_name
where a.user_type = 'SP'
and a.active = 'Y'
group by a.user_name
order by coalesce(ROUND(AVG(d.user_rate),2),0) desc;