Mysql Join for 3 tables - mysql

I have checked former posts and none has solved my problem yet, any help would be appreciated
MYSQL query to 3 tables (Users, Match, Interview)
Want to return the users name and interview # (if there is an interview number) for the specified Match.
But I do not want to limit the results to only users who have an interview. I tried JOIN, but cannot get it to work for 3 tables.
Here is what I have so far in PHP:
$query = "SELECT CONCAT(u.first_name,' ',u.last_name,'----',COALESCE(i.v_code,'')) as name, u.id as id
FROM #__users as u
JOIN #__bl_match as m ON ( (u.team_id = m.team1_id) OR
(u.team_id = m.team2_id) OR
(u.team_id = m.team3_id AND m.team3_id != 0) OR
(u.team_id = m.team4_id AND m.team4_id != 0) OR
(u.team_id = m.team5_id AND m.team5_id != 0) OR
(u.team_id = m.team6_id AND m.team6_id != 0) OR
(u.team_id = m.team7_id AND m.team7_id != 0) OR
(u.team_id = m.team8_id AND m.team8_id != 0) OR
(u.team_id = m.team9_id AND m.team9_id != 0) OR
(u.team_id = m.team10_id AND m.team10_id != 0))
AND m.id = ".$t_id."AND m.id != 0
JOIN #__bl_interview as i ON i.u_id = u.id";
$db->setQuery($query);
$parti12 = $db->loadObjectList();

If you want Users with no Interview, you'll need to use a LEFT JOIN to the interview table, but that means the interview number for that user will be NULL.
Since you're concatenating the number with the user name in your SELECT list, this results in the user's name being returned as NULL when they've got no interviews (since concatenating a string with a NULL value - or performing pretty much any other operation on a NULL value - produces a NULL result).
To avoid this, you must handle the case when i.v_code is NULL. The typical way to do that in MySQL is with the COALESCE function:
SELECT CONCAT(u.first_name, ' ', u.last_name, '----', COALESCE(i.v_code,'')) as name,
u.id as id
FROM #__users as u
JOIN #__bl_match as m ON ( (u.team_id = m.team1_id) OR
(u.team_id = m.team2_id) OR
(u.team_id = m.team3_id AND m.team3_id != 0) OR
(u.team_id = m.team4_id AND m.team4_id != 0) OR
(u.team_id = m.team5_id AND m.team5_id != 0) OR
(u.team_id = m.team6_id AND m.team6_id != 0) OR
(u.team_id = m.team7_id AND m.team7_id != 0) OR
(u.team_id = m.team8_id AND m.team8_id != 0) OR
(u.team_id = m.team9_id AND m.team9_id != 0) OR
(u.team_id = m.team10_id AND m.team10_id != 0))
AND m.id = ".$t_id."AND m.id != 0
LEFT JOIN #__bl_interview as i ON i.u_id = u.id"
Now, given the formatting you're applying to the name, you may be left with an extraneous ---- after the name with no subsequent interview code. If you'd like to avoid that, we can use IF instead of COALESCE to get a little smarter with our output, like so:
SELECT CONCAT(u.first_name, ' ', u.last_name, IF(i.v_code, '---- ' + i.v_code, '')) as name
Note what that's doing: if i.v_code is not NULL, the first expression in the IF evaluates to true, so the second expression is returned. Otherwise, the third expression (the empty string) is returned - so when i.v_code is NULL, you only output the user's name.

Related

Linq to Sql 3 joins with group and min()

I'm trying to convert the SQL below to Linq. I haven't figured out the syntax for the GROUP BY, the MIN() or the extra organization join conditions.
SELECT DISTINCT o.OrganizationHierarchyUnitLevelThreeNm, o.OrganizationHierarchyUnitLevelFourNm, a.LabAssetSerialNbr, MIN(a.SystemCreatedOnDtm) MinCreated
FROM vw_DimLabAsset a
INNER JOIN vw_FactWorker w ON a.LabAssetAssignedToWorkerKey = w.WorkerKey
INNER JOIN vw_DimOrganizationHierarchy o ON w.OrganizationHierarchyKey = o.OrganizationHierarchyKey
AND o.OrganizationHierarchyUnitLevelThreeNm IS NOT NULL
AND o.OrganizationHierarchyUnitLevelFourNm IS NOT NULL
GROUP BY o.OrganizationHierarchyUnitLevelThreeNm, o.OrganizationHierarchyUnitLevelFourNm, a.LabAssetSerialNbr
This is what I've managed to get so far:
var pphw = from a in Vw_DimLabAsset
where a.LabAssetHardwareStatus != "Retired" && (a.LabAssetHardwareSubStatus == null || a.LabAssetHardwareSubStatus != "Archive") && types.Contains(a.LabAssetTypeNm) // (a.LabAssetTypeNm == "u_cmdb_ci_prototype_system" || a.LabAssetTypeNm == "u_cmdb_ci_silicon")
join w in Vw_FactWorker on a.LabAssetAssignedToWorkerKey equals w.WorkerKey
join o in Vw_DimOrganizationHierarchy on w.OrganizationHierarchyKey equals o.OrganizationHierarchyKey
select new { o.OrganizationHierarchyUnitLevelThreeNm, o.OrganizationHierarchyUnitLevelFourNm, a.LabAssetSerialNbr };
Here is how I would translate the query:
var ans = (from a in vw_DimLabAsset
join w in vw_FactWorker on a.LabAssetAssignedToWorkerKey equals w.WorkerKey
join o in vw_DimOrganizationHierarchy on w.OrganizationHierarchyKey equals o.OrganizationHierarchyKey
where o.OrganizationHierarchyUnitLevelThreeNm != null && o.OrganizationHierarchyUnitLevelFourNm != null
group new { o, a } by new { o.OrganizationHierarchyUnitLevelThreeNm, o.OrganizationHierarchyUnitLevelFourNm, a.LabAssetSerialNbr } into oag
select new {
oag.Key.OrganizationHierarchyUnitLevelThreeNm,
oag.Key.OrganizationHierarchyUnitLevelFourNm,
oag.Key.LabAssetSerialNbr,
MinCreated = oag.Min(oa => oa.a.SystemCreatedOnDtm)
}).Distinct();

MYSQL join return too many results

So I'm trying to get some total numbers of different tables in the database.
This is the query that I'm using
$this->db->select('
c.*,
SUM(rm.discount_value) as totalDiscount,
SUM(a.status = 0) as totalVisits,
SUM(a.status != 0) as totalAnnulations,
SUM(r.treatment_price + r.arrangement_price + r.product_price) + c.start_rev as totalRevenue
')
->join('customers c','c.customer_id = a.customer_id','left')
->join('revenue r','r.customer_id = a.customer_id','left')
->join('remarks rm','rm.customer_id = a.customer_id','left')
->from('agenda a')
->where('a.user_id',$user_id)
->where('a.customer_id',$customer_id)
->group_by('a.customer_id');
This results in the following query.
SELECT `c`.*,
SUM(rm.discount_value) as totalDiscount,
SUM(a.status = 0) as totalVisits, SUM(a.status != 0) as totalAnnulations,
SUM(r.treatment_price + r.arrangement_price + r.product_price) + c.start_rev as totalRevenue
FROM (`agenda` a)
LEFT JOIN `customers` c ON `c`.`customer_id` = `a`.`customer_id`
LEFT JOIN `revenue` r ON `r`.`customer_id` = `a`.`customer_id`
LEFT JOIN `remarks` rm ON `rm`.`customer_id` = `a`.`customer_id` WHERE `a`.`user_id` = '9' AND `a`.`customer_id` = '4134'
GROUP BY `a`.`customer_id`
This query is returning 4810 visits, but there are only 74.
This returns too many results. Its like its not using that a.customer_id
Any help is welcome, thanks in advance.
You are using GROUP BY with a column that does not appear in the SELECT. See how to use GROUP BY.

How can I set dynamic optional WHERE clauses into a SQL query? (if the value of the parameter is not null)

I am not so into database and I have a problem with a query. I am working on MySql.
I have this query that contains a single WHERE clause that is mandatory and some other WHERE clauses that are optional, something like this:
WHERE Localization.id = 2
AND(
Crop.id = 2
OR
ProcessPhase.id = 1
OR
ProcessPhaseAction.id = 1
OR
UserType.id = 1
OR
Urgency.id = 1
OR
EnutriMessageDetails.provided_by_id = 1
OR
EnutriMessageDetails.cleared_by_id = 1
)
The Localization.id is the mandatory clause, the other into the AND are optional. I implemented in this way but I think that it is not good.
My original idea is that if the value of a field is null this specific where clause is deleted from the clauses list.
For example, I want to put all the clauses using the AND (avoiding the OR) and if I have something:
Crop.id = null
this clause it is removed from the clauses list.
I know that I can do it using a programming language appending the clauses with an IF statment ( IF is not null then append) but in this case this query will nor run into a program so I can't do it so I have to use only SQL.
How can I do it using only SQL?
EDIT-1:
This is the updated clauses version but it still not works:
WHERE Localization.id = 2
AND
(EnutriMessageDetails.crop_id = 2 OR EnutriMessageDetails.crop_id IS NULL)
AND
(EnutriMessageDetails.process_phase_id = 2 OR EnutriMessageDetails.process_phase_id IS NULL)
AND
(EnutriMessageDetails.process_phase_action_id = 2 OR EnutriMessageDetails.process_phase_action_id IS NULL)
AND
(EnutriMessageDetails.user_type_id = 2 OR EnutriMessageDetails.user_type_id IS NULL)
AND
(EnutriMessageDetails.urgency_id = 2 OR EnutriMessageDetails.urgency_id IS NULL)
AND
(EnutriMessageDetails.provided_by_id = 2 OR EnutriMessageDetails.provided_by_id IS NULL)
AND
(EnutriMessageDetails.cleared_by_id = 2 OR EnutriMessageDetails.cleared_by_id IS NULL)
EDIT-2: this is the entire 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
(EnutriMessageDetails.crop_id = 2 OR EnutriMessageDetails.crop_id IS NULL)
AND
(EnutriMessageDetails.process_phase_id = 2 OR EnutriMessageDetails.process_phase_id IS NULL)
AND
(EnutriMessageDetails.process_phase_action_id = 2 OR EnutriMessageDetails.process_phase_action_id IS NULL)
AND
(EnutriMessageDetails.user_type_id = 2 OR EnutriMessageDetails.user_type_id IS NULL)
AND
(EnutriMessageDetails.urgency_id = 2 OR EnutriMessageDetails.urgency_id IS NULL)
AND
(EnutriMessageDetails.provided_by_id = 2 OR EnutriMessageDetails.provided_by_id IS NULL)
AND
(EnutriMessageDetails.cleared_by_id = 2 OR EnutriMessageDetails.cleared_by_id IS NULL)
ORDER BY EnutrifoodMessage.id
You can use:
AND (Crop.id = 2 OR Crop.id IS NULL) AND ...
If Crop.id is NULL then the expression in the parenthesis is equal to 1 (true).

Filter mysql results based on checkboxes

I am trying to filter mysql results based on checkboxes that have been ticked. My query works on the first check but returns nothing on the second filter. My checkbox array is $_POST['country'] which I implode in the GetSQLValueString function to create the comma separated values - (United Kingdom, France) etc. I am using the MySQL IN clause for the multiple selections.
I need it to filter multiple country selections
if (isset($_POST['country_submit']) && $_POST['country'] != '') {
mysql_select_db($database_tub, $tub);
$query_trade = sprintf("
SELECT u.user_id,
u.contact_person,
u.company,
u.country,
u.pic_small,
u.website,
SUM(u.trader_or_bond = %s
AND t.user_id IS NOT NULL) AS count
FROM users u
LEFT JOIN trading t ON u.user_id = t.user_id
WHERE u.trader_or_bond = %s AND u.country IN(%s)
GROUP BY u.user_id
ORDER BY COUNT(t.user_id) DESC",
GetSQLValueString('trader', "text"),
GetSQLValueString('trader', "text"),
GetSQLValueString(implode(',', $_POST['country']), "text"));
$trade = mysql_query($query_trade, $tub) or die(mysql_error());
}
I have come up with this but not sure if safe for MySQL injection plus its not as clean as I would like.
if (isset($_POST['country_submit']) && $_POST['country'] != '') {
$SingleQuotes = "'".implode("', '", array_map('mysql_real_escape_string', $_POST['country']))."'";
mysql_select_db($database_tub, $tub);
$query_trade = sprintf("
SELECT u.user_id,
u.contact_person,
u.company,
u.country,
u.pic_small,
u.website,
SUM(u.trader_or_bond = %s
AND t.user_id IS NOT NULL) AS count
FROM users u
LEFT JOIN trading t ON u.user_id = t.user_id
WHERE u.trader_or_bond = %s AND u.country IN($SingleQuotes)
GROUP BY u.user_id
ORDER BY COUNT(t.user_id) DESC",
GetSQLValueString('trader', "text"),
GetSQLValueString('trader', "text"));
$trade = mysql_query($query_trade, $tub) or die(mysql_error());
}

Help to convert this sql query to 'JOIN' syntax

I am new to SQL. Can someone help to convert this query, so it uses join syntax?
SELECT groups.name,
users.firstname,
users.lastname,
users.emailaddress,
groupmembers.userid,
reminders.groupid,
reminders.ownerid,
reminderdetails.recno,
reminderdetails.cardid,
reminderdetails.message
FROM reminderdetails,
reminders,
groupmembers,
users,
groups
WHERE assocdate = 'Y'
AND ( reminder1 != 99
AND ( Datediff(reminderdate, '2011-09-22') = reminder1 )
OR ( reminder2 != 99
AND Datediff(reminderdate, '2011-09-22') = reminder2 ) )
AND reminders.cardid = reminderdetails.cardid
AND groupmembers.groupid = reminders.groupid
AND groupmembers.sendemail = 'Y'
AND users.recno = groupmembers.userid
AND groups.recno = reminders.groupid
Try this:
SELECT g.name,
uu.firstname,
uu.lastname,
uu.emailaddress,
gp.userid,
rm.groupid,
rm.ownerid,
rd.recno,
rd.cardid,
rd.message
FROM reminderdetails rd
JOIN reminders rm on rm.cardid=rd.cardId
JOIN groupmembers gp on gp.groupid=rm.groupId and gp.sendemail='Y'
JOIN users uu on uu.recNo=gp.userId,
JOIN groups g ON g.recno=rm.groupId
WHERE assocdate = 'Y'
AND ( reminder1 != 99
AND ( Datediff(reminderdate, '2011-09-22') = reminder1 )
OR ( reminder2 != 99
AND Datediff(reminderdate, '2011-09-22') = reminder2 ) )
Bit of a guess without knowing your table structure, but I think this seems about right.
Edit: Just seen the other one; I'd generally prefer to not load up the JOIN with too many clauses, as you end up going hunting all over the place when you want to find out what WHERE clauses are being applied. If possible, I think it's better to keep JOINs containing just the JOIN and put the rest into the WHERE.
I'm sure someone else can come along and shoot me down on that one, but that's my take on it :)
SELECT groups.name,
users.firstname,
users.lastname,
users.emailaddress,
groupmembers.userid,
reminders.groupid,
reminders.ownerid,
reminderdetails.recno,
reminderdetails.cardid,
reminderdetails.message
FROM groups
INNER JOIN groupmembers ON groups.groupid = groupmembers.groupid
INNER JOIN users ON groupmembers.userid = users.userid
INNER JOIN reminders ON users.userid = reminders.ownderid
INNER JOIN reminderdetails ON reminders.cardid = reminderdetails.cardid
WHERE assocdate = 'Y'
AND ( reminder1 != 99
AND ( Datediff(reminderdate, '2011-09-22') = reminder1 )
OR ( reminder2 != 99
AND Datediff(reminderdate, '2011-09-22') = reminder2 ) )
AND groupmembers.sendemail = 'Y'