Optimising Multiple Joins to the same table MySQL - mysql

I have a query which joins in the same table (user_status) multiple times in order to pull back different status information. The overall goal of this query is to turn it in to a view. I believe that these joins are causing latency in the query run time, which is causing the query to hang. I am trying to optimise the query as much as possible, but don't know of another way of doing this except to have all of these joins. The joins are left joins as I want to see null values being returned aswell. The where clause filter is to return data for a timeline of up to 370 days ago. I will paste my query below; any suggestions would be really appreciated:
SELECT
c.id AS customer_id,
c.priority AS priority,
c.create_date AS create_date,
u.login AS login,
c.due_date AS due_date,
ts.user_status AS status,
cts.status AS current_status,
cts.id AS status_id,
w.name AS workflow_name,
c.summary AS summary,
cfi.added_by AS acknowledged_by,
CONCAT(dispatch_user.first_name,' ',dispatch_user.last_name) AS dispatch_user,
CONCAT(dispatched_user.first_name,' ',dispatched_user.last_name) AS acknowledged,
CONCAT(last_update_by.first_name,' ',last_update_by.last_name) AS manager_last_updated_by,
c.updated_date AS updated_date,
CONCAT(u.first_name,' ',u.last_name) AS last_updated_by,
ts_new.status_date AS new_dt,
ts_initial.status_date AS initial_dt,
ts_assigned.status_date AS assigned_dt,
ts_investigating.status_date AS investigating_dt,
ts_resolved.status_date AS resolved_dt,
ts_pending_closure.status_date AS pending_closure_dt,
ts_closed.status_date AS closed_dt,
IF(user_visit.status IS NOT NULL, 'Yes', 'No') AS user_visit,
fftr.reason AS reason,
fftr.notes AS resolution,
FROM customer c
JOIN form1 AS tcv ON (c.id = tcv.customer_id)
JOIN user_status AS cts ON (c.current_status_id = cts.id)
JOIN user AS u ON (u.id = cts.status_by_id)
LEFT JOIN user_status AS ts ON (ts.workflow_state = cts.status)
LEFT JOIN change_info AS cfi ON cfi.customer_id = c.id
LEFT JOIN user_status AS dispatch_status ON dispatch_status.customer_id = c.id AND dispatch_status.status = 'FTD'
LEFT JOIN user AS dispatch_user ON dispatch_user.id = dispatch_status.status_by_id
LEFT JOIN user_status AS assigned_ft_dis ON assigned_ft_dis.customer_id = c.id AND assigned_ft_dis.status = 'ASSIGNED - FTD'
LEFT JOIN user_status AS assigned_ft_dis_rx ON assigned_ft_dis_rx.customer_id = c.id AND assigned_ft_dis_rx.status = 'ASSIGNED - FT'
LEFT JOIN user AS dispatched_user ON dispatched_user.id = assigned_ft_dis_rx.status_by_id
LEFT JOIN user_status AS last_update_status ON last_update_status.id = c.current_status_id
LEFT JOIN user last_update_by ON last_update_by.id = last_update_status.status_by_id
LEFT JOIN user_status AS ts_new ON c.id = ts_new.customer_id AND ts_new.status LIKE 'NEW%'
LEFT JOIN user_status AS ts_initial ON c.id = ts_initial_diagnosis.customer_id AND ts_initial_diagnosis.status LIKE 'INITIAL SOLUTION%'
LEFT JOIN user_status AS ts_assigned ON c.id = ts_assigned.customer_id AND ts_assigned.status LIKE 'ASSIGNED%'
LEFT JOIN user_status AS ts_investigating ON c.id = ts_investigating.customer_id AND ts_investigating.status LIKE 'INVESTIGATING%'
LEFT JOIN user_status AS ts_resolved ON c.id = ts_resolved.customer_id AND ts_resolved.status LIKE 'RESOLVED%'
LEFT JOIN user_status AS ts_pending_closure ON c.id = ts_pending_closure.customer_id AND ts_pending_closure.status LIKE 'PENDING CLOSURE%'
LEFT JOIN user_status AS ts_closed ON c.id = ts_closed.customer_id AND ts_closed.status LIKE 'CLOSED%'
LEFT JOIN user_status AS user_visit ON c.id = user_visit.customer_id AND user_visit.status = 'RESOLVED – FT'
LEFT JOIN change AS tc_fftr ON c.id = tc_fftr.customer_id AND tc_fftr.contents LIKE 'Resolution%'
LEFT JOIN form4 AS fftr ON fftr.change_id = tc_fftr.id
WHERE
c.create_date >= DATE_SUB(NOW(),INTERVAL 370 DAY)

First, the query as listed would not have run as you don't have a "w" alias, and have a trailing comma after the last field. I have rewritten (slightly) for readability and relationships to each other and changed a few "aliases".
SELECT
c.id as customer_id,
c.priority as priority,
c.create_date as create_date,
u.login as login,
c.due_date as due_date,
ts.user_status as status,
cts.status as current_status,
cts.id as status_id,
w.name as workflow_name,
c.summary as summary,
cfi.added_by as acknowledged_by,
concat(du.first_name,' ',du.last_name) as dispatch_user,
concat(disU.first_name,' ',disU.last_name) as acknowledged,
concat(updBy.first_name,' ',updBy.last_name) as manager_last_updated_by,
c.updated_date as updated_date,
concat(u.first_name,' ',u.last_name) as last_updated_by,
ts_new.status_date as new_dt,
tsi.status_date as initial_dt,
tsa.status_date as assigned_dt,
tsinv.status_date as investigating_dt,
tsres.status_date as resolved_dt,
tspc.status_date as pending_closure_dt,
ts_closed.status_date as closed_dt,
IF(uv.status IS NOT NULL, 'Yes', 'No') as user_visit,
fftr.reason as reason,
fftr.notes as resolution
FROM
customer c
join form1 tcv
on (c.id = tcv.customer_id)
join user_status cts
on c.current_status_id = cts.id
join user u
on cts.status_by_id = u.id
left join user_status ts
on cts.status = ts.workflow_state
left join change_info cfi
on c.id = cfi.customer_id
left join user_status ds
on c.id = ds.customer_id
and ds.status = 'FTD'
left join user du
on ds.status_by_id = du.id
left join user_status ftDis
on c.id = ftDis.customer_id
and ftDis.status = 'ASSIGNED - FTD'
left join user_status rx
on c.id = rx.customer_id
and rx.status = 'ASSIGNED - FT'
left join user disU
on rx.status_by_id = disU.id
left join user_status lus
ON c.current_status_id = lus.id
left join user updBy
on lus.status_by_id = updBy.id
left join user_status ts_new
on c.id = ts_new.customer_id
and ts_new.status like 'NEW%'
left join user_status tsi
on c.id = tsi.customer_id
and tsi.status like 'INITIAL SOLUTION%'
left join user_status tsa
on c.id = tsa.customer_id
and tsa.status like 'ASSIGNED%'
left join user_status tsinv
on c.id = tsinv.customer_id
and tsinv.status like 'INVESTIGATING%'
left join user_status tsres
on c.id = tsres.customer_id
and tsres.status like 'RESOLVED%'
left join user_status tspc
on c.id = tspc.customer_id
and tspc.status like 'PENDING CLOSURE%'
left join user_status ts_closed
on c.id = ts_closed.customer_id
and ts_closed.status like 'CLOSED%'
left join user_status uv
on c.id = uv.customer_id
and uv.status = 'RESOLVED – FT'
left join change tc_fftr
ON c.id = tc_fftr.customer_id
and tc_fftr.contents LIKE 'Resolution%'
left join form4 fftr
ON tc_fftr.id = fftr.change_id
WHERE
c.create_date >= DATE_SUB(NOW(),INTERVAL 370 DAY)
GROUP BY
customer_id
I would ensure the following compound indexes on your tables...
table index
customer (create_date, id)
form1 (customer_id)
change_info (customer_id, added_by)
user_status (id, status_by_id, status )
user (id, first_name, last_name)
user_status (customer_id, status, status_date, status_by_id )
change (customer_id, contents, id )
form4 (change_id)
Also, it appears you were not even using the assigned_ft_dis (changed alias to ftDis)
then, in your join after the "form1" of...
join user_status cts
on c.current_status_id = cts.id
join user u
on cts.status_by_id = u.id
left join user_status ts
on cts.status = ts.workflow_state
why are you re-joining based on the cts.status to the user_status table again by alias "ts". IF you have 10k records with status "NEW", you are left-joining to all of those records for the workflow_state. You have nothing associated to the customer ID. But since you are prior in the chain of joins, joined by the current_status_id (which I can only GUESS is the auto-increment ID of the user_status table). Is this a mistake? Are you trying to get some description for the "workflow_state". I believe this one component is a big hit on your performance. Is there a different TABLE (alias "w" for the workflow_state) NOT accurately reflected here?
Now, a possible rewrite. Do a single join to the user status and user table to determine the respective status elements and by whom and doing case/when for the criteria... something like... I am using "US" for User_Status alias and "U2" for generic "User" reference for each corresponding "user status" entry. Now, notice all the case/when instances. Since I am only joining to the status and then user table without specific criteria, I can apply the criteria at the FIELD condition level and either be null, or applicable and grab both the date and who of the action.
SELECT
c.id as customer_id,
c.priority as priority,
c.create_date as create_date,
u.login as login,
c.due_date as due_date,
ts.user_status as status,
cts.status as current_status,
cts.id as status_id,
w.name as workflow_name,
c.summary as summary,
MAX( case when US.status = 'FTD' then US.Status_Date END ) as dispatch_date,
MAX( case when US.status = 'FTD' then concat(U2.first_name,' ',U2.last_name) END ) as dispatch_user,
MAX( case when US.status = 'ASSIGNED - FTD' then US.Status_Date END ) as assigned_date,
MAX( case when US.status = 'ASSIGNED - FTD' then concat(U2.first_name,' ',U2.last_name) END ) as assigned_user,
MAX( case when US.status = 'ASSIGNED - FT' then US.Status_Date END ) as assigned2_date,
MAX( case when US.status = 'ASSIGNED - FT' then concat(U2.first_name,' ',U2.last_name) END ) as assigned2_user,
MAX( case when US.status like 'NEW%' then US.Status_Date END ) as new_date,
MAX( case when US.status like 'NEW%' then concat(U2.first_name,' ',U2.last_name) END ) as new_user,
MAX( case when US.status like 'INITIAL SOLUTION%' then US.Status_Date END ) as solution_date,
MAX( case when US.status like 'INITIAL SOLUTION%' then concat(U2.first_name,' ',U2.last_name) END ) as solution_user,
MAX( case when US.status like 'ASSIGNED%' then US.Status_Date END ) as assigned_date,
MAX( case when US.status like 'ASSIGNED%' then concat(U2.first_name,' ',U2.last_name) END ) as assigned_user,
MAX( case when US.status like 'INVESTIGATING%' then US.Status_Date END ) as investigate_date,
MAX( case when US.status like 'INVESTIGATING%' then concat(U2.first_name,' ',U2.last_name) END ) as investigate_user,
MAX( case when US.status like 'RESOLVED%' then US.Status_Date END ) as resolved_date,
MAX( case when US.status like 'RESOLVED%' then concat(U2.first_name,' ',U2.last_name) END ) as resolved_user,
MAX( case when US.status like 'PENDING CLOSURE%' then US.Status_Date END ) as pendClose_date,
MAX( case when US.status like 'PENDING CLOSURE%' then concat(U2.first_name,' ',U2.last_name) END ) as pendClose_user,
MAX( case when US.status like 'CLOSED%' then US.Status_Date END ) as closed_date,
MAX( case when US.status like 'CLOSED%' then concat(U2.first_name,' ',U2.last_name) END ) as closed_user,
MAX( case when US.status = 'RESOLVED - FT' then US.Status_Date END ) as resolved_date,
MAX( case when US.status = 'RESOLVED - FT' then concat(U2.first_name,' ',U2.last_name) END ) as resolved_user,
c.updated_date as updated_date,
concat(u.first_name,' ',u.last_name) as last_updated_by,
IF(uv.status IS NOT NULL, 'Yes', 'No') as user_visit,
fftr.reason as reason,
fftr.notes as resolution
FROM
customer c
left join user_status US
on c.id = US.customer_id
left join user U2
on US.status_by_id = U2.id
join form1 tcv
on (c.id = tcv.customer_id)
join user_status cts
on c.current_status_id = cts.id
join user u
on cts.status_by_id = u.id
left join user_status ts
on cts.status = ts.workflow_state
left join change_info cfi
on c.id = cfi.customer_id
left join user_status lus
ON c.current_status_id = lus.id
left join user updBy
on lus.status_by_id = updBy.id
left join change tc_fftr
ON c.id = tc_fftr.customer_id
and tc_fftr.contents LIKE 'Resolution%'
left join form4 fftr
ON tc_fftr.id = fftr.change_id
WHERE
c.create_date >= DATE_SUB(NOW(),INTERVAL 370 DAY)
GROUP BY
customer_id
This still may not work completely, but I am sure MOST of it WILL work and accommodate almost all of what you are trying to get even though I am getting a few more details (pair of both dates and who of the corresponding status actions).

Related

invoice type fetch query from tables

ER diagram
ER diagram is attached
I need to get sales invoice invoices.type = 'sales' and invoices.type = 'purchase'
with company name as you can see in select statement
also sales and purchase columns
My query
SELECT jobs.id as jobID,
-- c.name AS Customer,jobs.job_no,
invoices.invoice_due_date,
jobs.id,
( (invoice_items.amount * invoice_items.quantity * invoice_items.exchange_rate )) as Ammount
FROM invoices
INNER JOIN `invoice_items` ON invoices.id = invoice_items.invoice_id
INNER JOIN `jobs` ON jobs.id = invoices.job_id
-- INNER JOIN `company` as c ON c.company_id = jobs.company_id -- jobs and company.
WHERE invoices.type = 'sales'
-- new conditions
AND MONTH(jobs.created_at) = '3'
AND YEAR(jobs.created_at) = '2017'
AND jobs.status > 0
AND jobs.complete_job > 0
AND jobs.completed_at IS NOT NULL
AND invoice_items.deleted_at IS NULL
GROUP BY jobs.job_no
ORDER BY invoices.invoice_due_date DESC
Try this updated...
SELECT jobs.id as jobID,
C.name AS Customer,jobs.job_no,
invoices.invoice_due_date,
jobs.id,
( (invoice_items.amount * invoice_items.quantity *invoice_items.exchange_rate )) as Ammount,
CASE invoices.type
WHEN 'sales' THEN 'S'
ELSE 'P'
END as trans_type
FROM invoices
INNER JOIN `invoice_items` ON invoices.id = invoice_items.invoice_id
INNER JOIN `jobs` ON jobs.id = invoices.job_id
LEFT OUTER JOIN `company` as C ON C.company_id = jobs.company_id
WHERE (invoices.type = 'sales' OR invoices.type = 'purchase') AND (MONTH(jobs.created_at) = '3') AND (YEAR(jobs.created_at) = '2017') AND (jobs.status > 0) AND (jobs.complete_job > 0) AND (jobs.completed_at IS NOT NULL)

MySQL - I want my table JOIN to return a single row based on a condition

in the below code there are multiple entries in 'leads' table with the same 'account_id'. I want it to return a single row - the one with the minimal value of another field 'date_entered'. I cannot use 'group by' on account_id as I intend to use 'group by' on BU and get summation accordingly. Please help.
select uc.business_unit_dp_c,
FORMAT(SUM(CASE
WHEN lc.source_leads_c not in ('Discovery','Discovery SuperEmail','Self Generated','Partner','Channel_Partner') and k.id<>'' THEN k.order_value
WHEN lc.source_leads_c not in ('Discovery','Discovery SuperEmail','Self Generated','Partner','Channel_Partner') and s.id<>'' THEN s.sivr_aiv_inr
ELSE 0
END),0)
as Online,
FORMAT(SUM(CASE
WHEN lc.source_leads_c in ('Discovery', 'Discovery SuperEmail') and k.id<>'' THEN k.order_value
WHEN lc.source_leads_c in ('Discovery', 'Discovery SuperEmail') and s.id<>'' THEN s.sivr_aiv_inr
ELSE 0
END),0)
as Discovery,
FORMAT(SUM(CASE
WHEN lc.source_leads_c in ('Partner','Channel_Partner') and k.id<>'' THEN k.order_value
WHEN lc.source_leads_c in ('Partner','Channel_Partner') and s.id<>'' THEN s.sivr_aiv_inr
ELSE 0
END),0)
as Self_Generated_CP
from opportunities as o
left join opportunities_cstm as oc on o.id=oc.id_c
left join opportunities_knw_caf_1_c as ok on o.id=ok.opportunities_knw_caf_1opportunities_ida
left join knw_caf as k on ok.opportunities_knw_caf_1knw_caf_idb=k.id
left join opportunities_knw_sivr_caf_1_c as os on os.opportunities_knw_sivr_caf_1opportunities_ida=o.id
left join knw_sivr_caf as s on s.id=os.opportunities_knw_sivr_caf_1knw_sivr_caf_idb
left join accounts_opportunities as ao on ao.opportunity_id=o.id
left join leads as l on l.account_id=ao.account_id and l.account_id <> ''
left join leads_cstm as lc on lc.id_c=l.id
left join users_cstm as uc on uc.id_c=o.assigned_user_id
where o.sales_stage='clw' and
(k.id<>'' or s.id<>'') and o.jira_raise_date <> '' and
(o.tranjection_type in ('Fresh Plan / New Customer','Number Activation','Revival','Balance Amount') or o.transaction_sivr in ('Paid Project','Number Allocation','New Feature')) and
o.jira_raise_date between '2016-06-01' and curdate()
group by uc.business_unit_dp_c
Write SQL just as you described
Select *
from from opportunities o
left join opportunities_cstm oc
on o.id = oc.id_c
left join opportunities_knw_caf_1_c ok
on o.id = ok.opportunities_knw_caf_1opportunities_ida
left join knw_caf k
on ok.opportunities_knw_caf_1knw_caf_idb = k.id
left join opportunities_knw_sivr_caf_1_c os
on os.opportunities_knw_sivr_caf_1opportunities_ida=o.id
left join knw_sivr_caf s
on s.id = os.opportunities_knw_sivr_caf_1knw_sivr_caf_idb
left join accounts_opportunities ao
on ao.opportunity_id=o.id
left join leads l
on l.account_id=ao.account_id
and l.account_id <> ''
left join leads_cstm lc
on lc.id_c = l.id
left join users_cstm uc
on uc.id_c = o.assigned_user_id
where o.sales_stage = 'clw' and
and (k.id <> '' or s.id <> '')
and o.jira_raise_date <> ''
and (o.tranjection_type in
('Fresh Plan / New Customer',
'Number Activation','Revival','Balance Amount') or
o.transaction_sivr in
('Paid Project','Number Allocation','New Feature'))
and o.jira_raise_date between '2016-06-01' and curdate()
-- next, add this additional predicate to Where clause...
use table w/DateEntered column
and date_entered =
(Select Min(date_entered)
From accounts_opportunities os
join tableWithDateEntered dr -- Table w/DateEntered
on ????? -- proper join criteria here
Where os.account_id = l.account_id)
--- or as constructed by op ( and simplified by me, since both account_id and date_entered are in table leads, that's the only table that needs to be referenced in the subquery).....
and l.date_entered =
(select min(date_entered)
from leads
where account_id = l.account_id)
select min(C.date),C.Customer_Code from (
select InvoiceNo,month(InvoiceDate) as date,Customer_Code,Createddate from tbl_Invoices A Inner Join tbl_customer B on A.customer_Code=B.CustomerCode
where YEAR(InvoiceDate)='2017'
and CustomerCode not in (select CustomerCode from tbl_customer where year(createddate) in (year(getdate())))
and CustomerCode not in (select customer_Code from tbl_Invoices where year(InvoiceDate) in (year(getdate())-1))
and CustomerCode in (select customer_Code from tbl_Invoices where year(InvoiceDate) not in (year(getdate())))
--group by Customer_Code,Createddate,InvoiceNo
)C group by C.Customer_Code

MySQL, CROSS JOIN and unknown column

I wrote mysql query which use subquery. I can't understand why mysql shows me 'Unknown column 'T.TICKETID' in 'where clause'' in subquery. For MSSQL it works without problem.
SELECT #PERIODTYPE := 'Y';
SELECT
#PERIODTYPE,
CASE
WHEN #PERIODTYPE = 'W' THEN DATE_FORMAT(R.DATENEW,'%u')
WHEN #PERIODTYPE = 'M' THEN DATE_FORMAT(R.DATENEW,'%Y-%m')
WHEN #PERIODTYPE = 'Y' THEN DATE_FORMAT(R.DATENEW,'%Y')
ELSE DATE_FORMAT(R.DATENEW,'%Y-%m-%d')
END `Period`,
DATE_FORMAT(MIN(R.DATENEW),'%Y-%m-%d') min_date,
DATE_FORMAT(MAX(R.DATENEW),'%Y-%m-%d') max_date,
COUNT(*) Transactions,
SUM(SQ.`Sold Units`) `Sold Units`,
FORMAT(MAX(P.TOTAL), 2) `Largest Order`,
FORMAT(SUM(P.TOTAL), 2) `Total $ Sold`,
FORMAT(SUM(TXL.AMOUNT), 2) `Total Tax $ Collected`
FROM RECEIPTS R INNER JOIN TAXLINES TXL ON R.ID = TXL.RECEIPT
INNER JOIN TAXES TX ON TXL.TAXID = TX.ID
INNER JOIN TAXCATEGORIES TXC ON TX.CATEGORY = TXC.ID
INNER JOIN PAYMENTS P ON P.RECEIPT = R.ID
INNER JOIN TICKETS T ON R.ID = T.ID
CROSS JOIN (SELECT SUM(TL.UNITS) 'Sold Units' FROM TICKETLINES TL WHERE T.TICKETID = TL.TICKET) SQ
GROUP BY CASE
WHEN #PERIODTYPE = 'W' THEN DATE_FORMAT(R.DATENEW,'%u')
WHEN #PERIODTYPE = 'M' THEN DATE_FORMAT(R.DATENEW,'%Y-%m')
WHEN #PERIODTYPE = 'Y' THEN DATE_FORMAT(R.DATENEW,'%Y')
ELSE DATE_FORMAT(R.DATENEW,'%Y-%m-%d')
END
ORDER BY R.DATENEW
Update 1
I replaced table name (TICKETS) instead of alias (T). I got error. Please, see the screenshot.
SELECT #PERIODTYPE := 'D';
SELECT
#PERIODTYPE,
CASE
WHEN #PERIODTYPE = 'W' THEN DATE_FORMAT(R.DATENEW,'%u')
WHEN #PERIODTYPE = 'M' THEN DATE_FORMAT(R.DATENEW,'%Y-%m')
WHEN #PERIODTYPE = 'Y' THEN DATE_FORMAT(R.DATENEW,'%Y')
ELSE DATE_FORMAT(R.DATENEW,'%Y-%m-%d')
END `Period`,
DATE_FORMAT(MIN(R.DATENEW),'%Y-%m-%d') min_date,
DATE_FORMAT(MAX(R.DATENEW),'%Y-%m-%d') max_date,
COUNT(*) Transactions,
FORMAT(SUM(IFNULL(SQ.`Sold Units`,0)),2) `Sold Units`,
FORMAT(MAX(P.TOTAL), 2) `Largest Order`,
FORMAT(SUM(P.TOTAL), 2) `Total $ Sold`,
FORMAT(SUM(TXL.AMOUNT), 2) `Total Tax $ Collected`
FROM RECEIPTS R INNER JOIN TAXLINES TXL ON R.ID = TXL.RECEIPT
INNER JOIN TAXES TX ON TXL.TAXID = TX.ID
INNER JOIN TAXCATEGORIES TXC ON TX.CATEGORY = TXC.ID
INNER JOIN PAYMENTS P ON P.RECEIPT = R.ID
INNER JOIN TICKETS ON R.ID = TICKETS.ID
-- LEFT JOIN (SELECT TL.TICKET, SUM(TL.UNITS) 'Sold Units' FROM TICKETLINES TL GROUP BY TL.TICKET) SQ ON T.ID = SQ.TICKET
CROSS JOIN (SELECT SUM(TL.UNITS) 'Sold Units' FROM TICKETLINES TL WHERE TICKETS.ID = SQ.TICKET) SQ
GROUP BY CASE
WHEN #PERIODTYPE = 'W' THEN DATE_FORMAT(R.DATENEW,'%u')
WHEN #PERIODTYPE = 'M' THEN DATE_FORMAT(R.DATENEW,'%Y-%m')
WHEN #PERIODTYPE = 'Y' THEN DATE_FORMAT(R.DATENEW,'%Y')
ELSE DATE_FORMAT(R.DATENEW,'%Y-%m-%d')
END
ORDER BY R.DATENEW
The query don't work in mysql beacuse mysql can't use an alias declared ad an upper level respect the subquery ..
in your subquery in Cross Join
CROSS JOIN (SELECT SUM(TL.UNITS) 'Sold Units'
FROM TICKETLINES TL WHERE T.TICKETID = TL.TICKET) SQ
You use T.TICKETID
The alias T
INNER JOIN TICKETS T ON R.ID = T.ID
Is declare in a place not "accessible" by the scope of the subquery ..
Then if is possible i suggest you of build a subquery that non refer to T alias .. Try (if is possible ) building an equivalent subquery wihout alias

Moodle Resource/File Completion

I need help understanding WHERE the completion state of a resource (file) in Moodle is stored.
Please see attached images for more information.
The flag next to the file is marked as completed once the user viewed
This is setup in the Completion settings of this file/resource.
I need to generate a SQL report showing the file and the completion state.
I already have the "difficult part" of the query, I just need to select the completion state from "table-X" and wha-la!
Thank you.
SELECT r.id, r.name, r.course, cmc.userid, cmc.completionstate, cmc.viewed
FROM mdl_course_modules_completion cmc
JOIN mdl_course_modules cm ON cm.id = cmc.coursemoduleid
JOIN mdl_modules m ON m.id = cm.module AND m.name = 'resource'
JOIN mdl_resource r ON r.id = cm.instance
The completionstate and viewed constants are in /lib/completionlib.php
eg:
COMPLETION_INCOMPLETE = 0
COMPLETION_COMPLETE = 1
COMPLETION_COMPLETE_PASS = 2
COMPLETION_COMPLETE_FAIL = 3
COMPLETION_COMPLETE_RPL = 4 // This is used in Totara.
COMPLETION_NOT_VIEWED = 0
COMPLETION_VIEWED = 1
Okay, so I found the table and column.
Table: mdl_course_modules_completion
Column: Viewed
I will post my report code below, hopefully this might help the next guy.
Take Note: I joined all the module types to the query and filter only for type quiz, lesson and resource in the where statement. I did this because I am only interested in these 3 types. I however did not remove the joins because someone else might need the code.
SELECT DISTINCT
u.firstname AS 'Firstname'
,u.lastname AS 'Lastname'
,u.institution AS 'Institution'
,u.department AS 'Department'
,u.city AS 'City/Site'
,cc.name AS 'Course'
,c.fullname AS 'Module'
,CASE
WHEN mf.name IS NOT NULL THEN mf.name
WHEN mb.name IS NOT NULL THEN mb.name
WHEN mr.name IS NOT NULL THEN mr.name
WHEN mu.name IS NOT NULL THEN mu.name
WHEN mq.name IS NOT NULL THEN mq.name
WHEN mp.name IS NOT NULL THEN mp.name
WHEN ml.name IS NOT NULL THEN ml.name
ELSE NULL
END AS activityname
,CASE WHEN mdl.name = 'lesson' THEN CASE WHEN mlg.id IS NOT NULL AND mlg.completed IS NOT NULL THEN 'Complete' ELSE 'Incomplete' END
WHEN mdl.name = 'quiz' THEN CASE WHEN mqg.id IS NOT NULL AND mqg.timemodified IS NOT NULL THEN 'Complete' ELSE 'Incomplete' END
WHEN mdl.name = 'resource' THEN CASE WHEN cmc.viewed = 1 THEN 'Complete' ELSE 'Incomplete' END
END AS Status
FROM
mdl_user u
JOIN mdl_user_enrolments ue ON ue.userid = u.id
JOIN mdl_enrol E on E.id = ue.enrolid
JOIN mdl_course c ON c.id = E.courseid
JOIN mdl_course_categories cc ON c.category = cc.id
JOIN mdl_course_modules cm ON cm.course = c.id
JOIN mdl_course_modules_completion cmc ON cmc.coursemoduleid = cm.id
JOIN mdl_context AS ctx ON ctx.contextlevel = 70 AND ctx.instanceid = cm.id
JOIN mdl_modules AS mdl ON cm.module = mdl.id
LEFT JOIN mdl_forum AS mf ON mdl.name = 'forum' AND cm.instance = mf.id
LEFT JOIN mdl_book AS mb ON mdl.name = 'book' AND cm.instance = mb.id
LEFT JOIN mdl_resource AS mr ON mdl.name = 'resource' AND cm.instance = mr.id
LEFT JOIN mdl_url AS mu ON mdl.name = 'url' AND cm.instance = mu.id
LEFT JOIN mdl_quiz AS mq ON mdl.name = 'quiz' AND cm.instance = mq.id
LEFT JOIN mdl_quiz_grades mqg ON mqg.quiz = mq.id
LEFT JOIN mdl_page AS mp ON mdl.name = 'page' AND cm.instance = mp.id
LEFT JOIN mdl_lesson AS ml ON mdl.name = 'lesson' AND cm.instance = ml.id
LEFT JOIN mdl_lesson_grades mlg ON mlg.lessonid = ml.id
LEFT JOIN mdl_files AS f ON f.contextid = ctx.id
LEFT JOIN mdl_files_reference fr ON fr.id = f.referencefileid
WHERE mdl.name in ('quiz','lesson','resource')
ORDER BY firstname,Lastname,cc.name,c.fullname

Moodle Join Query Slow

I've been at this thing for hours. Does anyone have any ideas on how to speed this query up?
SELECT SQL_CALC_FOUND_ROWS
mdl_course.fullname as course_name,
mdl_course.idnumber as course_length,
mdl_user.firstname as firstname,
mdl_user.lastname as lastname,
case when mdl_course_completions.timecompleted IS NOT NULL
then FROM_UNIXTIME(mdl_course_completions.timecompleted,'%m/%d/%Y') else 'N/A' end AS date_completed,
mdl_cohort.name AS group_name,
mdl_course_categories.name as category_name,
case when mdl_course_completions.timecompleted IS NOT NULL then 'Completed' else
'Incomplete' end AS completion_status
FROM mdl_enrol
JOIN mdl_user_enrolments ON mdl_user_enrolments.enrolid = mdl_enrol.id
JOIN mdl_course ON mdl_course.id = mdl_enrol.courseid
JOIN mdl_user ON mdl_user.id = mdl_user_enrolments.userid AND mdl_user.deleted = 0
JOIN mdl_cohort_members ON mdl_cohort_members.userid = mdl_user.id
JOIN mdl_cohort ON mdl_cohort.id = mdl_cohort_members.cohortid
JOIN mdl_course_categories ON mdl_course_categories.id = mdl_course.category
JOIN mdl_course_completions ON mdl_course_completions.course = mdl_course.id
AND mdl_course_completions.userid = mdl_user.id
AND mdl_course_completions.deleted IS NULL
GROUP BY mdl_course_completions.id
ORDER BY mdl_course.fullname ASC
mdl_course_completions has over 100,000 rows in it and is slowing everything down.