MYSQL Inner Join with IF Statement - mysql

I'm trying to join several tables in my database.
I need to get account information from the 'accounts' table with the latest meter history on it.
And if an account has no meter history, I want it to show 'meter' related fields as NULL.
Here's my query so far:
SELECT
accounts.id,
accounts.account_order,
acc.id AS accounts_class_id,
acc.zone,
acc.book,
acc.service_class,
acc.size,
acc.account_no AS series_no,
accounts.status,
application_address.address_line,
concessionaires.firstname,
concessionaires.middlename,
concessionaires.lastname,
mb.brand_name,
m.meter_no,
ms.meter_status
FROM
accounts
INNER JOIN
applications
ON accounts.application_id = applications.id
LEFT JOIN
application_address
ON applications.application_no = application_address.application_no
LEFT JOIN
concessionaires
ON applications.concessionaire_no = concessionaires.concessionaire_no
INNER JOIN
accounts_classifications acc
ON accounts.id = acc.account
INNER JOIN meter_history mh
ON mh.id = (SELECT id FROM meter_history mh2
WHERE mh2.account_id = accounts.id
ORDER BY mh2.status_date DESC
LIMIT 1)
LEFT JOIN
meter_status ms
ON mh.meter_status = ms.id
INNER JOIN
meter m
ON mh.meter = m.id
LEFT JOIN
meter_brand mb
ON m.meter_brand = mb.id
WHERE
acc.book = 1 AND acc.zone = 20 AND applications.status = '6' AND acc.status = '1'
This would return only accounts with meter history on it.
Where should I put my IF condition so I get accounts with no history as well, or if that is even possible with my query. Thank you!

Related

Mysql subqueries problem with data retrieved

I'm trying to run a query but my outcome is not what i need.
So the problem is:
A user can be diretor and if this is the case he can see all activities from his department, and he can be user of another department too, in this case not director but only user.
I have 8 departments each with one director, so the following query should give me the activities of the department and the activities of this particular user in other department:
SELECT t1.idAtividade,
t1.idProfessor,
t2.Escola,
t1.Atividade,
t1.Periodo,
t1.Mes,
t1.haveClasses,
t1.DataPrevista,
t1.Destinatarios,
t1.Orcamento,
t1.PdfAtividade,
t1.Avaliacao,
t1.PdfAvaliacao,
t1.idProfessor,
p.Nome,
g.Grupo,
d.Departamento,
p2.Projeto,
t1.idProjeto
FROM atividades AS t1
INNER JOIN professores p on t1.idProfessor = p.idProfessor
INNER JOIN atividadesgrupos ag on t1.idAtividade = ag.idAtividade
INNER JOIN grupos g on ag.idGrupo = g.idGrupo
INNER JOIN departamentosatividades da on t1.idAtividade = da.idAtividade
INNER JOIN departamentos d on da.idDepartamento = d.idDepartamento
INNER JOIN escolas AS t2 ON (t2.idEscola = t1.idEscola)
INNER JOIN anosescolares AS ae ON (t1.idAnoEscolar = ae.idAnoEscolar)
INNER JOIN projetos p2 on t1.idProjeto = p2.idProjeto
WHERE ae.Estado = 1 AND (da.idDepartamento = :id_dpt and ag.idGrupo = :idGrupo)
ORDER BY (t1.idProfessor = :idProfessor) DESC, t1.idProfessor;");
This query is not working because the department have 22 activities but this user (idProfessor) has 5 in this department and 14 more in another department (defined by idGrupo)
I think i will need a subquery right?

SQL Optimization - Query take 15 seconds

I have 400 rows every tables. So, I will try to relationship every tables using LEFT JOIN based on ID, but my query takes 15 seconds, and this is my query:
SELECT
sender.id AS id,
sender.letter AS letter,
sender.date AS date,
mediaseller.contract_number AS contract,
sender.company AS company,
brand.value AS brand,
sender.message_category AS message_category,
sender.message_format AS message_format,
sender.senderid AS senderid,
cpname.value AS cpname,
sid.value AS sid,
status.status AS status,
sender.remarks AS remarks,
user.name AS name,
sender.id AS download,
mediaseller.value AS mediaseller,
lob.value AS lob,
lob.subvalue AS sublob,
sms_type.value AS type_sms,
status.approval_date,
status.batch_date,
status.done_date,
status.decline_date
FROM status
LEFT JOIN sender ON status.trxid = sender.trxid
LEFT JOIN user ON status.userid = user.id
LEFT JOIN mediaseller ON sender.mediaseller = mediaseller.id
LEFT JOIN lob ON sender.industry_category = lob.id
LEFT JOIN sms_type ON sender.type_sms = sms_type.id
LEFT JOIN cpname ON sender.cpname = cpname.id
LEFT JOIN sid ON sender.trxid = sid.trxid
LEFT JOIN brand ON sender.brand = brand.id
WHERE status.hidden = 0
ORDER BY status.id DESC LIMIT 10
I hopeful is query takes one seconds :D
Please give me advice, Thankyou!
You are not filtering by anything other than the status. So try this:
FROM (SELECT s.*
FROM status s
WHERE s.hidden = 0
ORDER BY status.id DESC
LIMIT 10
) status
LEFT JOIN sender ON status.trxid = sender.trxid
LEFT JOIN user ON status.userid = user.id
LEFT JOIN mediaseller ON sender.mediaseller = mediaseller.id
LEFT JOIN lob ON sender.industry_category = lob.id
LEFT JOIN sms_type ON sender.type_sms = sms_type.id
LEFT JOIN cpname ON sender.cpname = cpname.id
LEFT JOIN sid ON sender.trxid = sid.trxid
LEFT JOIN brand ON sender.brand = brand.id
WHERE status.hidden = 0
ORDER BY status.id DESC LIMIT 10
You still need the outer ORDER BY and LIMIT, but they should be on much less data resulting in a performance improvement.
Note: I assume that you have declared all the ids as primary keys, so they have indexes.

slow query with joins

Please am having difficulty in optimizing this query. What am trying to achieve is to join about 8 tables, of which only about 3 of the tables contains large data (1.5m records). This query returns expected records but is taking 1min to run which is bad.
I know it can be optimized to perform far better, pls i need assistance from you experts. I have index on the fields used for join already.
SELECT topic_id,
topic_title,
unit_name_abbrev,
sch_name_abbrev,
picture_small_url AS thumbnail,
profile_pix_upload_path,
first_name,
last_name,
topic_poster,
topic_replies,
topic_views,
topic_last_post_time AS topic_post_time,
sch_sub_forum_id
FROM (_sch_forum_topics
INNER JOIN _users
ON ( _users.userid = _sch_forum_topics.topic_poster )
INNER JOIN _profile
ON _profile.userid = _users.userid
INNER JOIN _class
ON _users.classid = _class.classid
INNER JOIN _level
ON _class.level_id = _level.id
INNER JOIN _unit
ON _class.unitid = _unit.unitid
INNER JOIN _department
ON _unit.deptid = _department.deptid
INNER JOIN _faculty
ON _department.facid = _faculty.facid
INNER JOIN _university
ON _faculty.schid = _university.schid)
WHERE _sch_forum_topics.sch_sub_forum_id = 4
ORDER BY _sch_forum_topics.topic_last_post_time DESC
LIMIT 0, 15
Try to filter before making JOIN's.
SELECT topic_id,
topic_title,
unit_name_abbrev,
sch_name_abbrev,
picture_small_url AS thumbnail,
profile_pix_upload_path,
first_name,
last_name,
topic_poster,
topic_replies,
topic_views,
topic_last_post_time AS topic_post_time,
sch_sub_forum_id
FROM
( select * FROM sch_forum_topics WHERE sch_sub_forum_id = 4
ORDER BY topic_last_post_time DESC
LIMIT 0, 15 ) main
INNER JOIN _users
ON ( _users.userid = main.topic_poster )
INNER JOIN _profile
ON _profile.userid = _users.userid
INNER JOIN _class
ON _users.classid = _class.classid
INNER JOIN _level
ON _class.level_id = _level.id
INNER JOIN _unit
ON _class.unitid = _unit.unitid
INNER JOIN _department
ON _unit.deptid = _department.deptid
INNER JOIN _faculty
ON _department.facid = _faculty.facid
INNER JOIN _university
ON _faculty.schid = _university.schid);

SQL JOIN Query - linking four tables

I have the SQL to display ALL the activities and relative Admin permissions (if any) for that activity.
Current SQL Code:
SELECT `activities`.*, `admins`.`admin_role_id`
FROM (`activities`)
LEFT JOIN `admins` ON `admins`.`activity_id`=`activities`.`id` AND admins.member_id=27500
WHERE `activities`.`active` = 1
Returning:
id | name | description | active | admin_role_id (or null)
I then need to detect whether they are an active member within that Activity.
I have the following SQL code:
SELECT DISTINCT `products`.`activity_ID` as joinedID
FROM (`transactions_items`)
JOIN `transactions` ON `transactions`.`id` = `transactions_items`.`id`
JOIN `products` ON `products`.`id` = `transactions_items`.`product_id`
JOIN `activities` ON `activities`.`id` = `products`.`activity_ID`
WHERE `transactions`.`member_id` = 27500
AND `activities`.`active` = 1
Is there any way to merge this into one SQL query. I can't figure out how to use the correct JOIN queries, because of the complexity of the JOINs.
Help please, thanks! :)
Try like this
SELECT `activities`.*, `admins`.`admin_role_id`
FROM (`activities`)
LEFT JOIN `admins` ON `admins`.`activity_id`=`activities`.`id` AND admins.member_id=27500
JOIN (`transactions_items`
JOIN `transactions` ON `transactions`.`id` = `transactions_items`.`id`
JOIN `products` ON `products`.`id` = `transactions_items`.`product_id`)
ON `activities`.`id`=`products`.`activity_ID`
WHERE `transactions`.`member_id` = 27500
AND `activities`.`active` = 1
Seems to me that a query like this would be marginally more comprehensible and (I think) adhere more closely to the spec...
SELECT c.*
, d.admin_role_id
FROM activities c
LEFT
JOIN admins d
ON d.activity_id = c.id
AND d.member_id = 27500
LEFT
JOIN products p
ON p.activity_ID = c.id
LEFT
JOIN transactions_items ti
ON ti.product_id = p.id
LEFT
JOIN transactions t
ON t.id = ti.id
AND t.member_id = 27500
WHERE c.active = 1

MySQL / PHP - 2 different arguments for 1 table

I have the following SQL:
$queryString = "
SELECT
iR.lastModified,
d.*,
c2.title as stakeholderTitle,
u.username as authorUsername,
c.title as authorContactName,
GROUP_CONCAT(iR.stakeholderRef) AS participants
FROM
informationRelationships iR,
contacts c2
INNER JOIN
debriefs d ON
d.id = iR.linkId
LEFT JOIN
users u ON
u.id = iR.author
LEFT JOIN
contacts c ON
c.ref = u.contactId
LEFT JOIN
debriefs d2 ON
d2.stakeholder = c2.ref
WHERE
(
iR.clientRef = '$clientRef' OR
iR.contactRef = '$contactRef'
)
AND
iR.projectRef = '$projectRef' AND
iR.type = 'Debrief'
GROUP BY
iR.linkId
ORDER BY
d.dateOfEngagement
";
notice how I require 2 different bits of data for the the contacts table.
So at one point, I need to match
c.ref = u.contactId
This will return one bit of information
but I also need a completely different grouping:
d2.stakeholder = c2.ref
Problem is that the title is the column i'm interested in for both:
c2.title as stakeholderTitle,
...
c.title as authorContactName
How do I go about doing this?
My current try is returning:
Error: Unknown column 'iR.linkId' in 'on clause'
I'm not sure I really understand what is happening here:
how to join two tables on common attributes in mysql and php?
EDIT::::---ANSWERED--zerkms
$queryString = "
SELECT
iR.lastModified,
d.*,
c2.title as stakeholderTitle,
u.username as authorUsername,
c.title as authorContactName,
GROUP_CONCAT(iR.stakeholderRef) AS participants
FROM
informationRelationships iR
INNER JOIN
debriefs d ON
d.id = iR.linkId
INNER JOIN
contacts c2 ON
d.stakeholder = c2.ref
LEFT JOIN
users u ON
u.id = iR.author
LEFT JOIN
contacts c ON
c.ref = u.contactId
WHERE
(
iR.clientRef = '$clientRef' OR
iR.contactRef = '$contactRef'
)
AND
iR.projectRef = '$projectRef' AND
iR.type = 'Debrief'
GROUP BY
iR.linkId
ORDER BY
d.dateOfEngagement
";
By re-ordering my query I have managed to get both columns in... Thanks zerkms!
You cannot mix implicit joins and explicit joins in a single query in mysql.
So
FROM informationRelationships iR,
contacts c2
should be rewritten to
FROM informationRelationships iR
INNER JOIN contacts c2 ON ...
Do not use cartesian product and joins in the same query (not subquery), here, use only joins (CROSS JOIN is the same as cartesian product).