Selecting the union part of an sql query - sql

I have this query
SELECT
L.Account,
L.PaidOffDate
FROM
MARS.dbo.vw_Loans L
WHERE
L.isActive = 'False'
AND L.LoanStatus NOT LIKE '%REO%'
AND L.LoanStatus <> 'Trailing Claims'
)
UNION
-- loan numbers for REO sold
(
SELECT
L.Account,
R.SoldDate
FROM
MARS.dbo.vw_REO R
LEFT JOIN
MARS.dbo.vw_Loans L ON L.ConvertedToPropertyID = R.PropertyID
WHERE
R.Active = 0
AND R.Status = 'Sold'
AND L.isActive = 'False'
AND L.LoanStatus LIKE '%REO%'
)
I put this as a common table expression, how do I select R.SoldDate in that case?
Specifically I am trying to run this
CASE
WHEN Inactives.PaidOffDate IS NOT NULL
AND Inactives.PaidOffDate BETWEEN DATEADD(MONTH, DATEDIFF(MONTH, 0, #reportingDate), -1) AND #reportingDate
THEN Inactives.PaidOffDate
ELSE
CASE
WHEN Inactives.SoldDate IS NOT NULL
AND Inactives.SoldDate BETWEEN DATEADD(MONTH, DATEDIFF(MONTH, 0, #reportingDate), -1) AND #reportingDate
THEN Inactives.SoldDate
ELSE ''
END
END AS [CHECKING PIF DATE]
But I cannot select Inactives.SoldDate

I think what you are after here is a computed column, something like this:
SELECT
L.Account,
L.PaidOffDate,
'Payoff Date' AS Type
FROM MARS.dbo.vw_Loans L
WHERE
L.isActive = 'False' AND
L.LoanStatus NOT LIKE '%REO%' AND
L.LoanStatus <> 'Trailing Claims'
UNION ALL
SELECT
L.Account,
R.SoldDate,
'Sale Date'
FROM MARS.dbo.vw_REO R
LEFT JOIN MARS.dbo.vw_Loans L
ON L.ConvertedToPropertyID = R.PropertyID
WHERE
R.Active = 0 AND
R.Status = 'Sold' AND
L.isActive = 'False' AND
L.LoanStatus LIKE '%REO%';
The computed column Type keeps track of the origin of each record, so that you will know this after the union has been peformed. Note that I switched to UNION ALL, assuming that you always wanted to retain all records.

You need to put the values into separate columns rather than separate *rows. I think the logic you want is conditional logic:
SELECT L.Account,
(CASE WHEN L.LoanStatus NOT LIKE '%REO%' AND L.LoanStatus <> 'Trailing Claims'
THEN L.PaidOffDate
END) as PaidOffDate
(CASE WHEN L.LoanStatus LIKE '%REO%'
THEN R.SoldDate
END) as R.SoldDate
FROM MARS.dbo.vw_Loans L LEFT JOIN
MARS.dbo.vw_REO R
ON L.ConvertedToPropertyID = R.PropertyID AND
R.Active = 0 AND R.Status = 'Sold'
WHERE L.isActive = 'False';
The other possibility is that you actually want two separate CTEs, one for each part of the query.

Related

SQL query with poor performances

I inherited from a SQL query that is quite slow to run (2-2mins20 on average) while the amount of data isn't huge.
I'm not yet much comfortable with SQL but I did attempt to use a temporary table variable in order to have a lookup table to find the region associated with each country. It didn't change anything regarding the total cost of the query (which is 4780, found via an EXPLAIN in DataGrid).
I'm unsure of how I could make it faster besides the creation of the right indexes.
SELECT CASE
WHEN Sites.country IN
('Australia', 'Hong Kong', 'India', 'Korea, Republic of', 'Malaysia', 'New Zealand', 'Philippines',
'Singapore', 'Taiwan', 'Thailand', 'Viet Nam')
THEN 'APAC'
WHEN Sites.country IN ('China')
THEN 'China'
WHEN Sites.country IN
('Austria', 'Belgium', 'Bulgaria', 'Croatia', 'Czech Republic', 'Denmark', 'Estonia', 'Finland',
'France', 'Germany', 'Greece', 'Hungary', 'Ireland', 'Israel', 'Italy', 'Latvia', 'Lebanon',
'Lithuania', 'Netherlands', 'Norway', 'Poland', 'Portugal', 'Romania', 'Russian Federation',
'Saudi Arabia', 'Serbia', 'South Africa', 'Spain', 'Sweden', 'Switzerland', 'Turkey', 'Ukraine',
'United Arab Emirates', 'United Kingdom')
THEN 'EMEA'
WHEN Sites.country IN ('Japan')
THEN 'Japan'
WHEN Sites.country IN
('Argentina', 'Brazil', 'Chile', 'Colombia', 'Costa Rica', 'Guatemala', 'Mexico', 'Peru', 'Puerto Rico')
THEN 'Latin America'
WHEN Sites.country IN ('Canada', 'United States')
THEN 'North America'
ELSE '?'
END AS 'Region',
Sites.country AS 'Country',
Protocols.number AS 'Protocol #',
Sites.number AS 'Site #',
VisitReports.finalized AS 'Finalized date',
VisitReports.startDate AS 'Start date',
VisitReports.endDate AS 'End date',
VisitReports.visitMode AS 'Mode',
LEN(REPLACE(VisitReports.remoteVisitDates, ',', '')) / 13 AS '# of remote dates',
VisitReports.onSiteVisitDates AS 'On site dates',
VisitReports.remoteVisitDates AS 'Remote dates',
VisitReports.visitId AS 'Visit ID',
CASE
WHEN R2Answer.data LIKE '%choice_yes%' THEN 'Yes'
WHEN R2Answer.data LIKE '%choice_no%' THEN 'No'
ELSE '-'
END AS 'R2',
CASE
WHEN SDR5Answer.data LIKE '%choice_yes%' THEN 'Yes'
WHEN SDR5Answer.data LIKE '%choice_no%' THEN 'No'
ELSE '-'
END AS 'SDR5',
CASE
WHEN SDR5_3Answer.data LIKE '%choice_yes%' THEN 'Yes'
WHEN SDR5_3Answer.data LIKE '%choice_no%' THEN 'No'
ELSE '-'
END AS 'SDR5_3',
CASE
WHEN SDR6Answer.data LIKE '%choice_yes%' THEN 'Yes'
WHEN SDR6Answer.data LIKE '%choice_no%' THEN 'No'
ELSE '-'
END AS 'SDR6',
CASE
WHEN SDR7Answer.data LIKE '%choice_yes%' THEN 'Yes'
WHEN SDR7Answer.data LIKE '%choice_no%' THEN 'No'
WHEN SDR7Answer.data LIKE '%choice_n_a%' THEN 'N/A'
ELSE '-'
END AS 'SDR7',
(SELECT COUNT(*)
FROM [DB].[SCHEMA].ActionItems
WHERE ActionItems.siteId = Sites.id
AND ActionItems.deletedAt IS NULL
AND ActionItems.createdAt > VisitReports.startDate
AND ActionItems.createdAt < VisitReports.finalized) AS '# created ActionItems',
(SELECT COUNT(DISTINCT ActionItems.id)
FROM [DB].[SCHEMA].ActionItemUpdates
JOIN [DB].[SCHEMA].ActionItems
ON ActionItems.id = ActionItemUpdates.actionItemId
AND ActionItems.siteId = Sites.id
WHERE ActionItemUpdates.deletedAt IS NULL
AND ActionItemUpdates.updateType IS NULL
AND ActionItemUpdates.createdAt > VisitReports.startDate
AND ActionItemUpdates.createdAt < VisitReports.finalized) AS '# updated ActionItems',
(SELECT COUNT(*)
FROM [DB].[SCHEMA].ActionItems
WHERE ActionItems.siteId = Sites.id
AND ActionItems.deletedAt IS NULL
AND ActionItems.closed > VisitReports.startDate
AND ActionItems.closed < VisitReports.finalized) AS '# closed ActionItems'
FROM [DB].[SCHEMA].Sites
JOIN [DB].[SCHEMA].Protocols on Protocols.id = Sites.protocolId
JOIN [DB].[SCHEMA].VisitReports ON VisitReports.siteId = Sites.id
AND questionnaireVersion >= 7
AND visitType = 'ongoing'
AND finalized IS NOT NULL
AND VisitReports.endDate > '2022-01-01' AND VisitReports.endDate < '2022-11-11'
LEFT JOIN [DB].[SCHEMA].Answers AS R2Answer ON R2Answer.reportId = VisitReports.id
AND R2Answer.questionId = 'R3'
LEFT JOIN [DB].[SCHEMA].Answers AS SDR5Answer
ON SDR5Answer.reportId = VisitReports.id
AND SDR5Answer.questionId = 'SDR3'
LEFT JOIN [DB].[SCHEMA].Answers AS SDR5_3Answer
ON SDR5_3Answer.reportId = VisitReports.id
AND SDR5_3Answer.questionId = 'SDR3.3'
LEFT JOIN [DB].[SCHEMA].Answers AS SDR6Answer
ON SDR6Answer.reportId = VisitReports.id
AND SDR6Answer.questionId = 'SDR10'
LEFT JOIN [DB].[SCHEMA].Answers AS SDR7Answer
ON SDR7Answer.reportId = VisitReports.id
AND SDR7Answer.questionId = 'SDR4'
ORDER BY [Finalized date]
Thank you in advance for your help!
You can try wth OUTER APPLY and conditional aggregation (CASE WHEN inside the aggregation function).
Something like:
SELECT
...
s.country AS [Country],
p.number AS [Protocol #],
s.number AS [Site #],
vr.finalized AS [Finalized date],
vr.startdate AS [Start date],
vr.enddate AS [End date],
vr.visitmode AS [Mode],
LEN(REPLACE(vr.remotevisitdates, ',', '')) / 13 AS [# of remote dates],
vr.onsitevisitdates AS [On site dates],
vr.remotevisitdates AS [Remote dates],
vr.visitId AS [Visit ID],
ans.[R3] AS [Answer R3],
ans.[SDR3] AS [Answer SDR3],
...
act.created AS [# created ActionItems],
act.updated AS [# updated ActionItems],
act.closed AS [# closed ActionItems]
FROM sites s
JOIN protocols p ON p.id = s.protocolid
JOIN visitreports vr ON vr.siteid = s.id
AND vr.questionnaireversion >= 7
AND vr.visittype = 'ongoing'
AND vr.finalized IS NOT NULL
AND vr.enddate > '2022-01-01'
AND vr.enddate < '2022-11-11'
OUTER APPLY
(
SELECT
COUNT(CASE WHEN ai.deletedat IS NULL AND ai.createdat > vr.startdate AND ai.createdat < vr.finalized THEN 1 END) AS created,
COUNT(CASE WHEN ai.deletedat IS NULL AND ai.closed > vr.startdate AND ai.closed < vr.finalized THEN 1 END) AS closed,
COUNT(CASE WHEN EXISTS
(
SELECT NULL
FROM actionitemupdates aiu
WHERE aiu.actionitemid = ai.id
AND aiu.updateType IS NULL
AND aiu.createdAt > vr.startDate
AND aiu.createdAt < vr.finalized
) THEN 1 END) AS updated
FROM actionitems ai
WHERE ai.siteid = s.id
) act
OUTER APPLY
(
SELECT
MAX(CASE WHEN a.questionId = 'R3' THEN
CASE WHEN a.data LIKE '%choice_yes%' THEN 'Yes'
WHEN a.data LIKE '%choice_no%' THEN 'No'
ELSE '-'
END
END) AS [R3],
MAX(CASE WHEN a.questionId = 'SDR3' THEN
CASE WHEN a.data LIKE '%choice_yes%' THEN 'Yes'
WHEN a.data LIKE '%choice_no%' THEN 'No'
ELSE '-'
END
END) AS [SDR3],
...
FROM answers a
WHERE a.reportid = vr.id
) ans
ORDER BY [Finalized date];
In any way you should have indexes on answers(reportid) and on actionitems(siteid) to be able to join the answers and action types quickly.
In order to access the YES/NO/- directly, I suggest you add a computed column to your answers table. That will simplyfy above query.
ALTER TABLE answers ADD yes_or_no AS (CASE WHEN data LIKE '%choice_yes%' THEN 'Yes' WHEN data LIKE '%choice_no%' THEN 'No' ELSE '-' END) PERSISTED;
UPDATE
Due to two shortcomings in SQL Server, the first OUTER APPLY must be split into two steps, otherwise you'll get syntax errors:
OUTER APPLY
(
SELECT
SUM(is_created) AS created,
SUM(is_closed) AS closed,
SUM(is_updated) AS updated
FROM
(
SELECT
CASE WHEN ai.deletedat IS NULL AND ai.createdat > vr.startdate AND ai.createdat < vr.finalized THEN 1 ELSE 0 END AS is_created,
CASE WHEN ai.deletedat IS NULL AND ai.closed > vr.startdate AND ai.closed < vr.finalized THEN 1 ELSE 0 END AS is_closed,
CASE WHEN EXISTS (SELECT NULL
FROM actionitemupdates aiu
WHERE aiu.actionitemid = ai.id
AND aiu.updateType IS NULL
AND aiu.createdAt > vr.startDate
AND aiu.createdAt < vr.finalized
) THEN 1 ELSE 0 END AS is_updated
FROM actionitems ai
WHERE ai.siteid = s.id
) precomputed
) act
As you stated, a Countries region lookup table makes the code cleaner. Besides that, I would look for opportunities to reduce data volume from Answers and ActionItemUpdates if the table size is significant. After that, aggregate Answers to reportId level; ActionItems and ActionItemUpdates to siteId level. Since visitType='ongoing', it seems that it's 1-to-1 between the two results. The last step is to join them together to get a site-level report.
with cte_visitReports as (
select id,
siteId,
finalized,
startDate,
endDate,
visitMode,
visitId,
onSiteVisitDates,
remoteVisitDates
from VisitReports
where endDate > '2022-01-01'
and endDate < '2022-11-11'
and questionnaireVersion >= 7
and visitType = 'ongoing'
and finalized IS NOT NULL),
cte_answers as (
select a.reportId,
max(case
when a.questionId='R3' and a.data like '%choice_yes%' then 'Yes'
when a.questionId='R3' and a.data like '%choice_no%' then 'No'
else '-'
end) as R2,
max(case
when a.questionId='SDR3' and a.data like '%choice_yes%' then 'Yes'
when a.questionId='SDR3' and a.data like '%choice_no%' then 'No'
else '-'
end) as SDR5,
max(case
when a.questionId='SDR3.3' and a.data like '%choice_yes%' then 'Yes'
when a.questionId='SDR3.3' and a.data like '%choice_no%' then 'No'
else '-'
end) as SDR5_3,
max(case
when a.questionId='SDR10' and a.data like '%choice_yes%' then 'Yes'
when a.questionId='SDR10' and a.data like '%choice_no%' then 'No'
else '-'
end) as SDR6,
max(case
when a.questionId='SDR4' and a.data like '%choice_yes%' then 'Yes'
when a.questionId='SDR4' and a.data like '%choice_no%' then 'No'
when a.questionId='SDR4' and a.data like '%choice_n_a%' then 'N/A'
else '-'
end) as SDR7
from Answers a
join cte_visitReports r
on a.reportId = r.id
where a.questionId in ('R3','SDR3','SDR3.3','SDR10','SDR4')
-- additional filters such as createdAt if available to reduce data volume
group by a.reportId),
cte_action_items as (
select ai.siteId,
count(distinct case when ai.deletedAt is null and ai.createdAt > r.startDate and ai.createdAt < r.finalized then ai.id end) as created_action_items,
count(distinct case when ai.deletedAt is null and ai.closed > r.startDate and ai.closed < r.finalized then ai.id end) as closed_action_items,
count(distinct case when iu.deletedAt is null and iu.createdAt > r.startDate and iu.createdAt < r.finalized then ai.id end) as updated_action_items
from ActionItems ai
join cte_visitReports r
on ai.siteId = r.siteId
left
join ActionItemUpdates iu
on ai.id = iu.actionItemId
where 1 = 1
-- additional filters if possible ro reduce data volume
group by ai.siteId)
select coalesce(c.region,'?') as 'Region',
s.country as 'Country',
p.number as 'Protocol #',
s.number as 'Site #',
r.finalized as 'Finalized date',
r.startDate as 'Start date',
r.endDate as 'End Date',
r.visitMode as 'Mode',
len(replace(r.remoteVisitDates, ',', '')) / 13 as '# of remote dates',
r.onSiteVisitDates as 'On site dates',
r.remoteVisitDates as 'Remote dates',
r.visitId as 'Visit ID',
coalesce(a.R2,'-') as 'R2',
coalesce(a.SDR5,'-') as 'SDR5',
coalesce(a.SDR5_3,'-') as 'SDR5_3',
coalesce(a.SDR6,'-') as 'SDR6',
coalesce(a.SDR7,'-') as 'SDR7',
coalesce(ai.created_action_items,0) as '# created ActionItems',
coalesce(ai.updated_action_items,0) as '# updated ActionItems',
coalesce(ai.closed_action_items,0) as '# closed ActionItems'
from Sites s
left
join Countries c
on s.country = c.country
join Protocols p
on s.protocolId = p.id
join cte_visitReports r
on s.id = r.siteId
left
join cte_answers a
on r.id = a.reportId
left
join cte_action_items ai
on s.id = ai.siteId
order by r.finalized;
If the report response time is critical, I would try the following approaches:
Tune the queries
Cache the result (ie. materialized views)
Create a datamart for reports and dashboards

Duplicate data when working with multiple tables. Clarification needed

I have a very simple table as shown when query returning clean data select * from Income where symbol = 'AAPL' and statementitem = 'Revenues' and periodtype="Annual";
--
When I attempt to put together a report, I get 0 from someplace. How can I remove the 0 to get a clean output? Where do these 0s come from?
DROP TABLE IF EXISTS _vars;
CREATE TABLE _vars(symbol);
INSERT INTO _vars(symbol) VALUES ('AAPL');
SELECT distinct a.yearmonth, a.symbol, periodtype,
case when a.statementitem = 'Revenues' AND a.periodtype = 'Annual' then (CASE WHEN (a.value is null or a.value = '') then 0 ELSE a.value END) else 0 end Revenue,
case when a.statementitem = 'Gross Profit' AND a.periodtype = 'Annual' then (CASE WHEN (a.value is null or a.value = '') then 0 ELSE a.value END) else 0 end GrossProfit,
case when a.statementitem = 'Selling General & Admin Expenses' AND a.periodtype = 'Annual' then (CASE WHEN (a.value is null or a.value = '') then 0 ELSE a.value END) else 0 end GrossProfit
FROM _vars
INNER JOIN Income a ON a.symbol = _vars.symbol and a.periodtype = 'Annual'
Your 1st query contains 3 conditions:
WHERE symbol = 'AAPL' AND statementitem = 'Revenues' AND periodtype = 'Annual'
and the result is 10 rows.
Your 2nd query joins _vars to the table and since _vars contains only 1 row with the column symbol having value 'AAPL' and you also apply the condition:
and a.periodtype = 'Annual'
in the ON clause, you are covering only 2 of the conditions of the 1st query.
You do not apply the condition:
statementitem = 'Revenues'
you are just checking it in:
case when a.statementitem = 'Revenues' AND .....
Checking a condition does not apply it.
This means that you get more rows in the results that are coming from all the rows that do not have 'Revenues' in the column statementitem and the CASE expression returns 0 for these rows in the column Revenue.
Edit:
You should use conditional aggregation:
SELECT a.yearmonth, a.symbol, a.periodtype,
COALESCE(MAX(CASE WHEN a.statementitem = 'Revenues' THEN a.value END), 0) Revenue,
COALESCE(MAX(CASE WHEN a.statementitem = 'Gross Profit' THEN a.value END), 0) GrossProfit,
COALESCE(MAX(CASE WHEN a.statementitem = 'Selling General & Admin Expenses' THEN a.value END), 0) [Selling General & Admin Expenses]
FROM _vars INNER JOIN Income a
ON a.symbol = _vars.symbol AND a.periodtype = 'Annual'
GROUP BY a.yearmonth, a.symbol, a.periodtype
You are getting 0 because of the below case statement. If your value is null and statementitem is not 'Revenues' and periodtype is not 'Annual', you are a making it as 0
case when a.statementitem = 'Revenues' AND a.periodtype = 'Annual'
then (CASE WHEN (a.value is null or a.value = '') then 0 ELSE a.value END) else 0
You can get rid of these if you don't want 0's in your result.
This will give you without 0's but with nulls,
SELECT distinct a.yearmonth, a.symbol, periodtype,
a.value as Revenue
FROM _vars
inner JOIN Income a ON a.symbol = _vars.symbol
where a.statementitem = 'Revenues' and a.periodtype = 'Annual'
This query will give you no nulls,
SELECT distinct a.yearmonth, a.symbol, periodtype,
a.value as Revenue
FROM _vars
inner JOIN Income a ON a.symbol = _vars.symbol
where a.statementitem = 'Revenues' and a.periodtype = 'Annual'
and (a.value is null or a.value = '')
Without Inner join,
SELECT distinct a.yearmonth, a.symbol, periodtype,
a.value as Revenue
from Income a
where a.statementitem = 'Revenues' and a.periodtype = 'Annual'
and (a.value is null or a.value = '')
and a.symbol in ('AAPL');
these duplicate data are because of records that are (AAPL,Annual) but are not (Revenues).you should move the condition of statementitem in where cluse or in join condition:
SELECT distinct a.yearmonth, a.symbol, periodtype,isnull(a.value,0) as Revenue
FROM _vars
inner JOIN Income a ON a.symbol = _vars.symbol
where a.statementitem = 'Revenues' and a.periodtype = 'Annual'
or
SELECT distinct a.yearmonth, a.symbol, periodtype,isnull(a.value,0) as revenue
FROM _vars
inner JOIN Income a ON a.symbol = _vars.symbol
and a.statementitem = 'Revenues' and a.periodtype = 'Annual'
Please use below query,
With Join
SELECT distinct a.yearmonth, a.symbol, periodtype,
case when a.statementitem = 'Revenues' then (CASE WHEN (a.value is null or a.value = '') then 0 ELSE a.value END) else 0 end Revenue,
case when a.statementitem = 'Gross Profit' then (CASE WHEN (a.value is null or a.value = '') then 0 ELSE a.value END) else 0 end GrossProfit,
case when a.statementitem = 'Selling General & Admin Expenses' then (CASE WHEN (a.value is null or a.value = '') then 0 ELSE a.value END) else 0 end GrossProfit
FROM _vars
INNER JOIN Income a ON a.symbol = _vars.symbol
where a.periodtype = 'Annual'
Without Join
SELECT distinct a.yearmonth, a.symbol, periodtype,
case when a.statementitem = 'Revenues' then (CASE WHEN (a.value is null or a.value = '') then 0 ELSE a.value END) else 0 end Revenue,
case when a.statementitem = 'Gross Profit' then (CASE WHEN (a.value is null or a.value = '') then 0 ELSE a.value END) else 0 end GrossProfit,
case when a.statementitem = 'Selling General & Admin Expenses' then (CASE WHEN (a.value is null or a.value = '') then 0 ELSE a.value END) else 0 end GrossProfit
FROM Income a
where a.periodtype = 'Annual'
and a.symbol in ('AAPL');

How to write SQL query to ignore duplicate row with null value

My View shows Duplicate row which i don't want.
I am geting
1, YM
1, NULL
2, YM
2, NULL
With below Code
SELECT
dbo.Store.SID,
CASE WHEN dbo.Store.SID <> dbo.FileStore.SID THEN NULL
WHEN dbo.FileStore.MailSent = 'M' THEN 'YM'
WHEN dbo.FileStore.SID = dbo.Store.SID AND dbo.FileStore.FileType = 1 THEN 'Y'
ELSE NULL END AS FM
FROM
dbo.STORE
INNER JOIN dbo.FileStore ON dbo.Store.SID = dbo.FileStore.SID
I am looking for
1 YM
2 YM
You appear to want filtering. If I understand correctly:
SELECT s.SID,
(CASE WHEN fs.MailSent = 'M' THEN 'YM'
WHEN fs.FileType = 1 THEN 'Y'
END) AS FM
FROM dbo.STORE s INNER JOIN
dbo.FileStore fs
ON s.SID = fs.SID
WHERE fs.MailSent = 'M' OR fs.FileType = 1;
There is no reason to repeat the JOIN conditions in the CASE expression. You know they are true because of the JOIN.
SELECT
dbo.Store.SID
,CASE
WHEN dbo.Store.SID <> dbo.FileStore.SID THEN NULL --will never happen since it's an inner join
WHEN dbo.FileStore.MailSent = 'M' THEN 'YM'
WHEN dbo.FileStore.SID = dbo.Store.SID --will happen always since it's an inner join
AND dbo.FileStore.FileType = 1 THEN 'Y'
ELSE NULL -- this is the cause for Null, you have FileStore.MailSent <> 'M'
END AS FM
FROM dbo.STORE
INNER JOIN dbo.FileStore
ON dbo.Store.SID = dbo.FileStore.SID

SQL Server - 2008 : Nested Select, need improve execution faster?

Here the problem:
First I have a nested query, for which I need to improve the execution time and make it faster. Imagine 47 seconds at first time and second time was 46 / 45 second. Second was running by cache (the second execution always faster than first time but not this).
Second that query uses SUM, CAST, CASE in each sub select. Can't dodge that
Third I read some another solution from internet using OPTION (FAST 500).
Here the example :
SELECT [cutomerSection],
SUM(DEBIT) AS DEBIT,
SUM(CREDIT) AS CREDIT,
SUM([OTHERS]) AS 'OTHERS'
FROM
(-- SECTOR A
SELECT cb.paymentGrp AS 'cutomerSection',
CASE
WHEN j.paymentStat = 'DEBIT' THEN SUM(CAST(ISNULL(isnull(qty, 1)*(100-disc)*d.adm/100, 0) AS INT)) + SUM(CAST(ISNULL(isnull(qty, 1)*(100-disc)*(d.fee-d.adm)/100, 0) AS INT))
ELSE 0
END AS 'DEBIT',
CASE
WHEN j.paymentStat = 'CREDIT' THEN SUM(CAST(ISNULL(isnull(qty, 1)*(100-disc)*d.adm/100, 0) AS INT)) + SUM(CAST(ISNULL(isnull(qty, 1)*(100-disc)*(d.fee-d.adm)/100, 0) AS INT))
ELSE 0
END AS 'CREDIT',
CASE
WHEN (j.paymentStat = ''
OR j.paymentStat IS NULL) THEN SUM(CAST(ISNULL(isnull(qty, 1)*(100-disc)*d.adm/100, 0) AS INT)) + SUM(CAST(ISNULL(isnull(qty, 1)*(100-disc)*(d.fee-d.adm)/100, 0) AS INT))
ELSE 0
END AS 'OTHERS'
FROM tbactDetail d WITH(NOLOCK)
LEFT JOIN tbsectorSection j WITH(NOLOCK) ON d.tranCode = j.tranCode
LEFT JOIN tbact t ON (d.actCode=t.actCode
AND t.sectorCode = j.sectorCode)
LEFT JOIN tbCustomer c WITH(NOLOCK) ON c.custCode=j.custCode
LEFT JOIN tbfrontDesk a WITH(NOLOCK) ON a.struckNo=j.struk
LEFT JOIN tbpaymentList cb WITH(NOLOCK) ON cb.paymentK = a.paymentK
LEFT JOIN tbleading dc ON dc.leadCode = j.leadCode
LEFT JOIN tbsector p ON j.sectorCode = p.sectorCode
WHERE (j.deleted IS NULL
OR j.deleted = 0)
AND a.status = 'FINISH'
AND (j.tranDate BETWEEN '2018-11-01 00:00:00' AND '2018-11-01 23:59:59')
GROUP BY cb.paymentGrp,
j.paymentStat
UNION ALL -- SECTOR PARK
SELECT cb.paymentGrp AS 'cutomerSection',
CASE
WHEN t.paymentStat = 'DEBIT' THEN SUM(CAST(isnull(d.rate*d.qty*(100-disc)/100, 0) AS INT))
ELSE 0
END AS 'DEBIT',
CASE
WHEN t.paymentStat = 'CREDIT' THEN SUM(CAST(isnull(d.rate*d.qty*(100-disc)/100, 0) AS INT))
ELSE 0
END AS 'CREDIT',
CASE
WHEN (t.paymentStat = ''
OR t.paymentStat IS NULL) THEN SUM(CAST(isnull(d.rate*d.qty*(100-disc)/100, 0) AS INT))
ELSE 0
END AS 'OTHERS'
FROM tbparkDetail d
LEFT JOIN tbTranPark t ON d.tranCode = t.tranCode
JOIN tbsectorSection j ON t.strukPoli = j.struk
LEFT JOIN tbCustomer c WITH(NOLOCK) ON c.custCode=j.custCode
LEFT JOIN tbfrontDesk a WITH(NOLOCK) ON a.struckNo=j.struk
JOIN tbpaymentList cb ON a.paymentK = cb.paymentK
LEFT JOIN tbleading dc ON dc.leadCode=j.leadCode
LEFT JOIN tbsector p ON j.sectorCode=p.sectorCode
WHERE (j.deleted IS NULL
OR j.deleted=0)
AND (t.strukPoli IS NOT NULL
OR t.strukPoli <> ''
OR t.strukPoli <> '--')
AND a.status = 'FINISH'
AND (j.tranDate BETWEEN '2018-11-01 00:00:00' AND '2018-11-01 23:59:59')
GROUP BY cb.paymentGrp,
t.paymentStat
UNION ALL -- SECTOR FRONT
SELECT cb.paymentGrp AS 'cutomerSection',
CASE
WHEN t.paymentStat = 'DEBIT' THEN SUM(CAST(isnull(d.rate*(100-disc)/100, 0) AS INT))
ELSE 0
END AS 'DEBIT',
CASE
WHEN t.paymentStat = 'CREDIT' THEN SUM(CAST(isnull(d.rate*(100-disc)/100, 0) AS INT))
ELSE 0
END AS 'CREDIT',
CASE
WHEN (t.paymentStat = ''
OR t.paymentStat IS NULL) THEN SUM(CAST(isnull(d.rate*(100-disc)/100, 0) AS INT))
ELSE 0
END AS 'OTHERS'
FROM tbDetailRadioterapi d
LEFT JOIN tbtranFront t ON d.tranCode = t.tranCode
LEFT JOIN tbsectorSection j ON t.strukPoli = j.struk
LEFT JOIN tbCustomer c WITH(NOLOCK) ON c.custCode=j.custCode
LEFT JOIN tbfrontDesk a WITH(NOLOCK) ON a.struckNo = j.struk
LEFT JOIN tbpaymentList cb ON a.paymentK = cb.paymentK
LEFT JOIN tbleading dc ON dc.leadCode=j.leadCode
LEFT JOIN tbsector p ON j.sectorCode=p.sectorCode
WHERE (t.deleted IS NULL
OR t.deleted=0)
AND (strukPoli IS NOT NULL
OR strukPoli <>''
OR strukPoli <>'--')
AND a.status='FINISH'
AND (j.tranDate BETWEEN '2018-11-01 00:00:00' AND '2018-11-01 23:59:59')
GROUP BY cb.paymentGrp,
t.paymentStat) AS a
GROUP BY [cutomerSection]
Third using option (fast 500), I don't know why but always got error :
Incorect Syntax near OPTION
PS : Sorry for my bad English

How to sum up the cursor value and store the value in another select statement in the same procedure?

I have two tables, one is general table and another is loan table.
General table includes id and name and id is not repeating.
Loan table includes id and loan amount. In loan table, the id may be repeating as one customer can have multiple loans.
Idea is to create a procedure which will join this both the table on the basis of id and display the final table with id, name and sum of all loans for that particular id (must sum up the value of common id's and store in single column) with the help of cursor.
Can only use procedure and cursor.
If it can be solved without cursor, then please provide the alternate solution.
I am using below query for the same, but unfortunately the end result displays the id multiple times:
SELECT
A.bpm_referenceno,
CASE WHEN B.loanbookingbranch='--Select--' or B.loanbookingbranch='null' THEN '' ELSE B.loanbookingbranch END,
CASE WHEN A.branch='' OR A.branch IS NULL OR A.branch='null' THEN '' ELSE A.branch END,
'',
CASE WHEN A.originator='' OR A.originator IS NULL OR A.originator='null' THEN '' ELSE A.originator END,
A.cif_id,
CASE WHEN D.callexecutiondate='' OR D.callexecutiondate IS NULL OR D.callexecutiondate ='null' THEN '' ELSE CASE WHEN D.calldescription='MG Contract Creation' AND D.callstatus='SUCCESS' THEN D.callexecutiondate END END,
CASE WHEN A.originationdate IS NULL THEN '' ELSE A.originationdate END,
CASE WHEN A.request_type='' OR A.request_type IS NULL OR A.request_type='null' THEN '' ELSE A.request_type END,
CASE WHEN a.loan_subtype='' OR a.loan_subtype IS NULL OR a.loan_subtype='null' THEN '' ELSE a.loan_subtype END,
CASE WHEN E.loanamounttxndetails IS NULL OR E.loanamounttxndetails ='null' OR E.loanamounttxndetails='' THEN '0' ELSE e.loanamounttxndetails END,
CASE WHEN E.customerdbrtxndetails IS NULL OR E.customerdbrtxndetails ='null' OR E.customerdbrtxndetails='' THEN '0.00' ELSE E.customerdbrtxndetails END,
'stlment count',
'loan os',
--Here I am inserting the query--
(SELECT
isnull(ab.mycount,0)
FROM
bm_rlos_exttable aa
LEFT OUTER JOIN
(SELECT bpm_referenceno,count(bpm_referenceno) mycount FROM
BM_RLOS_ExistingBMLiabilitiesGrid GROUP BY bpm_referenceno) ab ON aa.bpm_referenceno = ab.bpm_referenceno),
CASE WHEN G.isselected='true' THEN G.insuranceType ELSE '' END,
CASE WHEN E.loantenortxndetails IS NULL OR E.loantenortxndetails='' OR E.loantenortxndetails='null' THEN '' ELSE E.loantenortxndetails END,
CASE WHEN E.interestratetxndetails IS NULL OR E.interestratetxndetails='' OR E.interestratetxndetails='null' THEN '' ELSE E.interestratetxndetails END,
'CHARGE1',
'CHARGE2',
CASE WHEN D.calldescription='MG Contract Creation' AND D.callstatus='SUCCESS' THEN D.callreferenceid ELSE '' END,
'rco',
'tat'
FROM
BM_RLOS_EXTTABLE A WITH (NOLOCK)
INNER JOIN BM_RLOS_BasicLoanDetailsForm B WITH (NOLOCK)
ON A.bpm_referenceno = B.bpm_referenceno
INNER JOIN BM_RLOS_DisbursementCallsGrid D WITH (NOLOCK)
ON A.bpm_referenceno = D.bpm_referenceno
INNER JOIN BM_RLOS_CheckFinalEligibilityForm E WITH (NOLOCK)
ON A.bpm_referenceno = E.bpm_referenceno
INNER JOIN BM_RLOS_ExistingBMLiabilitiesGrid F WITH (NOLOCK)
ON A.bpm_referenceno = F.bpm_referenceno
INNER JOIN BM_RLOS_InsuranceProductSelectionGrid G WITH (NOLOCK)
ON A.bpm_referenceno = G.bpm_referenceno
INNER JOIN BM_RLOS_ChargeAndFeeDetailsForm H WITH (NOLOCK)
ON A.bpm_referenceno = H.bpm_referenceno
INNER JOIN BM_RLOS_DecisionHistoryForm I WITH (NOLOCK)
ON A.bpm_referenceno = I.bpm_referenceno
INNER JOIN wfcurrentroutelogtable J WITH (NOLOCK)
ON A.bpm_referenceno = J.ProcessInstanceId
This should do the trick
SELECT
a.id,
a.name,
b.mysum
FROM
General_Table a
LEFT OUTER JOIN (select bpm_id, SUM(outstandingamount) mysum
from loan_table group by bpm_id) b
ON a.id = b.bpm_id
Edit: subquery changed ( based on your join clause i assumed your id field in the loan_table was bpm_id)
Edit2:
Note i moved your nested query into a new LEFT JOIN in order to make this work.
You cannot use nested query in a select statement if it returns more then 1 record
SELECT
A.bpm_referenceno,
CASE WHEN B.loanbookingbranch='--Select--' or B.loanbookingbranch='null' THEN '' ELSE B.loanbookingbranch END,
CASE WHEN A.branch='' OR A.branch IS NULL OR A.branch='null' THEN '' ELSE A.branch END,
'',
CASE WHEN A.originator='' OR A.originator IS NULL OR A.originator='null' THEN '' ELSE A.originator END,
A.cif_id,
CASE WHEN D.callexecutiondate='' OR D.callexecutiondate IS NULL OR D.callexecutiondate ='null' THEN '' ELSE CASE WHEN D.calldescription='MG Contract Creation' AND D.callstatus='SUCCESS' THEN D.callexecutiondate END END,
CASE WHEN A.originationdate IS NULL THEN '' ELSE A.originationdate END,
CASE WHEN A.request_type='' OR A.request_type IS NULL OR A.request_type='null' THEN '' ELSE A.request_type END,
CASE WHEN a.loan_subtype='' OR a.loan_subtype IS NULL OR a.loan_subtype='null' THEN '' ELSE a.loan_subtype END,
CASE WHEN E.loanamounttxndetails IS NULL OR E.loanamounttxndetails ='null' OR E.loanamounttxndetails='' THEN '0' ELSE e.loanamounttxndetails END,
CASE WHEN E.customerdbrtxndetails IS NULL OR E.customerdbrtxndetails ='null' OR E.customerdbrtxndetails='' THEN '0.00' ELSE E.customerdbrtxndetails END,
'stlment count',
'loan os',
--Here I am inserting the query--
mycount,
CASE WHEN G.isselected='true' THEN G.insuranceType ELSE '' END,
CASE WHEN E.loantenortxndetails IS NULL OR E.loantenortxndetails='' OR E.loantenortxndetails='null' THEN '' ELSE E.loantenortxndetails END,
CASE WHEN E.interestratetxndetails IS NULL OR E.interestratetxndetails='' OR E.interestratetxndetails='null' THEN '' ELSE E.interestratetxndetails END,
'CHARGE1',
'CHARGE2',
CASE WHEN D.calldescription='MG Contract Creation' AND D.callstatus='SUCCESS' THEN D.callreferenceid ELSE '' END,
'rco',
'tat'
FROM
BM_RLOS_EXTTABLE A WITH (NOLOCK)
INNER JOIN BM_RLOS_BasicLoanDetailsForm B WITH (NOLOCK)
ON A.bpm_referenceno = B.bpm_referenceno
INNER JOIN BM_RLOS_DisbursementCallsGrid D WITH (NOLOCK)
ON A.bpm_referenceno = D.bpm_referenceno
INNER JOIN BM_RLOS_CheckFinalEligibilityForm E WITH (NOLOCK)
ON A.bpm_referenceno = E.bpm_referenceno
INNER JOIN BM_RLOS_ExistingBMLiabilitiesGrid F WITH (NOLOCK)
ON A.bpm_referenceno = F.bpm_referenceno
INNER JOIN BM_RLOS_InsuranceProductSelectionGrid G WITH (NOLOCK)
ON A.bpm_referenceno = G.bpm_referenceno
INNER JOIN BM_RLOS_ChargeAndFeeDetailsForm H WITH (NOLOCK)
ON A.bpm_referenceno = H.bpm_referenceno
INNER JOIN BM_RLOS_DecisionHistoryForm I WITH (NOLOCK)
ON A.bpm_referenceno = I.bpm_referenceno
INNER JOIN wfcurrentroutelogtable J WITH (NOLOCK)
ON A.bpm_referenceno = J.ProcessInstanceId
left join
(SELECT bpm_referenceno,count(bpm_referenceno) mycount FROM
BM_RLOS_ExistingBMLiabilitiesGrid GROUP BY bpm_referenceno) ab ON ab.bpm_referenceno = a.bpm_referenceno)
You don't need cursor at all! It's inefficient. This can be done simply by JOINing and GROUPing. Try this query:
select g.id, l.totalLoan from GeneralTable [g]
join (
select id, sum(loan) [totalLoan] from LoanTable
group by id
) [l] on [g].id = [l].id