I am learning MySQL through self-practice. In a project, I want to create a transfer module using MySQL (phpMyAdmin). Unfortunately, the WHERE conditions are not working well. I execute the query using the XAMPP application. A part of the query is -
SELECT
*
FROM
(SELECT
`emp_id`,
`emp_name`,
`present_posting`,
`curr_zone`,
`office_ID1` AS `new_office`,
`Zone1` AS `new_zone`,
`office_ID1` AS `C1`,
`post`,
`preference`,
`curr_zone_id`
FROM
`transfer_applications`
WHERE
`Mutual Accepted` != 'Mutual Accepted'
ORDER BY `apID` ASC) `aa`
LEFT JOIN
(SELECT
`zone_ID`, `ZONE`, `office_ID`, `office_Vacancy`
FROM
`vacancy`) `ab` ON `aa`.`C1` = `ab`.`office_ID`
LEFT JOIN
(SELECT
`zid`, `max_min_vacancy`
FROM
`capping_vacancy`) `ac` ON `aa`.`new_zone` = `ac`.`zid`
WHERE
((`curr_zone_id` != `new_zone`
AND (`max_min_vacancy` < 150
AND `max_min_vacancy` > 1)
AND `station_Vacancy` > 0
AND `post` = 4
AND `apID` = x + 1)
OR (`curr_zone_id` = `new_zone`
AND `station_Vacancy` > 0))
The problem is that it allows transfer even if there is no vacancy available that is the minimum capping in WHERE ( max_min_vacancy > 1 ) is not working. I am unable to find out the reason why it skips this condition while all other conditions in the WHERE are working fine. Kindly help me to find out the mistake. Thanks.
The WHERE clause is connected by an OR, so if the first Boolean expression is FALSE (ie. max_min_vacancy <=1), it is still TRUE as long as the second boolean expression returns TRUE.
...
WHERE
(
(
`curr_zone_id` != `new_zone` AND
(
`max_min_vacancy` < 150 AND
`max_min_vacancy` > 1 -- if max_min_vacancy <= 1 --> FALSE
) AND
`station_Vacancy` > 0 AND
`post` = 4 AND
`apID` = x + 1
)
OR ( -- But this condition is TRUE
`curr_zone_id` = `new_zone` AND
`station_Vacancy` > 0
)
)
Related
I have the following code written for a larger report that I have been working on. I have three columns resulting from subqueries: req_hrs, e_hrs, inprog_hrs. I need to add together the e_hrs and inprog_hrs, thus seeing whether that number is greater than or equal to req_hrs. If that is true, I need to return either an * or a null value.
Can someone please explain to me how I can add the two subquery results (e_hrs and inprog_hrs) together, and then compare that result to req_hrs thus returning said * or NVL? Code is below, Thank you:
SELECT
spriden_last_name lname,
spriden_first_name fname,
spriden_mi mi,
spriden_id id,
x.shrdgmr_majr_code_1 majr,
x.shrdgmr_grad_date grad_dt,
x.shrdgmr_degs_code degs,
DECODE(stvdegs_award_status_ind,'A','*',NULL) award_ind,
**DECODE(NVL(m.smbagen_req_credits_overall,0),0,
DECODE(NVL(sorcmjr_req_hours_ssdf,0),0,
DECODE(stvdegc_acat_code,'22',32,'23',64,'24',124,'42',42,999),
sorcmjr_req_hours_ssdf),m.smbagen_req_credits_overall) req_hrs,**
**TRUNC(shrlgpa_hours_earned,2) AS e_hrs,**
**(SELECT
NVL(SUM(sfrstcr_credit_hr),0)
FROM
sfrstcr
WHERE
sfrstcr_term_code = '&inprog_term'
AND sfrstcr_pidm = x.shrdgmr_pidm
AND sfrstcr_rsts_code IN ('RE','RW')
AND NOT EXISTS (
SELECT
'Y'
FROM
shrtckn,
shrtckg j
WHERE
shrtckn_pidm = sfrstcr_pidm
AND shrtckn_term_code = sfrstcr_term_code
AND shrtckn_crn = sfrstcr_crn
AND j.shrtckg_pidm = shrtckn_pidm
AND j.shrtckg_term_code = shrtckn_term_code
AND j.shrtckg_tckn_seq_no = shrtckn_seq_no
AND j.shrtckg_seq_no = (
SELECT
MAX(k.shrtckg_seq_no)
FROM
shrtckg k
WHERE
k.shrtckg_pidm = shrtckn_pidm
AND k.shrtckg_term_code = shrtckn_term_code
AND k.shrtckg_tckn_seq_no = shrtckn_seq_no))) AS inprog_hrs,**
ROUND(shrlgpa_gpa,2) gpa,
DECODE(SIGN(shrlgpa_gpa - 3.90),0,'S',1,'S',
DECODE(SIGN(shrlgpa_gpa - 3.75),0,'M',1,'M',
DECODE(SIGN(shrlgpa_gpa - 3.50),0,'C',1,'C',NULL))) latin,
(SELECT
m.shrasdl_astd_code_dl
FROM
shrasdl m
WHERE
m.shrasdl_term_code_effective = (
SELECT
MAX(n.shrasdl_term_code_effective)
FROM
shrasdl n)
AND m.shrasdl_min_gpa_term = (
SELECT
MAX(n.shrasdl_min_gpa_term)
FROM
shrasdl n
WHERE
n.shrasdl_term_code_effective = m.shrasdl_term_code_effective
AND shrlgpa_gpa >= n.shrasdl_min_gpa_term)) honors
FROM
shrdgmr x,
stvdegs,
stvdegc,
spriden,
sorcmjr,
smbagen m,
shrlgpa
WHERE
TO_CHAR(x.shrdgmr_grad_date,'MON-YY') IN ('&grad_dt1', NVL('&grad_dt2','XXX-
00'))
AND x.shrdgmr_seq_no = (
SELECT
MAX(z.shrdgmr_seq_no)
FROM
shrdgmr z
WHERE
z.shrdgmr_pidm = x.shrdgmr_pidm
AND z.shrdgmr_majr_code_1 = x.shrdgmr_majr_code_1
AND z.shrdgmr_grad_date IS NOT NULL)
AND stvdegs_code = x.shrdgmr_degs_code
AND stvdegc_code = x.shrdgmr_degc_code
AND spriden_pidm = x.shrdgmr_pidm
AND spriden_change_ind IS NULL
AND sorcmjr_cmjr_rule(+) = x.shrdgmr_cmjr_rule_1_1
AND REPLACE(m.smbagen_area(+),'-CORE','') = x.shrdgmr_majr_code_1
AND m.smbagen_active_ind(+) = 'Y'
AND m.smbagen_term_code_eff(+) <= x.shrdgmr_term_code_grad
AND ((m.smbagen_area IS NULL)
OR (m.smbagen_area IS NOT NULL
AND m.smbagen_term_code_eff = (
SELECT
MAX(n.smbagen_term_code_eff)
FROM
smbagen n
WHERE
REPLACE(n.smbagen_area,'-CORE','') = x.shrdgmr_majr_code_1
AND n.smbagen_active_ind = 'Y'
AND n.smbagen_term_code_eff <= x.shrdgmr_term_code_grad)))
AND shrlgpa_pidm(+) = x.shrdgmr_pidm
AND shrlgpa_levl_code(+) = x.shrdgmr_levl_code
AND shrlgpa_gpa_type_ind(+) = 'O'
ORDER BY
spriden_last_name,
spriden_first_name,
spriden_mi
;
Compare the sum of the union of the two sources with the required amount.
In simplified form:
select somekey, sum(hrs) worked_hrs, sum(req_hrs) required_hrs
from (
select
somekey,
e_hrs hrs
from e_hrs_table
where ...
union all -- the "all" is important to leave in!
select
somekey,
inprog_hrs
from inprog_hrs_table
where ...
) x
join req_hrs_table on req_hrs_table.somekey = x.somekey
where ... -- add req_hrs_table conditions here
group by somekey
You can add
having sum(hrs) < sum(req_hrs)
if you want only those rows that did not meet the quota.
I have a table with 3 columns( name, objectroot_dn, distinguishedname). Here distinguishedname is like a parent to objectroot_dn. I have to find whether for each objectroot_dn is there a child exists or not?
I can do this using the query below. It will return True if there is a child, False if there is not. But my problem is when the total dataset gets increased it takes lots of time.
For example, If the total number of row is 50,000 then it takes 10 mins for this query to complete.
Since I'm using a framework for different database, I can't index the columns.
SELECT
name,
objectroot_dn,
distinguishedname,
CASE
WHEN (SELECT count(*)
FROM (SELECT name
FROM elaoucontainergeneraldetails
WHERE objectroot_dn = dn.distinguishedname
LIMIT 1) AS tabel1) > 0
THEN 'True'
ELSE 'False'
END
FROM elaoucontainergeneraldetails AS dn
WHERE objectroot_dn = 'SOME_VALUE';
Please let me know how can I increase the speed of this query.
Thanks in advance. Appreciate all help.
You can have the same solution using left join or exists:
SELECT
dn.name,
dn.objectroot_dn,
dn.distinguishedname,
CASE
WHEN dn_in.objectroot_dn is not null
THEN 'True'
ELSE 'False'
END
FROM elaoucontainergeneraldetails AS dn
LEFT JOIN elaoucontainergeneraldetails dn_in on dn_in.objectroot_dn = dn.distinguishedname
WHERE objectroot_dn = 'SOME_VALUE';
EXISTS(subquery) yields a boolean value:
SELECT dn.name
, dn.objectroot_dn
, dn.distinguishedname
, EXISTS (SELECT *
FROM elaoucontainergeneraldetails nx
WHERE nx.objectroot_dn = dn.distinguishedname
) AS truth_value
FROM elaoucontainergeneraldetails AS dn
WHERE dn.objectroot_dn = 'SOME_VALUE'
;
i have a table Transactions that looks similar to this:
id Type Field ObjectId NewValue
1 AddLink HasMember 4567 someDomain/someDirectory/1231
2 AddLink HasMember 4567 someDomain/someDirectory/1232
3 AddLink HasMember 4567 someDomain/someDirectory/1233
4 DeleteLink HasMember 4567 someDomain/someDirectory/1231
The numeric end of "NewValue" is what i am interested in.
In Detail, i need those records where i have a record where type is "AddLink" and where no newer record of type "DeleteLink" exists, i.e. the records with id = 2 or 3 (since 4 deletes 1)
The "ObjectId" as well as the numeric bit of "NewValue" both are IDs of entries of the "tickets" table, and i need the relevant tickets.
i tried this:
SELECT `Tickets`.* FROM `Transactions` AS `addedLinks`
LEFT JOIN `Tickets` ON RIGHT (`addedLinks`.`NewValue`, 4) = `Tickets`.`id`
WHERE `addedLinks`.`Type` = 'AddLink'
AND `addedLinks`.`Field` = 'Hasmember'
AND `addedLinks`.`ObjectId` = '4567'
AND NOT RIGHT (`addedLinks`.`NewValue`, 4) in (
SELECT `Tickets`.* FROM `Transactions` AS `deletedLinks`
LEFT JOIN `Tickets` ON RIGHT (`deletedLinks`.`NewValue`, 4) = `Tickets`.`id`
WHERE `deletedLinks`.`Type` = 'DeleteLink'
AND `addedLinks`.`id` < `deletedLinks`.`id`
AND `deletedLinks`.`Field` = 'Hasmember'
AND `deletedLinks`.`ObjectId` = '4567' )
This gives me:
SQL Error (1241): Operand should contain 1 column(s)
Unless i got something wrong, the problem is
RIGHT (`addedLinks`.`NewValue`, 4)
in the "AND NOT ... in()" statement.
Could anyone point me in the right direction here?
[EDIT]
Thanks to David K-J, the following works:
SELECT `Tickets`.* FROM `Transactions` AS `addedLinks`
LEFT JOIN `Tickets` ON RIGHT (`addedLinks`.`NewValue`, 4) = `Tickets`.`id`
WHERE `addedLinks`.`Type` = 'AddLink'
AND `addedLinks`.`Field` = 'Hasmember'
AND `addedLinks`.`ObjectId` = '5376'
AND NOT (RIGHT (`addedLinks`.`NewValue`, 4)) in (
SELECT `id` FROM `Transactions` AS `deletedLinks`
WHERE `deletedLinks`.`Type` = 'DeleteLink'
AND `addedLinks`.`id` < `deletedLinks`.`id`
AND `deletedLinks`.`Field` = 'Hasmember'
AND `deletedLinks`.`ObjectId` = '5376' )
but i don't understand why?
The problem here is your sub-select, as you are using it to provide the value of an IN clause, your sub-select should only select the id field, i.e. Transactions.* -> Transactions.id
So you end up with:
...
AND NOT (RIGHT (`addedLinks`.`NewValue`, 4)) IN
SELECT id FROM Transactions AS deletedLinks WHERE
...
The reason for this is that IN requires a list to compare with, so foo IN ( 1,2,3,4,5 ). If your subquery is selecting multiple fields, the resulting list is conceptually a list of lists (AoAs) like, [1, 'a'], [2, 'b'], [3, 'c'] and it's going to complain at you =)
Ah that's so complicated and with subquery... make it simpler, will be much faster
CREATE TEMPORARY TABLE `__del_max`
SELECT `NewValue`, MAX(`id`) as id FROM tickets
WHERE type = 'DeleteLink'
GROUP BY NewValue;
CREATE INDEX _nv ON __del_max(`NewValue`)
SELECT * FROM `tickets`
LEFT OUTER JOIN `__del_max` ON tickets.NewValue = __del_max.NewValue AND __del_max.id > tickets.id
WHERE __del_max.id IS NULL
You can have it in single, big join, but it'd be beneficial to have it in TMP table so you can add an index ;)
I am using function to update to one column , like
DetailedStatus = dbo.fn_GetProcessStageWiseStatus(PR.ProcessID, PR.ProcessRunID, getdate())
Here 500,000 records are continuously UPDATED in this line. Its like like a loop
So using this function for few records its executing fast but when its 500,000 records executing it becomes very slow...
What can I do to make this execute faster using many records?
Any measures to be taken or any split to be used?
Function:
CREATE FUNCTION [dbo].[fn_GetProcessStageWiseStatus]
(
#ProcessID INT
,#ProcessRunID INT
,#SearchDate SMALLDATETIME
)
RETURNS VARCHAR(100)
AS
BEGIN
DECLARE
#iLoopCount SMALLINT
,#iRowCount SMALLINT
,#StepProgress VARCHAR(100)
,#StepCount SMALLINT
IF EXISTS(
SELECT TOP 1 1
FROM dbo.Step S WITH(NOLOCK)
JOIN dbo.vw_FileGroup FG
ON S.FileConfigGroupID = FG.FileConfigGroupID
WHERE S.ProcessID = #ProcessID
AND S.Active = 1
AND FG.FileConfigGroupActive = 1
AND FG.Direction = 'Inbound'
)
BEGIN
SET #StepProgress = 'Not Received'
END
ELSE
BEGIN
SET #StepProgress = 'Not Started'
END
DECLARE #StepRunDetailsTable TABLE
(
KeyNo INT IDENTITY(1,1)
,StepID INT
,StepStartTime SMALLDATETIME
,StepEndTime SMALLDATETIME
,SourceEnv VARCHAR(100)
,DestEnv VARCHAR(100)
)
INSERT INTO #StepRunDetailsTable
SELECT
S.StepID
,MAX(isnull(SR.StepStartTime, '06/06/2079'))
,MAX(isnull(SR.StepEndTime, '06/06/2079'))
,isnull(SENV.EnvironmentName, '')
,isnull(DENV.EnvironmentName, '')
FROM dbo.ProcessRun PR WITH(NOLOCK)
JOIN dbo.StepRun SR WITH(NOLOCK)
ON SR.ProcessRunID = PR.ProcessRunID
JOIN dbo.vw_StepHierarchy SH
ON SR.StepID = SH.StepID
AND SH.Active = 1
JOIN dbo.Step S WITH(NOLOCK)
ON SH.StepID = S.StepID
JOIN dbo.WorkFlow WF WITH(NOLOCK)
ON S.WorkFlowID = WF.WorkFlowID
AND WF.Active = 1
JOIN dbo.Environment SENV WITH(NOLOCK)
ON SENV.EnvironmentID = WF.SourceEnvironmentID
AND SENV.Active = 1
JOIN dbo.Environment DENV WITH(NOLOCK)
ON DENV.EnvironmentID = WF.DestinationEnvironmentID
AND DENV.Active = 1
WHERE PR.ProcessRunID = #ProcessRunID
GROUP BY S.StepID, SENV.EnvironmentName, DENV.EnvironmentName, SH.StepOrder
ORDER BY SH.StepOrder ASC
SELECT #StepCount = COUNT(*)
FROM dbo.ProcessRun PR WITH(NOLOCK)
JOIN dbo.Step S WITH(NOLOCK)
ON PR.ProcessID = S.ProcessID
AND PR.ProcessRunID = #ProcessRunID
AND S.Active = 1
SELECT #iRowCount = COUNT(DISTINCT StepID) FROM #StepRunDetailsTable
SET #iLoopCount = 0
WHILE (#iRowCount > #iLoopCount)
BEGIN
SET #iLoopCount = #iLoopCount + 1
SELECT
#StepProgress =
CASE
--WHEN #SearchDate BETWEEN StepStartTime AND StepEndTime
WHEN #SearchDate >= StepStartTime AND #SearchDate <= StepEndTime
THEN DestEnv + ' Load in Progress'
WHEN #SearchDate > StepEndTime AND #iLoopCount < #StepCount
THEN 'Waiting on next step - Loaded to ' + DestEnv
WHEN #SearchDate > StepEndTime AND #iLoopCount = #StepCount
THEN 'Completed'
WHEN #SearchDate < StepStartTime AND #iLoopCount = 1
THEN 'Load Not Started'
ELSE #StepProgress
END
FROM #StepRunDetailsTable
WHERE KeyNo = #iLoopCount
END
RETURN #StepProgress
END
Thanks in advance.
Seems like you have a change in execution plan when you try to update 500k rows.
You can try and set forceseek hint on the from clause to force using seeks instead of scans.
Also, WHILE (#iRowCount > #iLoopCount) should be replaced with if exists, because you basically check for certain conditions on the results table and you need to return as early as possible.
I see that you use nolock hint everywhere to allow dirty reads, you can set isolation level read uncommitted in the calling stored procedure and remove all of those; or consider to change the database to set read_committed_snapshot on to avoid locks.
By the way, scalar function calls in SQL Server are very expensive, so if you have some massive updates/selects happening in a loop where you call a function you have to avoid using functions as much as possible.
I've created this temporal table in my store procedure, as you can see I have more than 1 records for the same ID:
#tmpTableResults
TmpInstallerID TmpConfirmDate TmpConfirmLocalTime
============== ============== ===================
173 2011-11-08 11:45:50
278 2011-11-04 09:06:26
321 2011-11-08 13:21:35
321 2011-11-08 11:44:54
483 2011-11-08 11:32:00
483 2011-11-08 11:31:59
645 2011-11-04 10:03:15
645 2011-11-04 07:03:15
That is the result of the query to create #tmpTableResults
DECLARE #tmpTableResults TABLE
(
TmpInstallerID int,
TmpConfirmDate date,
TmpConfirmLocalTime time
)
DECLARE #tmpTableQuery VarChar(800)
SET #tmpTableQuery = 'select FxWorkorder.INSTALLERSYSID, FxWorkorder.CONFIRMDATE, FxWorkorder.CONFIRMLOCALTIME from FxWorkorder
join install on FxWorkorder.INSTALLERSYSID = install.sysid
join RouteGroupWorkarea on FxWorkorder.WORKAREAGROUPSYSID = RouteGroupWorkarea.IWORKAREA_ID
join RoutingGroup on RouteGroupWorkarea.IRG_ID = RoutingGroup.IRG_IDENTITY
where FxWorkorder.SCHEDULEDDATE > = #StartDate and FxWorkorder.SCHEDULEDDATE <= #EndDate
and FxWorkorder.Jobstatus <> "Unassign"
and FxWorkorder.Jobstatus <> "Route"
and install.FOXTELCODE <> ""
and FxWorkorder.CONFIRMLOCALTIME is not null
and FxWorkorder.CONFIRMDATE <> ""
group by FxWorkorder.INSTALLERSYSID, FxWorkorder.CONFIRMDATE, FxWorkorder.CONFIRMLOCALTIME
order by FxWorkorder.INSTALLERSYSID, FxWorkorder.CONFIRMDATE, FxWorkorder.CONFIRMLOCALTIME desc '
INSERT INTO #tmpTableResults EXEC(#tmpTableQuery)
I'm creating another query to get data from another table and only the first record from the temporal table for the same INSTALLERSYSID
SELECT RoutingGroup.SDESCRIPTION, FxWorkorder.INSTALLERSYSID, FxWorkOrder.JOBSTATUS, Install.FOXTELCODE,
install.NAME, FxWorkOrder.ScheduledDate,
count(*) as TotalJobs, COUNT(CONFIRMDATE) as ConfirmedJobs,
(select TmpInstallerID, TmpConfirmDate, TmpConfirmLocalTime from #tmpTableResults where TmpInstallerID = FxWorkorder.INSTALLERSYSID)
from FxWorkorder
join install on fxworkorder.INSTALLERSYSID = install.sysid
join RouteGroupWorkarea on FxWorkOrder.WORKAREAGROUPSYSID = RouteGroupWorkarea.IWORKAREA_ID
join RoutingGroup on RouteGroupWorkarea.IRG_ID = RoutingGroup.IRG_IDENTITY
where FxWorkorder.SCHEDULEDDATE > = #StartDate and FxWorkorder.SCHEDULEDDATE <= #EndDate
and FxWorkOrder.Jobstatus <> 'Unassign'
and FxWorkOrder.Jobstatus <> 'Route'
and Install.FOXTELCODE <> ''
group by RoutingGroup.SDESCRIPTION,FxWorkOrder.INSTALLERSYSID, FxWorkOrder.JOBSTATUS, Install.FOXTELCODE,install.NAME, FxWorkOrder.ScheduledDate,FxWorkOrder.WORKAREAGROUPSYSID
When I tried to save the sp I got the error
"Only one expression can be specified in the select list when the subquery is not introduced with EXISTS."
I can't see why I got this error. But if I run the query in sql that works. Can someone see the error?
I don't know how your second query works for you ‘in sql’ (where is that supposed to be? do you mean SSMS = SQL Server Management Studio?), but I'm sure it cannot possibly work in any version of SQL Server that exists at the moment. It's because of this subquery in the SELECT list:
(select TmpInstallerID, TmpConfirmDate, TmpConfirmLocalTime from #tmpTableResults where TmpInstallerID = FxWorkorder.INSTALLERSYSID)
The thing is, every expression in the SELECT clause should be scalar, but this subquery returns a row of more than one value. Even if it's only one row, it is illegal there, because it returns several columns. The subquery in that context should return no more than one value, i.e. it should be one column and the result produced should contain either no rows or just one.
You could try this query instead (although I'm not entirely sure without knowing more details about your schema):
SELECT
RoutingGroup.SDESCRIPTION,
FxWorkorder.INSTALLERSYSID,
FxWorkOrder.JOBSTATUS,
Install.FOXTELCODE,
install.NAME, FxWorkOrder.ScheduledDate,
count(*) as TotalJobs, COUNT(CONFIRMDATE) as ConfirmedJobs,
tmp.TmpInstallerID,
tmp.TmpConfirmDate,
tmp.TmpConfirmLocalTime
from FxWorkorder
join install on fxworkorder.INSTALLERSYSID = install.sysid
join RouteGroupWorkarea on FxWorkOrder.WORKAREAGROUPSYSID = RouteGroupWorkarea.IWORKAREA_ID
join RoutingGroup on RouteGroupWorkarea.IRG_ID = RoutingGroup.IRG_IDENTITY
join #tmpTableResults tmp ON tmp.TmpInstallerID = FxWorkorder.INSTALLERSYSID
where FxWorkorder.SCHEDULEDDATE > = #StartDate
and FxWorkorder.SCHEDULEDDATE <= #EndDate
and FxWorkOrder.Jobstatus <> 'Unassign'
and FxWorkOrder.Jobstatus <> 'Route'
and Install.FOXTELCODE <> ''
group by
RoutingGroup.SDESCRIPTION,
FxWorkOrder.INSTALLERSYSID,
FxWorkOrder.JOBSTATUS,
Install.FOXTELCODE,install.NAME,
FxWorkOrder.ScheduledDate,
FxWorkOrder.WORKAREAGROUPSYSID
tmp.TmpInstallerID,
tmp.TmpConfirmDate,
tmp.TmpConfirmLocalTime
That is, I added one more join, the one to #tmpTableResults, as well as added the columns you were trying to pull to the SELECT clause and to the GROUP BY clause.
Also, if I were you I would consider using short aliases for tables, like this:
SELECT
…
wo.INSTALLERSYSID,
wo.JOBSTATUS,
…
from FxWorkorder wo
join …
That might make your queries more readable.