MySQL LEFT JOIN Problem - Missing LEFT column - mysql

I'm having problems with an SQL query used to display custom profile fields and any (optional) corresponding values.
Here is the SQL query I'm using:
SELECT pf.`id`, pf.`name`, pv.`value` FROM `profile_fields` AS pf
LEFT JOIN `profile_values` AS pv ON (pf.`id` = pv.`field_id`)
WHERE (pf.`site_id` = '0' OR pf.`site_id` = '%d') AND (pv.`user_id` = '%d' OR pv.`user_id` IS NULL)
ORDER BY pf.`order` ASC
The problem I'm having is that any columns with no corresponding profile_values records are not shown at all, when they should show, but just with an empty value.
Many thanks!

Try moving the profile values conditions to the JOIN statement:
SELECT pf.`id`, pf.`name`, pv.`value` FROM `profile_fields` AS pf
LEFT JOIN `profile_values` AS pv ON (
pf.`id` = pv.`field_id` AND
(pv.`user_id` = '%d' OR pv.`user_id` IS NULL)
)
WHERE (pf.`site_id` = '0' OR pf.`site_id` = '%d')
ORDER BY pf.`order` ASC

Related

Trying to join two tables with multiple where condition on both table in sql

I wrote following sql query
SELECT clicks.offer_id, clicks.offer_name, clicks.country, clicks.device_type, clicks.os_name, conversions.name , clicks.ip_address as Session, conversions.conversion_ip as Conversion, conversions.currency as Currency , conversions.payout as Payout
FROM clicks
JOIN users ON clicks.affiliate_id = users.id
LEFT JOIN conversions ON clicks.transaction_id = conversions.click_transaction_id
WHERE clicks.affiliate_id = '2'
AND conversions.status = ('approved' or 'pending')
AND date(clicks.created_at) BETWEEN '2021-11-08' AND '2021-12-07'
in where condition doesn't affect the following condition
AND conversions.status = ('approved' or 'pending')
What I did mistake here?
You can use the IN operator in the WHERE clause like below;
SELECT clicks.offer_id, clicks.offer_name,
clicks.country, clicks.device_type, clicks.os_name,
conversions.name , clicks.ip_address as Session,
conversions.conversion_ip as Conversion,
conversions.currency as Currency ,
conversions.payout as Payout
FROM clicks
JOIN users ON clicks.affiliate_id = users.id
LEFT JOIN conversions ON clicks.transaction_id = conversions.click_transaction_id
WHERE clicks.affiliate_id = '2' AND conversions.status IN ('approved', 'pending')
AND date(clicks.created_at) BETWEEN '2021-11-08' AND '2021-12-07';

SQL left join exclude non matching records

I'm working on this query (running on MySQL 5.6):
SELECT
veicoli_contratti.targa AS targa,
veicoli_contratti.canone_noleggio AS canone,
anag_convenzionati.nome AS convenzionato,
SUM(noleggio_veicoli.fatt_prezzo_totale_noleggio) AS noleggi_incasso,
noleggio_veicoli.modalita_noleggio,
COUNT(DISTINCT noleggio_veicoli.id) AS noleggi
FROM
veicoli_contratti
LEFT JOIN
noleggio_veicoli ON veicoli_contratti.id = noleggio_veicoli.id_veicolo
INNER JOIN
anag_convenzionati ON veicoli_contratti.id_convenzionato = anag_convenzionati.id
WHERE
(veicoli_contratti.data_cancellazione IS NULL)
AND (veicoli_contratti.targa <> '')
AND (noleggio_veicoli.data_cancellazione IS NULL)
AND (anag_convenzionati.data_cancellazione IS NULL)
AND (YEAR(noleggio_veicoli.rientro_data) = 2020)
AND (MONTH(noleggio_veicoli.rientro_data) = 10)
AND ((noleggio_veicoli.stato_noleggio = 'C')
OR (noleggio_veicoli.stato_noleggio = 'F')
)
AND ((noleggio_veicoli.modalita_noleggio = 'S')
OR (noleggio_veicoli.modalita_noleggio = 'OPO')
OR (noleggio_veicoli.modalita_noleggio = 'M')
)
AND (veicoli_contratti.stato = 'OPERATIVA')
GROUP BY anag_convenzionati.id , veicoli_contratti.id , noleggio_veicoli.modalita_noleggio
ORDER BY convenzionato , noleggi DESC , canone DESC , noleggi_incasso DESC ;
I thought LEFT JOIN clause will produce a record even if there's not a matching record in table noleggio_veicoli but this doesn't happen.
The result include just records where a match is found between veicoli_contratti and noleggio_veicoli.
I tried also adding OR noleggio_veicoli.id IS NULL in WHERE clause but it's not the solution.
How can I fix this?
I created an SQL fiddle to try this here
Your understand is correct. However, the where clause is "undoing" the LEFT JOIN. Why?
You have conditions such as this:
AND ((noleggio_veicoli.stato_noleggio = 'C') OR (noleggio_veicoli.stato_noleggio = 'F'))
Well, NULL fails those conditions so non-matches are filtered out. This condition (along with other conditions) should be included in the ON clause. For this one, it looks like:
AND noleggio_veicoli.stato_noleggio IN ('C', 'F')

Include another select column based on data - MySQL

How do I include SUM((pm.Quantity * bl.TotalQty)) AS NextBOMItemCount WHERE projectbomlist.ParentPartNum = bl.PartNum?
The data should not be changed, the same data should be retrieved, the however additional column has to be included.
VIEW: `NEWprojectBOMItemCount
select
`pm`.`ProjectCode` AS `ProjectCode`,
`bl`.`PartNum` AS `PartNum`,
sum((`pm`.`Quantity` * `bl`.`TotalQty`)) AS `BOMItemCount`,
`bl`.`mp` AS `mp`,
`p`.`complete` AS `complete`,
`bl`.`RMInd` AS `RMInd`,
`bl`.`M_PartNum` AS `M_PartNum`
from
(
(`projectmachine` `pm` join `projectbomlist` `bl`)
join `projects` `p`
)
where
(
(`pm`.`MachineListID` = `bl`.`MachineListID`)
and (`pm`.`ProjectCode` = `bl`.`ProjectCode`)
and (`pm`.`ProjectCode` = `p`.`ProjectCode`)
and (`p`.`AfterProjectHeirarchyInd` = 'Y')
)
and and pm.ProjectCode = 'AB212323'
group by
`pm`.`ProjectCode` ,
`bl`.`PartNum`
order by
`pm`.`ProjectCode` ,
`bl`.`PartNum`
Or, another option can be, please consider above view used in below query, please suggest changes to the below query as shown above (repeating here)
`sum((pm.Quantity * bl.TotalQty)) AS NextBOMItemCount where projectbomlist.ParentPartNum = bl.PartNum` - in place of `(select-NextBOMItemCount)`?
Please see PBLH.ParentPartNum is the column that I should compare with BL.ProjectCode to get NextBOMItemCount value.
QUERY calling view: NEWprojectBOMItemCount
Select
BL.PartNum PartNumber,
PBLH.ParentPartNum NextBOM,
(select-NextBOMItemCount),
BOMItemCount TotalQty,
PL.Description,
BL.MP as PartType,
PL.Vendor,
PL.QBType
from
NEWprojectBOMItemcount BL,
bomwiz.partslist PL,
bomwiz.projectbomlistheirarchy PBLH
Where
BL.PartNum = PL.PartNum
And BL.PartNum = PBLH.PartNum
And BL.ProjectCode = PBLH.ProjectCode
And BL.projectCode = 'AB212323'
Order By PartNumber
I think that you are looking for conditional aggregation. Your requirement could be expressed as follows:
SUM(
CASE WHEN blh.ParentPartNum = bl.PartNum
THEN pm.Quantity * bl.TotalQty
ELSE 0
END
) AS NextBOMItemCount
Let me pinpoint other issues with your query:
you have unwanted parentheses all around, and I am suspicious about the syntax of the JOINs ; you need to move conditions to the ON clause of the relevant JOIN.
every non-aggregated column must appear in the GROUP BY clause - you have missing columns there
backquotes are usually not needed
Here is an updated version of the query:
SELECT
pm.ProjectCode AS ProjectCode,
bl.PartNum AS PartNum,
SUM(pm.Quantity * bl.TotalQty) AS BOMItemCount,
SUM(
CASE WHEN blh.ParentPartNum = bl.PartNum
THEN pm.Quantity * bl.TotalQty
ELSE 0
END
) AS NextBOMItemCount,
bl.mp AS mp,
p.complete AS complete,
bl.RMInd AS RMInd,
bl.M_PartNum AS M_PartNum
FROM
projectmachine AS pm
INNER JOIN projectbomlist AS bl
ON pm.MachineListID = bl.MachineListID
AND pm.ProjectCode = bl.ProjectCode
INNER JOIN join projects AS p
ON pm.ProjectCode = p.ProjectCode
AND p.AfterProjectHeirarchyInd = 'Y'
INNER JOIN projectbomlistheirarchy blh
ON bl.ProjectCode = blh.ProjectCode
WHERE
pm.ProjectCode = 'AB212323'
GROUP BY
pm.ProjectCode,
bl.PartNum,
bl.mp,
p.complete,
bl.RMInd,
bl.M_PartNum
ORDER BY
pm.ProjectCode,
bl.PartNum

How can I create a WHERE clause where there are some mandatory fields and some other optional fields in a SQL query

I am not so into database and I have the following doubt. I am using MySql
I have this query that return multiple records (it works fine) and I have to add the WHERE clause in such a way that some fields are mandatory and some other fields are optional.
So I have this query:
SELECT
EnutrifoodMessage.content
, MessageType.message_type_name
, Country.country_name
, IFNULL(Province.province_name, 'All Provinces') as province_name
, IFNULL(District.district_name, 'Any District') as district_name
, Crop.crop_name
, EnutriMessageDetails.creation_date
, EnutriMessageDetails.message_important_days
, temp_scale.scale_name as temperature
, humidity_scale.scale_name as humidity
, ProcessPhase.phase_name
, ProcessPhaseAction.process_phase_action_name
, Urgency.urgency_name as action
, IFNULL(MeteoWarningDescription.meteo_warning_description_name, '') as emergency
, IFNULL(EnutriMessageDetails.internal_link, '') as internal_link
, IFNULL(EnutriMessageDetails.reference_link, '') as reference_link
, IFNULL(EnutriMessageDetails.external_link, '') as external_link
, IFNULL(cleared_by_institution.institution_name, '') as message_cleared_by
, UserType.user_type_name as end_user
, provider.institution_name as provider
, ValueAddition.value_addition_name
FROM EnutriMessageDetails
LEFT JOIN EnutrifoodMessage
ON EnutrifoodMessage.id = EnutriMessageDetails.enutri_food_message_id
LEFT JOIN MessageType
ON MessageType.id = EnutriMessageDetails.message_type_id
LEFT JOIN Localization
ON Localization.id = EnutriMessageDetails.localization_id
LEFT JOIN Country
ON Country.id = Localization.country_id
LEFT JOIN Province
ON Province.id = Localization.province_id
LEFT JOIN District
ON District.id = Localization.district_id
LEFT JOIN Crop
ON Crop.id = EnutriMessageDetails.crop_id
LEFT JOIN Scale temp_scale
ON temp_scale.id = EnutriMessageDetails.temp_scale_id
LEFT JOIN Scale humidity_scale
ON humidity_scale.id = EnutriMessageDetails.humidity_scale_id
LEFT JOIN ProcessPhase
ON ProcessPhase.id = EnutriMessageDetails.process_phase_id
LEFT JOIN ProcessPhaseAction
ON ProcessPhaseAction.id = EnutriMessageDetails.process_phase_action_id
LEFT JOIN Urgency
ON Urgency.id = EnutriMessageDetails.urgency_id
LEFT JOIN MeteoWarningDescription
ON MeteoWarningDescription.id = EnutriMessageDetails.meteo_warning_description_id
LEFT JOIN Institution cleared_by_institution
ON cleared_by_institution.id = EnutriMessageDetails.cleared_by_id
LEFT JOIN UserType
ON UserType.id = EnutriMessageDetails.user_type_id
LEFT JOIN Institution provider
ON provider.id = EnutriMessageDetails.provided_by_id
LEFT JOIN ValueAddition
ON ValueAddition.id = EnutriMessageDetails.value_addition_id
WHERE Localization.id = 2
AND Crop.id = 2
ORDER BY EnutrifoodMessage.id
I need to add the WHERE clause in such a way that:
1) This field is mandatory:
Localization.id = 2
UserType.id = 1
2) These other fields are optional:
EnutriMessageDetails.creation_date >= a specified date
Urgency.id = 3
I want that the first type of field have to be inserted, the other type have to be optional and can be not fill.
How can I correctly handle this situation?
Try case expression:
Where Localization.id = 2 and UserType.id = 1 and
1 = case when EnutriMessageDetails.creation_date >= **[a specified date]**
then case when and Urgency.id = 3
then 1
else 0
end
else 1
end
Edit: Correction.
Please try the following to test if it will work this is to check if its null or not. So then you can react on it.
WHERE Urgency.id LIKE CASE WHEN Urgency.id IS NULL
THEN Urgency.id
ELSE CONCAT('%', Urgency.id, '%')
END
I dont have a testing environment for mySql so please check if it will work just trying to help.
It seems you want:
WHERE (urgency.id = #urgencyid OR #urgencyid IS NULL)
or
ON (urgency.id = #urgencyid OR #urgencyid IS NULL)
So when an ID is given, only data matching the ID will be selected, and if no ID is given, all data will.
The WHERE clause will not select any record if the ID does not exist in the table. So the urgency table should be inner-joined. If it is outer-joined, the WHERE clause turns it into an inner join, as records with ID null will be dismissed. Avoid such pseudo outer joins.
For an inner join it doesn not matter whether to use WHERE or ON. For an outer join, however, the WHERE clause would turn it into an inner join as mentioned, whereas the ON clause would still outer-join (with a given ID, either the ID is found or an empty dummy record joined).

Doctrine limit is breaking my query?

I have the following code:
$params = array();
$query_questions_visibles = questionTable::getInstance()->createQuery("q")
->select("q.*, ua.*, a.*, u.*, c.*")
->leftJoin("q.Answers a")
->leftJoin("a.UserAnswers ua")
->Where("q.blocked = false")
->andWhere("ua.user_id = :user_id")
->orderBy("q.id DESC")
->groupBy("q.id");
//Subquery --> Calculates when a question is active or not
$format = sfConfig::get("app_datetime_format");
$active_time = date($format, strtotime(sfConfig::get("app_question_active_time")));
$sub_query_is_active = $query_questions_visibles->createSubQuery()
->select("MAX(ua0.created_at)")
->from("question q0")
->leftJoin("q0.Answers a0")
->leftJoin("a0.UserAnswers ua0")
->where("q0.id = q.id");
$query_questions_visibles->addSelect("COALESCE((".$sub_query_is_active.") > :active_time, false) as Active");
//Set param values
$params["user_id"] = $guardUser->id;
$params["active_time"] = $active_time;
$result = $query_questions_visibles->execute($params);
The previous code works as expected.
Generated SQL is complete and works:
SELECT q.id AS q__id, q.user_id AS q__user_id, q.category_id AS q__category_id, q.gender_restriction AS q__gender_restriction, q.question AS q_question, q.photo AS q_photo, q.latitude AS q_latitude, q.longitude AS q_longitude, q.multiple AS q_multiple, q.blocked AS q_blocked, q.created_at AS q__created_at, q.updated_at AS q__updated_at, a.id AS a__id, a.question_id AS a__question_id, a.text AS a_text, u.id AS u_id, u.user_id AS u__user_id, u.answer_id AS u__answer_id, u.created_at AS u__created_at, u.updated_at AS u__updated_at, COALESCE((SELECT MAX(u2.created_at) AS u2__0 FROM question q2 LEFT JOIN answer a2 ON q2.id = a2.question_id LEFT JOIN user_answer u2 ON a2.id = u2.answer_id WHERE (q2.id = q.id)) > :active_time, 0) AS u2__0 FROM question q LEFT JOIN answer a ON q.id = a.question_id LEFT JOIN user_answer u ON a.id = u.answer_id WHERE (q.blocked = 0 AND u.user_id = :user_id) GROUP BY q.id ORDER BY q.id DESC
But, if I want to limit results, I modify the end lines as:
$query_questions_visibles->limit(10);
$result = $query_questions_visibles->execute($params);
Doctrine throws an error:
SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens
at Doctrine_Connection->execute('SELECT DISTINCT q2.id FROM question q2 LEFT JOIN answer a2 ON q2.id = a2.question_id LEFT JOIN user_answer u2 ON a2.id = u2.answer_id WHERE q2.blocked = 0 AND u2.user_id = :user_id GROUP BY q2.id ORDER BY q2.id DESC LIMIT 10', array('user_id' => '1', 'active_time' => '2013-03-17 17:12:12')) in SF_ROOT_DIR\lib\vendor\symfony\lib\plugins\sfDoctrinePlugin\lib\vendor\doctrine\Doctrine\Query.php line 1290 ...
My purpose is only limit the query to 10 results, ¿where is my Subquery with COALESCE and MAX functions? ¿Why there's a SELECT DISTINCT who I never specified? ¿Why is selecting only q.id?
I spend all day trying to figure it out, i have no answer...
Any Ideas why setting a limit causes this?
When you add limit() to the Doctrine query then the Doctrine internals create in fact two queries. The first one select a limited set of distinct ids based on the conditions of your query. The second query selects the actual objects limiting the select to the ids found with the first query.
The problem with your query is that you use params inside of the select part, which is not used in the first query.
The only solutuion that comes to my mind is to add the value of the active_time parameter directly to the select part, without using the named param. It might not be the nicest solution but I can't think of a different one right now. The addSelect() does not accept additional parameters like where() does which could fix the issue (with where() you can use: ->where('field > ?', $value)).