I was converting MySql to DB2 queries, and so far I got to this:
SELECT
loandata.*,
SUM(lc.amount_outstanding_derived) AS chargesDue
FROM
(
SELECT
cl.display_name AS clientName,
cl.id AS clientId,
ln.id AS loanId,
ln.account_no AS accountId,
ln.loan_status_id AS accountStatusId,
pl.short_name AS productShortName,
ln.product_id AS productId,
ln.currency_code AS currencyCode,
ln.currency_digits AS currencyDigits,
ln.currency_multiplesof AS inMultiplesOf,
rc.name AS currencyName,
rc.display_symbol AS currencyDisplaySymbol,
rc.internationalized_name_code AS currencyNameCode,
CASE WHEN ln.loan_status_id = 200 THEN ln.principal_amount
ELSE NULL
END AS disbursementAmount,
SUM(COALESCE((CASE WHEN ln.loan_status_id = 300 THEN ls.principal_amount ELSE 0.0 END), 0.0) - COALESCE(CASE WHEN ln.loan_status_id = 300 THEN ls.principal_completed_derived ELSE 0.0 END, 0.0)) AS principalDue,
ln.principal_repaid_derived AS principalPaid,
SUM(COALESCE(CASE WHEN ln.loan_status_id = 300 THEN ls.interest_amount ELSE 0.0 END, 0.0) - COALESCE(CASE WHEN ln.loan_status_id = 300 THEN ls.interest_completed_derived ELSE 0.0 END, 0.0)) AS interestDue,
ln.interest_repaid_derived AS interestPaid,
SUM(COALESCE(CASE WHEN ln.loan_status_id = 300 THEN ls.fee_charges_amount ELSE 0.0 END, 0.0) - COALESCE(CASE WHEN ln.loan_status_id = 300 THEN ls.fee_charges_completed_derived ELSE 0.0 END, 0.0)) AS feeDue,
ln.fee_charges_repaid_derived AS feePaid
FROM
m_loan LN
JOIN m_client cl ON
cl.id = ln.client_id
LEFT JOIN m_office OF ON
of.id = cl.office_id
AND of.hierarchy LIKE ?
LEFT JOIN m_product_loan pl ON
pl.id = ln.product_id
LEFT JOIN m_currency rc ON
rc.code = ln.currency_code
JOIN m_loan_repayment_schedule ls ON
ls.loan_id = ln.id
AND ls.completed_derived = 0
AND ls.duedate <= ?
WHERE
of.id = ?
AND (ln.loan_status_id = 300)
AND ln.group_id IS NULL
) AS loandata
LEFT JOIN m_loan_charge lc ON
lc.loan_id = loandata.loanId
AND lc.is_paid_derived = 0
AND lc.is_active = 1
AND ( lc.due_for_collection_as_of_date <= ?
OR lc.charge_time_enum = 1)
GROUP BY
loandata.clientId,
loandata.loanId
ORDER BY
loandata.clientId,
loandata.loanId
But I am getting an error :
SQL Error [42803]: An expression starting with "DISBURSEMENTAMOUNT"
specified in a SELECT clause, HAVING clause, or ORDER BY clause is not
specified in the GROUP BY clause or it is in a SELECT clause, HAVING
clause, or ORDER BY clause with a column function and no GROUP BY
clause is specified.. SQLCODE=-119, SQLSTATE=42803, DRIVER=4.26.14
I have tried inserting Group by and Order By clauses each for the select clause items like so:
SELECT
loandata.*,
SUM(lc.amount_outstanding_derived) AS chargesDue
FROM
(
SELECT
cl.display_name AS clientName,
cl.id AS clientId,
ln.id AS loanId,
ln.account_no AS accountId,
ln.loan_status_id AS accountStatusId,
pl.short_name AS productShortName,
ln.product_id AS productId,
ln.currency_code AS currencyCode,
ln.currency_digits AS currencyDigits,
ln.currency_multiplesof AS inMultiplesOf,
rc.name AS currencyName,
rc.display_symbol AS currencyDisplaySymbol,
rc.internationalized_name_code AS currencyNameCode,
CASE WHEN ln.loan_status_id = 200 THEN ln.principal_amount
ELSE NULL
END AS disbursementAmount,
SUM(COALESCE((CASE WHEN ln.loan_status_id = 300 THEN ls.principal_amount ELSE 0.0 END), 0.0) - COALESCE(CASE WHEN ln.loan_status_id = 300 THEN ls.principal_completed_derived ELSE 0.0 END, 0.0)) AS principalDue,
ln.principal_repaid_derived AS principalPaid,
SUM(COALESCE(CASE WHEN ln.loan_status_id = 300 THEN ls.interest_amount ELSE 0.0 END, 0.0) - COALESCE(CASE WHEN ln.loan_status_id = 300 THEN ls.interest_completed_derived ELSE 0.0 END, 0.0)) AS interestDue,
ln.interest_repaid_derived AS interestPaid,
SUM(COALESCE(CASE WHEN ln.loan_status_id = 300 THEN ls.fee_charges_amount ELSE 0.0 END, 0.0) - COALESCE(CASE WHEN ln.loan_status_id = 300 THEN ls.fee_charges_completed_derived ELSE 0.0 END, 0.0)) AS feeDue,
ln.fee_charges_repaid_derived AS feePaid
FROM
m_loan LN
JOIN m_client cl ON
cl.id = ln.client_id
LEFT JOIN m_office OF ON
of.id = cl.office_id
AND of.hierarchy LIKE ?
LEFT JOIN m_product_loan pl ON
pl.id = ln.product_id
LEFT JOIN m_currency rc ON
rc.code = ln.currency_code
JOIN m_loan_repayment_schedule ls ON
ls.loan_id = ln.id
AND ls.completed_derived = 0
AND ls.duedate <= ?
WHERE
of.id = ?
AND (ln.loan_status_id = 300)
AND ln.group_id IS NULL
GROUP BY
cl.display_name,
cl.id,
ln.id,
ln.account_no,
ln.loan_status_id,
pl.short_name,
ln.product_id,
ln.currency_code,
ln.currency_digits,
ln.currency_multiplesof,
rc.name,
rc.display_symbol,
rc.internationalized_name_code,
ln.loan_status_id,
ln.principal_amount,
ln.principal_repaid_derived,
ln.interest_repaid_derived,
ln.fee_charges_repaid_derived
ORDER BY
cl.display_name,
cl.id,
ln.id,
ln.account_no,
ln.loan_status_id,
pl.short_name,
ln.product_id,
ln.currency_code,
ln.currency_digits,
ln.currency_multiplesof,
rc.name,
rc.display_symbol,
rc.internationalized_name_code,
ln.loan_status_id,
ln.principal_amount,
ln.principal_repaid_derived,
ln.interest_repaid_derived,
ln.fee_charges_repaid_derived
) AS loandata
LEFT JOIN m_loan_charge lc ON
lc.loan_id = loandata.loanId
AND lc.is_paid_derived = 0
AND lc.is_active = 1
AND ( lc.due_for_collection_as_of_date <= ?
OR lc.charge_time_enum = 1)
GROUP BY
loandata.clientId,
loandata.loanId
ORDER BY
loandata.clientId,
loandata.loanId
A gross simplification of your query is:
SELECT loandata.*,
SUM(lc.amount_outstanding_derived) AS chargesDue
FROM (SELECT <lots of columns>
FROM <lots of tables>
. . .
) loandata LEFT JOIN
m_loan_charge lc
ON lc.loan_id = loandata.loanId AND
lc.is_paid_derived = 0 AND
lc.is_active = 1 AND
( lc.due_for_collection_as_of_date <= ? OR lc.charge_time_enum = 1)
GROUP BY loandata.clientId, loandata.loanId
ORDER BY loandata.clientId, loandata.loanId;
You have a SELECT * bringing in lots of columns. Fine. Then you have an aggregation function -- so the query is an aggregation query. Need a GROUP BY with lots of columns.
But I don't find one. I only find a GROUP BY with two columns. And that is an error in SQL. And happily, that is now an error in the more recent versions of MySQL. And in basically every other database.
You need to list all the columns in the GROUP BY that are not aggregated in the SELECT.
Related
QUESTION REWORDED
I had the following column definition in an SQL statement with its own GROUP BY...
SUM((SELECT a.CONT_TOT
FROM (SELECT gl2.VisitID, gl2.MessageID, gl2.BillOfLading, COUNT(gl2.ContainerID) AS CONT_TOT
FROM dbo.tblEDIGoodsLines AS gl2
WHERE gl2.VisitID = gl.VisitID AND gl2.MessageID = gl.MessageID AND gl2.BillOfLading = gl.BillOfLading
GROUP BY gl2.VisitID, gl2.MessageID, gl2.BillOfLading) AS a)) as TotalContainers,
...etc
And I continuously got this error.
Cannot perform an aggregate function on an expression containing an
aggregate or a subquery.
I am trying to get the TOTAL number of lines in the outside/bigger SELECT, and a total number of UNIQUE container counts in the TOTUCONT.
What am I doing wrong?
Here is the greater SQL query, to illustrate my point about GROUP BY and sub-queries in an aggregate function like SUM():
SELECT
gl.MessageID,
gl.BillOfLading,
gl.[Description],
CASE WHEN e.PortID = 9 THEN 'Export'
WHEN e.PortID = 11 THEN 'Import'
ELSE 'ERROR'
END AS Direction,
CASE WHEN ctypes.ID IS NOT NULL
THEN ctypes.ContainerSizeType
ELSE 'OTH'
END AS CSizeType,
ctypes.Length_ft + 'ft ' + ctypes.Height_ft + 'ft - ' + ctypes.Characteristics + ' (' + COALESCE(ctypes.Codes1995, ctypes.Codes1984) + ')' AS ContainerType,
COUNT(gl.ContainerID) AS TOTCONT,
SUM(a.CTOTAL) AS TOTUCONT
FROM tblEDIGoodsLines AS gl
INNER JOIN tblEDIEquipmentLines AS el
ON el.MessageID = gl.MessageID AND
el.ContainerID = gl.ContainerID
INNER JOIN tblEDI AS e
ON CHARINDEX(e.MessageID, gl.MessageID) > 0 AND
e.VisitID = gl.VisitID AND
CHARINDEX('EXCEL', e.MessageRelease) = 0 AND
e.Status = 1
LEFT JOIN tblContainerTypesISO6346 AS ctypes
ON ctypes.Codes1984 = el.SizeAndType OR
ctypes.Codes1995 = el.SizeAndType
LEFT JOIN (SELECT gl2.MessageID, gl2.VisitID, gl2.BillOfLading, gl2.description, COUNT(DISTINCT gl2.ContainerID) AS CTOTAL
FROM tblEDIGoodsLines AS gl2
WHERE gl2.MessageID = gl.MessageID
AND gl2.VisitID = gl.VisitID
and gl2.BillOfLading = gl.billoflading
and gl2.description = gl.description
GROUP BY gl2.MessageID, gl2.VisitID, gl2.BillOfLading, gl2.description) AS a
ON a.MessageID = gl.MessageID AND a.VisitID = gl.VisitID AND a.BillOfLading = gl.billoflading AND a.description = gl.description
WHERE gl.Status = 1
AND gl.VisitID = 22987
GROUP BY
gl.MessageID,
gl.BillOfLading,
gl.[Description],
CASE WHEN e.PortID = 9 THEN 'Export'
WHEN e.PortID = 11 THEN 'Import'
ELSE 'ERROR'
END,
CASE WHEN ctypes.ID IS NOT NULL
THEN ctypes.ContainerSizeType
ELSE 'OTH'
END,
ctypes.Length_ft + 'ft ' + ctypes.Height_ft + 'ft - ' + ctypes.Characteristics + ' (' + COALESCE(ctypes.Codes1995, ctypes.Codes1984) + ')'
The above does not work anyway, as I am trying to solve this by separating the "column" SELECT into it's own JOIN query, but now I get this:
The multi-part identifier "gl.MessageID" could not be bound.
So this implies, that the LEFT JOIN (SELECT...) is invalid?
Thanks again
UPDATE 2
Here is a data sample to explain further:
So you can see the outcome I want, TOTCONT to add up to '4'. That's easy - just count the number of rows, but TOTUCONT to count only the Container ID once.
Try refactoring the code to be more like this (as I commented earlier). It may also help with the other issues you are dealing with:
with cte_ctotal
as (
select gl2.MessageID,
gl2.VisitID,
gl2.BillOfLading,
gl2.description,
COUNT(distinct gl2.ContainerID) as CTOTAL
from tblEDIGoodsLines as gl2
group by gl2.MessageID,
gl2.VisitID,
gl2.BillOfLading,
gl2.description
),
cte_containers
as (
select
a.ContainerID,
gl.MessageID,
gl.VisitID,
gl.BillOfLading,
gl.Description,
case
when e.PortID = 9
then 'Export'
when e.PortID = 11
then 'Import'
else 'ERROR'
end as Direction,
case
when ctypes.ID is not null
then ctypes.ContainerSizeType
else 'OTH'
end as CSizeType,
ctypes.Length_ft + 'ft ' + ctypes.Height_ft + 'ft - ' + ctypes.Characteristics + ' (' + COALESCE(ctypes.Codes1995, ctypes.Codes1984) + ')' as ContainerType,
from tblEDIGoodsLines gl
inner join tblEDIEquipmentLines el on el.MessageID = gl.MessageID
and el.ContainerID = gl.ContainerID
inner join tblEDI e on CHARINDEX(e.MessageID, gl.MessageID) > 0
and e.VisitID = gl.VisitID
and CHARINDEX('EXCEL', e.MessageRelease) = 0
and e.status = 1
left join tblContainerTypesISO6346 ctypes on ctypes.Codes1984 = el.SizeAndType
or ctypes.Codes1995 = el.SizeAndType
where gl.status = 1
and gl.VisitID = 22987
)
select
c.MessageID,
c.BillOfLading,
c.Description,
c.Direction,
c.CSizeType,
c.ContainerType,
COUNT(c.ContainerID) as TOTCONT,
SUM(COALESCE(ct.CTOTAL,0)) as TOTUCONT
from cte_containers c
left join cte_ctotal ct on ct.MessageID = c.MessageID
and ct.VisitID = c.VisitID
and ct.BillOfLading = c.billoflading
and ct.description = c.description
group by c.MessageID,
c.BillOfLading,
c.Description,
c.Direction,
c.CSizeType,
c.ContainerType;
Try this,
(SELECT SUM(a.CONT_TOT)
FROM (SELECT gl2.VisitID, gl2.MessageID, gl2.BillOfLading, COUNT(gl2.ContainerID) AS CONT_TOT
FROM dbo.tblEDIGoodsLines AS gl2
WHERE gl2.VisitID = gl.VisitID AND gl2.MessageID = gl.MessageID AND gl2.BillOfLading = gl.BillOfLading
GROUP BY gl2.VisitID, gl2.MessageID, gl2.BillOfLading) AS a) as TotalContainers,
I think you can simplify this to:
(SELECT COUNT(gl2.ContainerID)
FROM dbo.tblEDIGoodsLines gl2
WHERE gl2.VisitID = gl.VisitID AND
gl2.MessageID = gl.MessageID AND
gl2.BillOfLading = gl.BillOfLading
) as TotalContainers,
Notes:
The outer SUM() is unnecessary. You can do the aggregation in the subqueries.
You do not need two levels of subqueries.
The GROUP BY is unnecessary. An aggregation query with no GROUP BY always returns exactly one row, which is what you want for a scalar subquery.
Depending on the rest of your query, this still might not work in your full query. If this is the case, then you should ask a new question, with sample data, desired results, and (a simplified version of) the query that does not work.
Change to this:
SUM(a.CONT_TOT) as TotalContainers
FROM (
SELECT COUNT(gl2.ContainerID) AS CONT_TOT
FROM dbo.tblEDIGoodsLines AS gl2
WHERE gl2.VisitID = gl.VisitID AND gl2.MessageID = gl.MessageID AND gl2.BillOfLading = gl.BillOfLading
GROUP BY gl2.VisitID, gl2.MessageID, gl2.BillOfLading
) AS a,
You may need to use parentheses at the end depending on the use of the code.
I removed additional columns from the SELECT list as they are not needed to get the SUM() (unless you need them for something else?).
Edit
Remove the WHERE clause from the last JOIN:
WHERE gl2.MessageID = gl.MessageID
AND gl2.VisitID = gl.VisitID
and gl2.BillOfLading = gl.billoflading
and gl2.description = gl.description
These conditions are applied in the ON clause.
I would like the results to produce a new row in each instance where a condition is met. I'm using a CASE statement but this isn't the way to go since once the first condition is met it stops evaluating the field.
SELECT
Reviews.ReviewID,
CASE
WHEN Score_CorrectID = 0 THEN 'Correct ID Right Party Authentication'
WHEN Score_ProperlyIdentified = 0 THEN 'PCA Properly Identified Itself'
WHEN Score_MiniMiranda = 0 THEN 'Mini-Miranda'
END AS [Error Type]
FROM Reviews INNER JOIN PCAs ON Reviews.PCAID = PCAs.PCAID LEFT JOIN
PCARebuttal ON Reviews.ReviewID = PCARebuttal.ReviewID
WHERE
(Score_CorrectID = 0 OR Score_ProperlyIdentified = 0 OR Score_MiniMiranda =
0)
This produces this:
I would like this:
Use apply:
SELECT r.ReviewID, v.error_type
FROM Reviews r INNER JOIN
PCAs
ON r.PCAID = PCAs.PCAID LEFT JOIN
PCARebuttal pr
ON r.ReviewID = pr.ReviewID OUTER APPLY
(SELECT *
FROM (VALUES (Score_CorrectID, 'Correct ID Right Party Authentication'),
(Score_ProperlyIdentified, 'PCA Properly Identified Itself'),
(Score_MiniMiranda, 'Mini-Miranda')
) v(score, error_type)
WHERE score = 0
) v
WHERE (Score_CorrectID = 0 OR Score_ProperlyIdentified = 0 OR Score_MiniMiranda = 0);
That said, I would probably just concatenate the values into a single column:
SELECT r.ReviewID,
( (CASE WHEN Score_CorrectID = 0 THEN 'Correct ID Right Party Authentication; ' ELSE '' END) +
(CASE WHEN Score_ProperlyIdentified = 0 THEN 'PCA Properly Identified Itself; ' ELSE '' END) +
(CASE WHEN Score_MiniMiranda = 0 THEN 'Mini-Miranda;' ELSE '' END)
) as error_types
FROM Reviews r INNER JOIN
PCAs
ON r.PCAID = PCAs.PCAID LEFT JOIN
PCARebuttal pr
ON r.ReviewID = pr.ReviewID OUTER APPLY
(SELECT *
FROM (VALUES ()
) v(score, error_type)
WHERE score = 0
) v
WHERE (Score_CorrectID = 0 OR Score_ProperlyIdentified = 0 OR Score_MiniMiranda = 0);
Instead of using case, you can use union all instead:
SELECT
Reviews.ReviewID,
'Correct ID Right Party Authentication' AS [Error Type]
FROM Reviews
INNER JOIN PCAs ON Reviews.PCAID = PCAs.PCAID
LEFT JOIN PCARebuttal ON Reviews.ReviewID = PCARebuttal.ReviewID
WHERE Score_CorrectID = 0
UNION ALL
SELECT
Reviews.ReviewID,
'PCA Properly Identified Itself' AS [Error Type]
FROM Reviews
INNER JOIN PCAs ON Reviews.PCAID = PCAs.PCAID
LEFT JOIN PCARebuttal ON Reviews.ReviewID = PCARebuttal.ReviewID
WHERE Score_ProperlyIdentified = 0
UNION ALL
SELECT
Reviews.ReviewID,
'Mini-Miranda' AS [Error Type]
FROM Reviews
INNER JOIN PCAs ON Reviews.PCAID = PCAs.PCAID
LEFT JOIN PCARebuttal ON Reviews.ReviewID = PCARebuttal.ReviewID
WHERE Score_MiniMiranda = 0
hi good people please find the code below is running in db2 but fails in oracle.
select * from
(select distinct e.time_stamp,e.applicationid, e.processname,
e.stage, e.initiatingsource, e.status, e.start_time, i.consultant,
g.cifnumber, g.applicantfirstname, g.applicantlastname,
case when e.branch is not null
then e.branch
else case when g.branch is not null
then g.branch
else i.branch
end
end as branch
from (select c.time_stamp, b.applicationid, b.processname,
b.stage, b.branch, b.initiatingsource,
case when d.status is null
then c.status
else d.status
end as status,
c.time_stamp as START_TIME,
case when d.time_stamp is not null
then d.time_stamp
else current_timestamp
ens as END_TIME
from (select distinct f.applicationid, f.branch, f.initiatingsource, f.processname,
case when f.stage in ('START''END')
then 'APPLICATION'
else f.stage, f.stagecounter
from processmetric f) b
left join processmetric c on b.applicationid = c.applicationid and b.processname = c.processname and (b.stage = c.stage or (b.stage = 'APPLICATION' and c.stage = 'START')) and b.stagecounter = c.stagecounter and c.phase = 'START'
left join processmetric d on b.applicationid = d.applicationid and b.processname = d.processname and (b.stage = d.stage or (b.stage = 'APPLICATION' and d.stage = 'END')) and b.stagecounter = d.stagecounter and d.phase ='END')e
left join applicationcustomerdata g on g.applicationid = e.applicationid
and g.time_stamp in (select max(x.time_stamp)
from applicationcustomerdata x
where x.applicationid = g.applicationid
)
left join applicationdata i on i.applicationid = e.applicationid
and i.time_stamp in (select max(z.time_stamp)
from applicationdata z
where z.applicationid = i.applicationid
)
order by e.start_time
) a
where a.start_time is not null and a.stage not in ('APPLICATION') and a.status not in ('COMPLETE' , 'COMPLETED' , 'CANCEL', 'FRAUD' , 'DECLINE') and a.stage = 'VERIFICATION';
Oracle don't allow to make outer join with subquery. Following 2 joins are problematic ones:
left join applicationcustomerdata g on g.applicationid = e.applicationid
and g.time_stamp in (select max(x.time_stamp)
from applicationcustomerdata x
where x.applicationid = g.applicationid
)
left join applicationdata i on i.applicationid = e.applicationid
and i.time_stamp in (select max(z.time_stamp)
from applicationdata z
where z.applicationid = i.applicationid
)
You need to rewrite statement (if you need this all in one SQL) or write some PL/SQL loops through data.
I have the following code.
It has 2 dates:
1.
(case
when not trunc(iv.dated) is null then trunc(iv.dated) else trunc(iv1.dated)
end) date_stock_received
2.
trunc(dh.actshpdate) SHIP_DATE
Is there a way to join the dates so they show in one column?
select unique li.catnr, li.av_part_no,
(select sum(pl.qty_onhand) from part_loc pl where li.av_part_no = pl.part_no) qty_onhand,
(case
when not trunc(iv.dated) is null then trunc(iv.dated) else trunc(iv1.dated)
end) date_stock_received,
(case
when not sum(iv.quantity) is null then sum(iv.quantity) else sum(iv1.quantity)
end) qty_received,
dp.delqty, od.ord_extordnr, trunc(dh.actshpdate) SHIP_DATE
from leos_item li
LEFT JOIN scm_packtyp sp
ON li.packtyp = sp.packtyp
LEFT JOIN invtran_view_oes iv
ON li.av_part_no = iv.part_no
and (iv.transaction = 'NREC' and iv.location_no = ' RETURNS W')
LEFT JOIN invtran_view_oes iv1
on li.av_part_no = iv1.part_no
and (iv1.transaction = 'CORR+' and iv1.remark like 'STOCK FROM SP PALLET%')
LEFT JOIN oes_delsegview od
ON od.catnr = li.catnr
and od.prodtyp = li.prodtyp
and od.packtyp = li.packtyp
LEFT JOIN oes_dpos dp
ON od.ordnr = dp.ordnr
and od.posnr = dp.posnr
and od.segnr = dp.segnr
LEFT JOIN oes_dhead dh
on dp.dheadnr = dh.dheadnr
and dh.shpfromloc = 'W'
where li.cunr = '816900'
and substr(li.catnr,1,5) in ('RGMCD','RGJCD')
and li.item_type = 'FP'
and li.catnr = 'RGJCD221'
group by li.catnr, li.av_part_no, iv.dated, iv.quantity, iv1.dated, iv1.quantity, dp.delqty,
dp.ordnr, dp.posnr, dp.segnr, od.ord_extordnr, dh.actshpdate
order by li.av_part_no
Current result is ...
... what I would like to see is ...
Is this possible ?
The coalesce function might be what you want.
select trunc(coalesce(iv.dated, iv1.dated, dh.actshpdate)) theDateYouMightWant
I am receiving this error when trying to execute the query below. Any ideas or suggestions?
Error:
Multiple columns are specified in an aggregated expression containing an outer reference. If an expression being aggregated contains an outer reference, then that outer reference must be the only column referenced in the expression.
SELECT TestInstances.pkTestInstanceID AS 'pkTestInstanceID',
bands.pkPerformanceLevelReportBandID AS 'BandID',
bands.StackPosition AS 'StackPosition',
(SELECT TOP 100 PERCENT SUM(CASE WHEN bands.StackPosition = b.StackPosition THEN 1 ELSE 0 END) * 100/ CASE WHEN COUNT(StudentScores_Subject.pkStudentScoreID) = 0 THEN 1 ELSE COUNT(StudentScores_Subject.pkStudentScoreID) END
FROM PerformanceLevelReportBands b
WHERE b.fkPerformanceLevelReportID = #intPerfLevelReportId
ORDER BY SUM(CASE WHEN bands.StackPosition = b.StackPosition THEN 1 ELSE 0 END) * 100/ CASE WHEN COUNT(StudentScores_Subject.pkStudentScoreID) = 0 THEN 1 ELSE COUNT(StudentScores_Subject.pkStudentScoreID) END) AS 'Percent',
COUNT(StudentScores_Subject.pkStudentScoreID) AS 'Count'
FROM StudentScores_Subject
INNER JOIN StudentTests ON StudentScores_Subject.fkStudentTestID = StudentTests.pkStudentTestID
INNER JOIN TestInstances ON TestInstances.pkTestInstanceID = StudentTests.fkTestInstanceID
INNER JOIN CAHSEE_TestPeriods ON CAHSEE_TestPeriods.pkTestPeriodID = TestInstances.fkTestPeriodID
INNER JOIN PerformanceLevelReportBands bands ON bands.fkPerformanceLevelReportID = #intPerfLevelReportId
LEFT JOIN MMARS_Web_TestInfo_California.dbo.PerfLevelReportBandCutScores cutScores ON cutScores.fkPerformanceLevelReportBandID = bands.pkPerformanceLevelReportBandID
AND cutScores.fkGradeID = #intGradeId
AND cutScores.fkTestSubjectID IN (SELECT id FROM #tempSubs)
INNER JOIN PerfLevelReportBandComponents bandComponents ON bandComponents.fkPerformanceLevelReportBandID = bands.pkPerformanceLevelReportBandID
AND((bandComponents.ScoreValue = StudentScores_Subject.ScoreValue) OR
((CAST(StudentScores_Subject.ScoreValue AS INT) BETWEEN bandComponents.minScore and bandComponents.maxScore)
OR
(CAST(StudentScores_Subject.ScoreValue AS INT) BETWEEN cutScores.minScore and cutScores.maxScore)))
RIGHT JOIN MM_SchoolYears ON MM_SchoolYears.pkSchoolYearID = TestInstances.fkSchoolYearID
WHERE MM_SchoolYears.pkSchoolYearID IN (SELECT number FROM itot(#strYearIds, N','))
AND StudentScores_Subject.fkStudentTestID IN (SELECT id FROM #tempTests)
AND StudentScores_Subject.fkScoreTypeID = bandComponents.fkScoreTypeID
AND StudentScores_Subject.fkTest_SubjectID IN (SELECT id FROM #tempSubs)
GROUP BY TestInstances.pkTestInstanceID, bands.pkPerformanceLevelReportBandID, bands.StackPosition
ORDER BY TestInstances.pkTestInstanceID, bands.pkPerformanceLevelReportBandID, bands.StackPosition
The problem is here you can't combine an outer and inner reference in an aggregate function
(SELECT TOP 100 PERCENT SUM(CASE WHEN bands.StackPosition = b.StackPosition THEN 1 ELSE 0 END) * 100/ CASE
WHEN COUNT(StudentScores_Subject.pkStudentScoreID) = 0 THEN 1
ELSE COUNT(StudentScores_Subject.pkStudentScoreID)
END
FROM PerformanceLevelReportBands b
WHERE b.fkPerformanceLevelReportID = #intPerfLevelReportId
ORDER BY SUM(CASE WHEN bands.StackPosition = b.StackPosition THEN 1 ELSE 0 END) * 100/ CASE
WHEN COUNT(StudentScores_Subject.pkStudentScoreID) = 0 THEN 1
ELSE COUNT(StudentScores_Subject.pkStudentScoreID)
END) AS 'Percent'
So change it to
(SELECT TOP 100 PERCENT SUM(CASE WHEN bb.StackPosition = b.StackPosition THEN 1 ELSE 0 END) * 100/ CASE
WHEN COUNT(StudentScores_Subject.pkStudentScoreID) = 0 THEN 1
ELSE COUNT(StudentScores_Subject.pkStudentScoreID)
END
FROM PerformanceLevelReportBands b JOIN PerformanceLevelReportBands bb
ON bb.fkPerformanceLevelReportID =bands.fkPerformanceLevelReportID
AND b.fkPerformanceLevelReportID =bb.fkPerformanceLevelReportID
WHERE b.fkPerformanceLevelReportID = #intPerfLevelReportId
ORDER BY SUM(CASE WHEN bb.StackPosition = b.StackPosition THEN 1 ELSE 0 END) * 100/ CASE
WHEN COUNT(StudentScores_Subject.pkStudentScoreID) = 0 THEN 1
ELSE COUNT(StudentScores_Subject.pkStudentScoreID)
END) AS 'Percent'
Here is a more thorough explanation.
I'd recommend commenting out bandComponents then cutScores, rerunning after removing each components and seeing where the query fails. Once you figure out where it's failing, then you can fix it.
Also, could be this line, the query in your Percent column.
ORDER BY SUM(CASE WHEN bands.StackPosition = b.StackPosition THEN 1 ELSE 0 END) * 100
I tried to organize your query a bit better to make it more legible.
SELECT
TestInstances.pkTestInstanceID AS 'pkTestInstanceID'
, bands.pkPerformanceLevelReportBandID AS 'BandID'
, bands.StackPosition AS 'StackPosition'
, (
SELECT TOP 100 PERCENT
SUM( CASE
WHEN bands.StackPosition = b.StackPosition
THEN 1
ELSE 0
END) * 100 /
CASE
WHEN COUNT(StudentScores_Subject.pkStudentScoreID) = 0
THEN 1
ELSE COUNT(StudentScores_Subject.pkStudentScoreID)
END
FROM PerformanceLevelReportBands b
WHERE b.fkPerformanceLevelReportID = #intPerfLevelReportId
ORDER BY SUM(CASE WHEN bands.StackPosition = b.StackPosition THEN 1 ELSE 0 END) * 100
/
CASE
WHEN COUNT(StudentScores_Subject.pkStudentScoreID) = 0
THEN 1
ELSE COUNT(StudentScores_Subject.pkStudentScoreID)
END
) AS 'Percent'
, COUNT(StudentScores_Subject.pkStudentScoreID) AS 'Count'
FROM
StudentScores_Subject
INNER JOIN
StudentTests ON
StudentScores_Subject.fkStudentTestID = StudentTests.pkStudentTestID
INNER JOIN
TestInstances ON
TestInstances.pkTestInstanceID = StudentTests.fkTestInstanceID
INNER JOIN
CAHSEE_TestPeriods ON
CAHSEE_TestPeriods.pkTestPeriodID = TestInstances.fkTestPeriodID
INNER JOIN
PerformanceLevelReportBands bands ON
bands.fkPerformanceLevelReportID = #intPerfLevelReportId
LEFT JOIN
MMARS_Web_TestInfo_California.dbo.PerfLevelReportBandCutScores cutScores ON
cutScores.fkPerformanceLevelReportBandID = bands.pkPerformanceLevelReportBandID
AND cutScores.fkGradeID = #intGradeId
AND cutScores.fkTestSubjectID IN (SELECT id FROM #tempSubs)
INNER JOIN
PerfLevelReportBandComponents bandComponents ON
bandComponents.fkPerformanceLevelReportBandID = bands.pkPerformanceLevelReportBandID
AND(
(bandComponents.ScoreValue = StudentScores_Subject.ScoreValue) OR
(
(CAST(StudentScores_Subject.ScoreValue AS INT) BETWEEN bandComponents.minScore and bandComponents.maxScore) OR
(CAST(StudentScores_Subject.ScoreValue AS INT) BETWEEN cutScores.minScore and cutScores.maxScore)
)
)
RIGHT JOIN
MM_SchoolYears ON
MM_SchoolYears.pkSchoolYearID = TestInstances.fkSchoolYearID
WHERE
MM_SchoolYears.pkSchoolYearID IN (SELECT number FROM itot(#strYearIds, N','))
AND StudentScores_Subject.fkStudentTestID IN (SELECT id FROM #tempTests)
AND StudentScores_Subject.fkScoreTypeID = bandComponents.fkScoreTypeID
AND StudentScores_Subject.fkTest_SubjectID IN (SELECT id FROM #tempSubs)
GROUP BY TestInstances.pkTestInstanceID, bands.pkPerformanceLevelReportBandID, bands.StackPosition
ORDER BY TestInstances.pkTestInstanceID, bands.pkPerformanceLevelReportBandID, bands.StackPosition
I faced the same problem or something similar.
I left here both the initial code and the resolution in case it helps you.
Initial code:
SELECT ISNULL((SELECT DateName(mm,DATEADD(mm,Perioada - 1,0))),'Nedefinit') as [Period],MAX(t.TipPerioada) AS TipPerioada,t.Perioada,MAX(t.An) AS An, a.NumePrenume, CAST(t.Volum as float) as ValTip,
ISNULL((Select Sum(v.Cantitate*p.VolumProdus)
From Wme_Vanzari as v
WHERE ('ND'='ND' or v.MarcaAgent = t.MarcaAgent) and t.[An]=v.AnFactura and t.Perioada=v.Lunafactura),0) as Realizat,
'' as Diferenta,'' as DiferentaWD,'' as Procent
FROM [Memo_Target] t
--Aduce Suma de Cantitate si MarcaAgent pentru a nu dubla cu liniile din Vanzari
LEFT JOIN (Select SUM(Cantitate) as Cantitate, MarcaAgent
From Wme_Vanzari
WHERE AnFactura = #An
GROUP BY MarcaAgent) v on t.MarcaAgent = v.MarcaAgent
LEFT JOIN WME_Agenti a on a.Marca = t.MarcaAgent
--Aduce Suma de VolumProdus, CodProdus si Marca Agent Filtrat dupa Anul dat in parametru, Volum necesar pt a calcula Realizat si a scade din targetul setat
LEFT JOIN (SELECT SUM(ISNULL(n.VolumProdus, 0)) AS VolumProdus, v.CodProdus, v.MarcaAgent
FROM Wme_NomenclatorProduse n
LEFT JOIN Wme_Vanzari v ON v.CodProdus = n.CodIntern
WHERE v.MarcaAgent IS NOT NULL AND v.CodProdus IS NOT NULL AND v.AnFactura = #An
GROUP BY v.CodProdus, v.MarcaAgent ) p ON p.MarcaAgent = t.MarcaAgent
WHERE (t.Volum IS NOT NULL AND t.Volum > 0)
AND t.An = #An
AND (CAST(t.Perioada AS INT) BETWEEN #lunastart AND #lunaend)
AND TipTarget = #tiptarget
AND (a.Marca IN (SELECT * FROM dbo.GetIdsTableString(#marcaAgent)) OR #marcaAgent = 'ND')
GROUP BY a.NumePrenume, t.Volum, Perioada,t.An
Error message was the same, and this is the resolution code:
SELECT ISNULL((SELECT DateName(mm,DATEADD(mm,Perioada - 1,0))),'Nedefinit') as [Period],MAX(t.TipPerioada) AS TipPerioada,t.Perioada,MAX(t.An) AS An, a.NumePrenume, CAST(t.Volum as float) as ValTip,
(ISNULL((Select Sum(p.VolumProdus)
From Wme_Vanzari as v
WHERE ('ND'='ND' or v.MarcaAgent = t.MarcaAgent) and t.[An]=v.AnFactura and t.Perioada=v.Lunafactura),0) * sum(v.Cantitate)) as Realizat,
'' as Diferenta,'' as DiferentaWD,'' as Procent
FROM [Memo_Target] t
--Aduce Suma de Cantitate si MarcaAgent pentru a nu dubla cu liniile din Vanzari
LEFT JOIN (Select SUM(Cantitate) as Cantitate, MarcaAgent
From Wme_Vanzari
WHERE AnFactura = #An
GROUP BY MarcaAgent) v on t.MarcaAgent = v.MarcaAgent
LEFT JOIN WME_Agenti a on a.Marca = t.MarcaAgent
--Aduce Suma de VolumProdus, CodProdus si Marca Agent Filtrat dupa Anul dat in parametru, Volum necesar pt a calcula Realizat si a scade din targetul setat
LEFT JOIN (SELECT SUM(ISNULL(n.VolumProdus, 0)) AS VolumProdus, v.CodProdus, v.MarcaAgent
FROM Wme_NomenclatorProduse n
LEFT JOIN Wme_Vanzari v ON v.CodProdus = n.CodIntern
WHERE v.MarcaAgent IS NOT NULL AND v.CodProdus IS NOT NULL AND v.AnFactura = #An
GROUP BY v.CodProdus, v.MarcaAgent ) p ON p.MarcaAgent = t.MarcaAgent
WHERE (t.Volum IS NOT NULL AND t.Volum > 0)
AND t.An = #An
AND (CAST(t.Perioada AS INT) BETWEEN #lunastart AND #lunaend)
AND TipTarget = #tiptarget
AND (a.Marca IN (SELECT * FROM dbo.GetIdsTableString(#marcaAgent)) OR #marcaAgent = 'ND')
GROUP BY a.NumePrenume, t.Volum, Perioada,t.An
As you can see, I chose to leave a single column in the first subselect and i was forced to use multiplication operation after this subselect.
I hope it helps!