MySQL LEFT JOIN Query is Behaving Strangely - mysql

Mysql LEFT JOIN query is returning strange result. The query returns a record when the right ON condition "PARTIALLY" matches the left.
SELECT s.id sid
, s.points sCredits
, s.ghs
, s.usd
, s.africa
, o.id oid
, o.user_id
, o.item_id
FROM pi21o_zoo_item s
LEFT
JOIN pi21o_logos_orders o
ON s.id = o.item_id
AND o.user_id = '268'
WHERE s.id = '268'
The problem is the query returns a record when s.id = '268' and o.item_id = '268-AGW'

Your problem is that when you compare an integer (s.id) with a string (o.item_id) MySQL automatically converts the string to an integer (see the manual). Since '268-AGW' starts with an integer, it is successfully converted to 268 which then matches the s.id value. To work around this, cast the s.id value to a string i.e. write
(CAST(`s`.`id` AS CHAR) = `o`.`item_id`) AND (`o`.`user_id` = '268')

Related

Mqsyl - multiple left joins

I'm trying to improve a live product search for the admin side of our online store.
We're currently using the following query:
SELECT p.product_id, p.full_title, p.descript, p.cost, p.no_vat, p.high_pic, p.prod_type, count(p.product_id) AS occurence, t.descript AS type_desc, p.available
FROM gdd_product as p, gdd_prodtype as t, gdd_info as i
LEFT JOIN gdd_keyword as k ON i.product_id = k.product
WHERE p.prod_type = t.prod_type
AND i.product_id = p.product_id
AND replace(concat_ws(p.descript, i.info_search1, i.info_search2, i.info_search3, k.keyword),' ','')
LIKE '%tool%'
GROUP BY p.product_id
ORDER BY occurence DESC, cost ASC LIMIT 30
This works, but omits any results which don't have an entry in the info_search columns.
So I tried changing it so that gdd_info is LEFT JOINed, with this code:
SELECT p.product_id, p.full_title, p.descript, p.cost, p.no_vat, p.high_pic, p.prod_type,
count(p.product_id) AS occurence, t.descript AS type_desc, p.available
FROM gdd_product as p, gdd_prodtype AS t
LEFT JOIN gdd_info as i ON p.product_id = i.product_id
LEFT JOIN gdd_keyword as k ON p.product_id = k.product
WHERE p.prod_type = t.prod_type
AND replace(CONCAT_WS(p.descript, i.info_search1, i.info_search2, i.info_search3, k.keyword),' ','')
LIKE '%tool%'
GROUP BY p.product_id
ORDER BY occurence DESC, cost ASC
LIMIT 30
...but that throws an error:
SQL Error (1054): Unknown column 'p.product_id' in 'on clause'
What am I doing wrong?
1st. Don't mix standards the ANSI standards (ANSI-92 vs ANSI-89). Either use INNER/CROSS/LEFT join or the , notation but not both. It's bad form and may eventually break; and maybe what's causing your p.product error now.
SELECT p.product_id, p.full_title, p.descript, p.cost
, p.no_vat, p.high_pic, p.prod_type
, count(p.product_id) AS occurence, t.descript AS type_desc
, p.available
FROM gdd_product as p
INNER JOIN gdd_prodtype AS t
on p.prod_type = t.prod_type
LEFT JOIN gdd_info as i
ON p.product_id = i.product_id
LEFT JOIN gdd_keyword as k
ON p.product_id = k.product
WHERE replace(CONCAT_WS(p.descript, i.info_search1, i.info_search2, i.info_search3, k.keyword),' ','')
LIKE '%tool%'
GROUP BY p.product_id
ORDER BY occurence DESC, cost ASC
LIMIT 30
2nd. the reason why it's omitting records is likely because NULL concatenated with a string is NULL. Then you search for a string against a null which will never return a result. You need to coalesce the i.info_search1... with a empty set '' coalesce(i.info_earch1,'') and so on... so it takes the 1st non-null value in a series and then a string is compared against a string
replace(CONCAT_WS(
coalesce(p.descript,'')
, coalesce(i.info_search1,'')
, coalesce(i.info_search2,'')
, coalesce(i.info_search3,'')
, coalesce(k.keyword,'')),' ','')
Giving us...
SELECT p.product_id, p.full_title, p.descript
, p.cost, p.no_vat, p.high_pic, p.prod_type
, count(p.product_id) AS occurence, t.descript AS type_desc
, p.available
FROM gdd_product as p
INNER JOIN gdd_prodtype AS t
on p.prod_type = t.prod_type
LEFT JOIN gdd_info as i
ON p.product_id = i.product_id
LEFT JOIN gdd_keyword as k
ON p.product_id = k.product
WHERE replace(CONCAT_WS(
coalesce(p.descript,'')
, coalesce(i.info_search1,'')
, coalesce(i.info_search2,'')
, coalesce(i.info_search3,'')
, coalesce(k.keyword,'')),' ','')
LIKE '%tool%'
GROUP BY p.product_id
ORDER BY occurence DESC, cost ASC
LIMIT 30
Think of it this way...
Say p.descript exists but info doesn't on your left join... so you concat p.descript with null getting null. Nothing will be like null so you get no records as you can't execute an equality check (like) on a null value and expect to get a result.
Now say p.descript doesn't exist and is null, concat it with anything that is null is yet again null so you have the same result.
Since any value could be null in your concat_WS string we need to coalesce all values just in case.
and now we have a valid string compared against your like and thus when your string matches your like, you'll now get results instead of when a column value in your ws_concat being null wiping your record out.

GROUP BY with HAVING but unrecognized table in MySQL

I have this query, and I am trying to split the answer column RES (that is divided by commas) into more rows (instead). But when I try to do that, the HAVING part is not working at all, and it's throwing: Unknow column.
This is the original query:
SELECT ad.ID_ANSWER as idRes
, IFNULL(c.NOMBRE_FACTURA,a.INTERVIEWED_NAME) AS nomPdv
, c.CODIGO
, q.`NAME` AS nombreEncuesta
, ad.ID_QUESTION AS idCue
, que.QUESTION
, GROUP_CONCAT(ad.ANSWER) AS RES
, a.LATITUDE
, a.LONGITUDE
, cm.DIRECCION
, c.NIT
, cm.NOMREPRESENTANTE
, cm.FECHA_NACIMIENTO
, a.ID_QUESTIONARY
, cm.TELEFONO, cm.FECHA_NACIMIENTO, cm.NITREPRESENTANTE,
CONCAT(cm.APELLIDO_PATERNO,' ',cm.APELLIDO_MATERNO,' ', cm.NOMBRES_CLIENTE) as RAZONSOCIAL, a.USUARIO_ID, a.FECHA_ID, R.NOMBRE AS RUTA, CASE WHEN D.NOMBRE IS NULL THEN DP.NOMBRE ELSE D.NOMBRE END AS DEPARTAMENTO, P.NOMBRE AS ENCUESTADOR
FROM VM_ANSWER AS a
JOIN VM_ANSWER_DETAIL ad
ON ad.ID_ANSWER = a.ID_ANSWER
JOIN VM_QUESTIONARY AS q
ON q.ID_QUESTIONARY = a.ID_QUESTIONARY
JOIN VM_QUESTION AS que
ON que.ID_QUESTION = ad.ID_QUESTION
JOIN VM_QUESTIONARY_RANGE AS qr
on qr.ID_QUESTIONARY = a.ID_QUESTIONARY
AND qr.OPERACION_ID = 1
JOIN AD_USUARIO U
ON U.USERNAME = a.USUARIO_ID
JOIN GL_PERSONA P
ON P.ID_PERSONA = U.ID_PERSONA
LEFT
JOIN (SELECT * FROM VP_VENDEDOR V GROUP BY V.ID_PERSONA) V ON V.ID_PERSONA = U.ID_PERSONA
LEFT JOIN VP_SUCURSAL S ON S.ID_SUCURSAL = V.ID_SUCURSAL
LEFT JOIN GL_DEPARTAMENTO D ON D.ID_DEPARTAMENTO = S.ID_DEPARTAMENTO
LEFT JOIN VP_CLIENTE AS c ON c.ID_CLIENTE = a.ID_CLIENT
LEFT JOIN VM_CLIENTE_MOVIL AS cm ON cm.ID_CLIENTE = c.ID_CLIENTE
LEFT JOIN GL_DEPARTAMENTO DP ON DP.ID_DEPARTAMENTO = cm.ID_CIUDAD
LEFT JOIN VM_RUTA_VENDEDOR RV ON RV.ID_VENDEDOR = V.ID_VENDEDOR AND RV.OPERACION_ID > 0
LEFT JOIN VM_RUTA R ON R.ID_RUTA = RV.ID_RUTA
WHERE a.OPERACION_ID = 1 AND qr.ID_BRANCH = 3 AND IF (61 = 0, TRUE, a.ID_QUESTIONARY = 61)
GROUP BY a.ID_QUESTIONARY,a.ID_ANSWER
ORDER BY a.ID_QUESTIONARY,a.ID_ANSWER
When I add the following code
LEFT JOIN GL_TIPO T ON T.ID_TIPO = que.ID_TYPE
WHERE a.OPERACION_ID = 1 AND qr.ID_BRANCH = 3 AND IF (61 = 0, TRUE, a.ID_QUESTIONARY = 61)
GROUP BY a.ID_QUESTIONARY,a.ID_ANSWER, ad.ID_ANSWER_DETAIL HAVING T.ID_TIPO=1012
ORDER BY a.ID_QUESTIONARY,a.ID_ANSWER
throws me the error of not recognized table T.ID_TIPO, but if I take off the HAVING word, the left join works normally.
this is the normal result, that as you can see in the column RES, it's divided by a comma when there is more than an answer:
I know it's complicated to understand, 1012 is a multi-select answer type from table GL_TIPO, and it's used in the table Question to define the type of it.
If you can help me to understand what I am doing wrong with the HAVING reserved word it would be awesome, but if you have any suggestion is also welcome too.
Try this:
GROUP BY a.ID_QUESTIONARY,a.ID_ANSWER, que.ID_TIPO=1012
This will put the questions with ID_TIPO=1012 into its own row, and all other ID_TIPO values will be grouped together. Both of these are nested within the ID_QUESTIONARY, ID_ANSWER groups.

converting mysql sql to sql server

I have a MySQL SQL that works fine with Jaspersoft report:
SELECT pr.id AS project_id,
pr.project_name as project_name,
pr.export_event_id,
au.full_name,
ee.timestamp
FROM (
SELECT project.id, project.project_name, MAX(project.export_event_id) AS max_export_event_id FROM project INNER JOIN export_event iee ON project.export_event_id = iee.id
where IIF ($P{exportEventDate} IS NULL, TRUE, CONVERT(DATE, iee.timestamp) <= $P{exportEventDate})
GROUP BY project_name
) AS in_PR INNER JOIN project AS pr ON pr.project_name = in_PR.project_name AND pr.export_event_id = in_PR.max_export_event_id
INNER JOIN project_owner_base pob ON pob.id = pr.project_owner_id
INNER JOIN export_event AS ee ON pr.export_event_id = ee.id
INNER JOIN auth_user au ON pob.auth_user_id = au.id
WHERE IIF ($P{projectOwner} IS NULL, TRUE, au.id = $P{projectOwner})
I am trying to convert it to SQL Server but can't figure out the equivalent.
Think of the $P{...} as '?' in dynamic SQL
Any idea?
I think this is just a simple OR statement.
Where #ProjectOwner IS NULL
OR au.id = #ProjectOwner
Your query is pretty close. I would remove the IIF() entirely -- in either database. The result is something like this:
SELECT pr.id AS project_id,
pr.project_name as project_name,
pr.export_event_id,
au.full_name,
ee.timestamp
FROM (SELECT p.project_name, MAX(p.export_event_id) AS max_export_event_id
FROM project p INNER JOIN
export_event iee
ON p.export_event_id = iee.id
WHERE ? IS NULL OR CONVERT(DATE, iee.timestamp) <= ?
GROUP BY p.project_name
) in_PR INNER JOIN
project pr
ON pr.project_name = in_PR.project_name AND
pr.export_event_id = in_PR.max_export_event_id INNER JOIN
project_owner_base pob
ON pob.id = pr.project_owner_id INNER JOIN
export_event ee
ON pr.export_event_id = ee.id INNER JOIN
auth_user au
ON pob.auth_user_id = au.id
WHERE ? IS NULL OR au.id = ?;
I replaced the variables with ? (as suggested by your question). The above should work in either database.
Note that this also fixes the aggregation in the subquery to remove p.id which seems unnecessary (and should cause an error in SQL Server).

Using ORDER BY on a multiple LEFT JOIN query

I have this long query that I finally got to work but I am unable to ORDER BY date_time_added, which is a field that is in all the tables except for user_accounts and relationships table. How do i make it work correctly?
$sql = "select distinct pb.user_id, pb.Full_name,
tv.why_onsite3, tv.onsite3_id, tv.other_date as onsite3_date,
tv.user_allowed as tv_user_allowed, np.onsite4_name ,
np.onsite4_id, np.other_date as onsite4_date, np.user_allowed
as np_user_allowed, pml.med_name , pml.med_id, pml.other_date
as pml_date, pml.user_allowed as pml_user_allowed, pl.onsite5_name,
pl.onsite5_test_id, pl.other_date as some_stats_date, pl.user_allowed as
pl_user_allowed, chlp.problem_name_is , chlp.current_problem_id,
chlp.other_date as chlp_date, chlp.user_allowed as chlp_user_allowed,
pphl.onsite10_health_prob_id , pphl.onsite10_problem_name_is,
pphl.other_date as pphl_date, pphl.user_allowed as pphl_user_allowed,
al.onsite_id , al.onsite_name, al.other_date as onsite_date,
al.user_allowed as al_user_allowed, sl.onsite2_id , sl.onsite2_name,
sl.other_date as onsite2_date, sl.user_allowed as sl_user_allowed,
hal.onsite6_id , hal.reason_for_admit, hal.other_date as hal_date,
hal.user_allowed as hal_user_allowed, il.onsite9_id , il.onsite9_name,
il.other_date as il_date , il.user_allowed as il_user_allowed
from user_accounts pb left join some_stuff tv on pb.user_id = tv.user_id
left join some_onsite4s np on pb.user_id = np.user_id
left join some_med pml on pb.user_id = pml.user_id
left join list_hal hal on pb.user_id = hal.user_id
left join list_for_things il on pb.user_id = il.user_id
left join list_on sl on pb.user_id = sl.user_id
left join some_all al on pb.user_id = al.user_id
left join some_list pphl on pb.user_id = pphl.user_id
left join some_stats pl on pb.user_id = pl.user_id
left join some_probs chlp on pb.user_id = chlp.user_id
where (pb.user_id in (select fb.friend_id from relationships fb
where fb.user_id = '$uid')
or pb.user_id in (select fb1.user_id from relationships fb1
where fb1.friend_id = '$uid')
)
group by pb.user_id ORDER BY date_time_added DESC LIMIT $startrow, 20";
In ORDER BY clause, you have to specify what is the exact column you are ordering by. That means you have to prefix the column that is used for ordering, because you have multiple columns that are called the same in multiple tables.
Other option is to restructure the query completely and use UNION operator with multiple SELECT statements. Each SELECT statement would pickup a group of data from one table and order that group by column from that table.
The solution depend on the data that you want to output - the context of the data.

SQL calculating time between assignments

I have to write an SQL statement which contain a field that contain two different values consecutively but in the way I have wrote it, it return always null because it is interpreted as having the two value in the same time!
My conditions should be : (ci.field = 'Group' and ci.oldString = 'Triage' ) and (ci.field='assignee' and ci.newString is not NULL)
That means calculate time between: when the issue is assigned to group named Triage and when the issue is assigned to a person.
How can I fix it?
My SQL statement:
select TIMEDIFF(a.created,b.created)
from
(select g.created, g.issueid as groupid1
from changegroup g
join changeitem ci on (ci.groupid = g.id)
join jiraissue ji on (ji.id = g.issueid)
join project p on (p.id = ji.project)
join priority pr on (pr.id = ji.priority)
where ci.field = 'Group'
and ci.oldString = 'Triage'
and ci.field='assignee'
and ci.newString is not NULL
and p.pname = 'Test'
and pr.pname='P1'
and ji.created between '2011-08-11 14:01:00' and '2011-08-12 14:11:00'
) a
left join (
select ji.created, ji.id as groupid2
from jiraissue ji
join changegroup g on (g.issueid = ji.id)
join project p on (p.id = ji.project)
where p.pname = 'Test'
and ji.created between '2011-08-11 14:01:00' and '2011-08-12 14:11:00'
) b ON (a.groupid1 = b.groupid2);
This is the table from which I should retrieve data
See my comment about the quality of your question but a hint at how to solve this goes like (assuming you can make sure this doesn't create 1-n joins)
select groupid_orsomething_else, TIMEDIFF(a.created, b.created)
from yourtable
left join
(select groupid_orsomething_else, created
from yourtable
where field = 'Group' and oldstring is 'Triage'
) a
on a.groupid_orsomething_else = yourtable.groupid_orsomething_else
left join
(select groupid_orsomething_else, created
from yourtable
where field = 'assignee' and oldstring is null) b
on b.groupid_orsomething_else = yourtable.groupid_orsomething_else