SQL minus query rows from another row - mysql

I'm pulling information out with the code below, which works absolutely fine.
I need to pull out the data without the contractorID affecting it, then subtract the rows from the first query from it.
SELECT
DISTINCT a.addID
, p.propdetailID
, p.plotID
FROM address AS a
LEFT JOIN propdetail AS p ON (a.addID = p.addID)
JOIN housebuildertoproperty AS htp ON (htp.addID = p.addID)
JOIN contractortopropdetail AS ctp ON (ctp.propdetailID = p.propdetailID)
WHERE htp.housebuilderID = 1
AND ctp.contractorID = 1
So what I mean is:
row 1
that's the result from the first query
row 1
row 2
row 3
That's the result from the query without the AND ctp.contractorID = 1 part. I need code that will pull out:
row 2
row 3
I tried MINUS but phpMyAdmin just didn't accept it. I've looked into NOT IN but I can't seem to figure this out.

First, the left join is unnecessary, because the subsequent join conditions and where clause turn it into an inner join.
Your problem is that some of the addresses on with contractorID = 1 have other contractors. The solution is to use group by instead of distinct and use a having clause to filter out addresses for contractor 1:
SELECT a.addID, p.propdetailID, p.plotID
FROM address a JOIN
propdetail p
ON (a.addID = p.addID) JOIN
housebuildertoproperty htp
ON (htp.addID = p.addID) JOIN
contractortopropdetail ctp
ON (ctp.propdetailID = p.propdetailID)
WHERE htp.housebuilderID = 1
GROUP BY a.addID, p.propdetailID, p.plotID
HAVING SUM(ctp.contractorID = 1) = 0

Related

SQL query returning 0 rows after adding extra INNER JOIN

The issue is simple to explain, but seemingly not so simple to solve.
This SQL query returns 0 rows:
SELECT app_handover.*, sys_logins.first_name, sys_logins.last_name, sys_logins.dept_id, org_depts.dept_name
FROM ((app_handover
INNER JOIN sys_logins ON app_handover.sent_by = sys_logins.id)
INNER JOIN org_depts ON sys_logins.dept_id = org_depts.id)
WHERE app_handover.id = '12'
This one, however, returns 1 row as I expected:
SELECT app_handover.*, sys_logins.first_name, sys_logins.last_name, sys_logins.dept_id
FROM app_handover
INNER JOIN sys_logins ON app_handover.sent_by = sys_logins.id
WHERE app_handover.id = '12'
The only difference is the lack of INNER JOIN with the org_depts table.
What I want to be returned is all the column values from app_handover, which references sys_logins.id in its sent_by column. I also want the value of org_depts.dept_name, which is referenced by sys_logins.dept_id.
I cannot think of an alternative syntax to use, but clearly there is an error in my logic in the first example, which is returning 0 rows instead of 1 as I expected.
Yep, LEFT JOIN was the answer. The value of dept_id in the matching sys_logins row was NULL, so no matching record was found in org_depts.
This query works and now returns 1 row:
SELECT app_handover.*, sys_logins.first_name, sys_logins.last_name, sys_logins.dept_id, org_depts.dept_name
FROM ((app_handover
INNER JOIN sys_logins ON app_handover.sent_by = sys_logins.id)
LEFT JOIN org_depts ON sys_logins.dept_id = org_depts.id)
WHERE app_handover.id = '12'

MySql - having issues with double left join

I am having issues with getting this double left join to get the listingspecificsListPrice, but that info exists in the table, cant figure out why it would not include it. This is my sql.
SELECT mls_subject_property.*, mls_images.imagePath, mls_forms_listing_specifics.listingspecificsListPrice
FROM mls_subject_property
LEFT JOIN mls_images ON mls_subject_property.mls_listingID = mls_images.mls_listingID
LEFT JOIN mls_forms_listing_specifics ON mls_forms_listing_specifics.mls_listingID = mls_subject_property.mls_listingID AND mls_images.imgOrder = 0
WHERE userID = 413
GROUP BY mls_subject_property.mls_listingID
The result comes out like this..
All of the other fields come back, but it doesnt seem to want to bring back those two items.
This is a picture of the other table, to show that the data does in fact exist.
The mls_images.imgOrder = 0 condition should be in the join with mls_images, not mls_forms_listing_specifics.
Don't use GROUP BY if you're not using any aggregation functions. Use SELECT DISTINCT to prevent duplicates.
SELECT DISTINCT mls_subject_property.*, mls_images.imagePath, mls_forms_listing_specifics.listingspecificsListPrice
FROM mls_subject_property
LEFT JOIN mls_images ON mls_subject_property.mls_listingID = mls_images.mls_listingID AND mls_images.imgOrder = 0
LEFT JOIN mls_forms_listing_specifics ON mls_forms_listing_specifics.mls_listingID = mls_subject_property.mls_listingID
WHERE userID = 413

Getting wrong COUNT values in query

I am using the following query to get COUNT items from rows from the same table in LEFT JOIN.
This is the query:
SELECT
pac.id_sat as id_sat,
pac.nombre_contacto as nombre_contacto,
pac.centro_contacto as centro_contacto,
pac.tel_contacto as tel_contacto,
pac.horario_contacto as horario_contacto,
pac.email_contacto as email_contacto,
pac.num_factura as num_factura,
pac.fecha_factura as fecha_factura,
eq.nombre_equipo as modelo_equipo,
pac.num_serie as num_serie,
pac.tipo_incidencia as tipo_incidencia,
pac.cod_sat as cod_sat,
pac.estado as estado,
pac.clinica as clinica,
pac.fecha_sat as fecha_sat,
COUNT(medfotos.id_media_sat) as num_fotos,
COUNT(medvideos.id_media_sat) as num_videos
FROM tb_sat pac
LEFT JOIN tb_equipos eq ON pac.modelo_equipo = eq.id_equipo
LEFT JOIN tb_media_sat medfotos ON pac.cod_sat = medfotos.cod_sat AND medfotos.tipo = 1
LEFT JOIN tb_media_sat medvideos ON pac.cod_sat = medvideos.cod_sat AND medvideos.tipo = 2
WHERE pac.clinica = '".$idclinica."'
GROUP BY pac.id_sat
ORDER BY pac.fecha_sat DESC
My issue is that I am getting a wrong amount of COUNT items.
The real value for num_fotos should be 3 and for num_videos should be 2.
I am getting num_fotos = 6 and num_videos = 6.
EDIT
Table tb_sat
Table tb_media_sat
Sub-query will work better in your case like as follows:
SELECT pac.*, (SELECT COUNT(id_media_sat) FROM tb_media_sat WHERE cod_sat=pac.cod_sat AND tipo=1) AS num_fotos, (SELECT COUNT(id_media_sat) FROM tb_media_sat WHERE cod_sat=pac.cod_sat AND tipo=2) AS num_videos FROM tb_sat pac WHERE pac.clinica = '".$idclinica."' ORDER BY pac.fecha_sat DESC
Rest columns, please add yourself slowly slowly. I hope you will get correct output.

MySQL - Multirow Sum without Subquery

I currently have this working using a Sub-query, but as the DB grows this will become HUGELY inefficient. I'm wondering if there is a more efficient way to do what I need to do without sub-queries?
I need to have my final output look like so:
Question, Answer, Responses, Charts included in Response Count
Did this work?, N/A, 26, 30
Did this work?, Yes, 4, 30
This is my current query:
SELECT
bq_text,
ba_a,
bq_id,
COUNT(ba_a) AS ba_aC,
(SELECT COUNT(*) FROM board_done_sheet WHERE sd_b_id = bs.bs_id AND sd_sub = 1) AS sd_chartnumC
FROM board_done_sheet AS sh
LEFT JOIN board_done bd
ON (bd.bd_id = sh.sd_bd_id)
LEFT JOIN boardsubs bs
ON (bd.bd_b_id = bs.bs_id)
LEFT JOIN b_q_answers ba
ON (sh.sd_s_id = ba.ba_s_id)
LEFT JOIN bsquestions bq
ON (bq.bq_id = ba.ba_q_id)
LEFT JOIN multiples m
ON (ba.ba_m_id = m.m_id)
LEFT JOIN users u
ON (u.us_id = bd.bd_d_id)
LEFT JOIN profiles p
ON (p.p_u_id = bd.bd_d_id)
LEFT JOIN users rev
ON (rev.us_id = bd.bd_rev)
WHERE sd_sub = '1' AND bq_text <> 'Date' AND bq_id = 380
GROUP BY bs_id, bq_text, ba_a
That works perfectly, the problem is it has to use sub-queries which as time goes by will get less efficient.
I'm just wondering if there is a better more efficient way to do that summed field without it.
Presumably the subquery you're concerned about is the one in your toplevel SELECT.
That is easy to refactor so it won't get repeated.
Just JOIN it to the rest of the table. You'll want this sort of thing:
SELECT
bq_text, ...
COUNT(ba_a) AS ba_aC,
countup.countup AS sd_chartnumC
FROM board_done_sheet AS sh
LEFT JOIN board_done bd
ON (bd.bd_id = sh.sd_bd_id)
...
LEFT JOIN users rev
ON (rev.us_id = bd.bd_rev)
JOIN (
SELECT COUNT(*) AS countup , sd_b_id
FROM board_done_sheet
WHERE sd_sub = 1
GROUP BY sd_b_id
) AS countup ON countup.sd_b_id = bs.bs_id
WHERE sd_sub = '1'
AND bq_text <> 'Date'
AND bq_id = 380
GROUP BY bs_id, bq_text, ba_a
The countup subquery generates a summary table of counts and ids, and then joins it to the other tables.
A JOIN cascade of this complexity may become inefficient for other reasons as your table grows if you don't structure your indexes correctly.

When using GROUP BY server still waste resources to process UNGROUPED query first?

I need to make second request inside one so far i did it like this and then just grouped by userid field, works. But without grouping it shows way too many results i was wondering if this results grouped are actually being requested first and then filtered so it loads mysql server?
SELECT mn.userid, user_table.first_name, user_table.last_name, employer_info.emp_name, emp2.emp_name AS emp2name
FROM main as mn
LEFT JOIN position_info ON position_info.pos_id = mn.position
LEFT JOIN employer_info ON employer_info.emp_id = position_info.emp_id
LEFT JOIN position_info AS position2 ON pos2.pos_id = mn.position2
LEFT JOIN employer_info AS emp2 ON emp2.emp_id = pos2.emp_id
WHERE mn.type = 31 or mn.type = 3
GROUP BY mn.userid
Would this way of building query be more resource friendly?
SELECT mn.userid, user_table.first_name, user_table.last_name, employer_info.emp_name, emp2.emp_name AS emp2name
FROM main as mn
LEFT JOIN position_info ON position_info.pos_id = mn.position
LEFT JOIN employer_info ON employer_info.emp_id = position_info.emp_id
LEFT JOIN employer_info AS emp2 ON emp2.emp_id = {
SELECT emp_id FROM position_info WHERE pos_id = mn.positions2
)
WHERE mn.type = 31 or mn.type = 3
GROUP BY mn.userid
request looks almost same in length, but returns far less results when not grouped, so its better to do it first or second way?
P.S. dont pay attention to the code its not the question