How can I prevent a Lazy Spool from happening in my query? - sql

I been struggling to optimize this query,
SELECT
dbo.OE61BLIN.Order_Key
,dbo.OE61BLIN.Doc_Type
,dbo.OE61BHED.Doc__
,dbo.OE61BHED.Inv_Date
,dbo.OE61BHED.Cust__
,dbo.OE61BLIN.Line_Type
,dbo.OE61BLIN.Item__
,dbo.OE61BLIN.Description
,(CASE
WHEN dbo.OE61BLIN.Doc_Type = 'I' THEN dbo.OE61BLIN.Qty_Shipped * dbo.OE61BLIN.Unit_Factor
WHEN dbo.OE61BLIN.Doc_Type = 'C' AND
dbo.OE61BLIN.return_to_inventory_ = 1 THEN -dbo.OE61BLIN.Qty_Shipped * dbo.OE61BLIN.Unit_Factor
ELSE 0
END) AS QTY
,(CASE
WHEN dbo.OE61BLIN.Doc_Type = 'I' THEN dbo.OE61BLIN.Ext_Price
WHEN dbo.OE61BLIN.Doc_Type = 'C' THEN -dbo.OE61BLIN.Ext_Price
ELSE 0
END) * (CASE
WHEN ISNULL(dbo.OE61BHED.Inv_Disc__, 0) <> 0 THEN 1 - (dbo.OE61BHED.Inv_Disc__ / 100)
ELSE 1
END)
AS amount
,dbo.OE61BHED.Inv_Disc__
,dbo.OE61BLIN.ITEM_GROUP
,dbo.OE61BLIN.Category
,ISNULL(dbo.AR61ACST.intercompany, 0) AS intercompany
FROM dbo.OE61BHED
LEFT OUTER JOIN dbo.AR61ACST
ON dbo.OE61BHED.Cust__ = dbo.AR61ACST.Cust__
RIGHT OUTER JOIN dbo.OE61BLIN
ON dbo.OE61BHED.Order_Key = dbo.OE61BLIN.Order_Key
WHERE (dbo.OE61BLIN.Line_Type = 'R')
AND isnull(intercompany,0) != 1
AND (dbo.OE61BLIN.Doc_Type = 'C'
OR dbo.OE61BLIN.Doc_Type = 'I')
Complete estimated execution plan is here
https://www.brentozar.com/pastetheplan/?id=S1htt0rxN
Actual Exectuion Plan
https://www.brentozar.com/pastetheplan/?id=BymztxLgE
I use SQL Sentry Plan Explorer to optimaze it ,
and it suggested that I should add the following two indexes, which I have
But it doesnt improve much, It only removed RID Look Up from plan.
CREATE NONCLUSTERED INDEX [XI_LineTypeDocType_OE61BLIN_12172018]
ON [dbo].[OE61BLIN] ([Line_Type],[Doc_Type])
INCLUDE ([Order_Key],[Item__],[Description],[Category],[Return_to_Inventory_],[Unit_Factor],[Qty_Shipped],[Ext_Price],[ITEM_GROUP])
CREATE INDEX [XI_CustIntercompany_AR67ACST_12172018] ON [GarbageMark].[dbo].[AR61ACST]
([Cust__] ASC)
INCLUDE ([Intercompany])
I am completely stuck on how to aproach this problem.
I see that Lazy Spool is the most expensive operation but I dont know how to remove
or substitute.

Regrettably you don't prefix intercompany in the where clause with its table name so to some extent I'm guessing that the changes you see below. I am going to suggest that you re-arrange your query to avoid the use of right outer join and then, perhaps more importantly, place the intercompany <> 1 condition directly into the left join which
removes the use of ISNULL() from your where clause.
SELECT
dbo.OE61BLIN.Order_Key
, dbo.OE61BLIN.Doc_Type
, dbo.OE61BHED.Doc__
, dbo.OE61BHED.Inv_Date
, dbo.OE61BHED.Cust__
, dbo.OE61BLIN.Line_Type
, dbo.OE61BLIN.Item__
, dbo.OE61BLIN.Description
, (CASE
WHEN dbo.OE61BLIN.Doc_Type = 'I' THEN dbo.OE61BLIN.Qty_Shipped * dbo.OE61BLIN.Unit_Factor
WHEN dbo.OE61BLIN.Doc_Type = 'C' AND
dbo.OE61BLIN.return_to_inventory_ = 1 THEN -dbo.OE61BLIN.Qty_Shipped * dbo.OE61BLIN.Unit_Factor
ELSE 0
END) AS QTY
, (CASE
WHEN dbo.OE61BLIN.Doc_Type = 'I' THEN dbo.OE61BLIN.Ext_Price
WHEN dbo.OE61BLIN.Doc_Type = 'C' THEN -dbo.OE61BLIN.Ext_Price
ELSE 0
END) * (CASE
WHEN ISNULL( dbo.OE61BHED.Inv_Disc__, 0 ) <> 0 THEN 1 - (dbo.OE61BHED.Inv_Disc__ / 100)
ELSE 1
END)
AS amount
, dbo.OE61BHED.Inv_Disc__
, dbo.OE61BLIN.ITEM_GROUP
, dbo.OE61BLIN.Category
, ISNULL( dbo.AR61ACST.intercompany, 0 ) AS intercompany
FROM dbo.OE61BLIN
INNER JOIN dbo.OE61BHED ON dbo.OE61BLIN.Order_Key = dbo.OE61BHED.Order_Key
LEFT OUTER JOIN dbo.AR61ACST ON dbo.OE61BHED.Cust__ = dbo.AR61ACST.Cust__
AND dbo.AR61ACST.intercompany != 1
WHERE dbo.OE61BLIN.Line_Type = 'R'
AND dbo.OE61BLIN.Doc_Type IN ('C','I')
;
I believe the join between OE61BLIN and OE61BHED can be an inner join, if not try using a left join.

Related

SQL Server CASE using 2 different Tables

I am trying to use two different tables in a CASE statement but am really struggling. Most of my SQL knowledge is self taught so finding it a bit of a struggle!
The result I am trying to achieve is if TC.ClockingStatus WHEN 1 then '24' (1st Table) if not WHEN OP.Status WHEN 'C' THEN 99 WHEN 'I' THEN 50 ELSE 0 END (2nd Table) AS Status.
This is my current statement:
SELECT TOP (100) PERCENT
RTRIM(OP.Standard_Op) AS TaskDescription,
OP.Op_Number AS OpStep,
CAST(CAST(OP.Works_Order_Number AS DECIMAL(12, 2)) AS NVARCHAR(50)) AS OrderCode,
CASE OP.Status
WHEN 'C' THEN 99
WHEN 'I' THEN 50
ELSE 0
END AS Status,
CAST(OP.Op_Number AS varchar(50)) AS OpCode,
CAST(CAST(OP.Works_Order_Number AS decimal(12, 2)) AS nvarchar(50)) + '_' + CAST(OP.Op_Number AS nvarchar(50)) AS JobCode,
TC.ClockingStatus
FROM
dbo.PROGRESS AS OP
INNER JOIN
dbo.vOrcData_ActiveOperations AS AW ON AW.Works_Order = OP.Works_Order_Number
AND AW.Op_Number = OP.Op_Number
INNER JOIN
dbo.WOHEAD AS WH ON WH.Works_Order = OP.Works_Order_Number
INNER JOIN
dbo.RESOURCE AS RR ON RR.Resource_Code = OP.Original_Resource_Code
LEFT OUTER JOIN
dbo.Techman_WOCLOCK AS TC ON OP.Works_Order_Number = TC.OrderCode
AND OP.Op_Number = TC.OpStep
LEFT OUTER JOIN
dbo.MEMO_FIELDS_SQL ON dbo.MEMO_FIELDS_SQL.Memo_Unique = OP.Man_Memo_Unique
LEFT OUTER JOIN
(SELECT
Allocated_WO_Num, Sub_Con_Op_No,
MAX(Date_Promised) AS Date_Promised
FROM
dbo.PODETAIL AS PODETAIL_1
GROUP BY
Allocated_WO_Num, Sub_Con_Op_No) AS PODETAIL ON PODETAIL.Allocated_WO_Num = OP.Works_Order_Number
AND PODETAIL.Sub_Con_Op_No = OP.Op_Number
LEFT OUTER JOIN
(SELECT
Works_Order, Operation,
SUM(Operation_Time) AS TimeComplete
FROM
dbo.WOCLOCK
GROUP BY
Works_Order, Operation) AS CLOCKEDTIME ON WH.Works_Order = CLOCKEDTIME.Works_Order AND OP.Op_Number = CLOCKEDTIME.Operation
It's possible to use different columns/expressions in a case statement,
but you can't name the column before the first WHEN, like you do.
Try this:
CASE
WHEN TC.ClockingStatus = 1 THEN 24
WHEN OP.Status = 'C' THEN 99
WHEN OP.Status = 'I' THEN 50
ELSE 0 END
The expressions inside a WHEN test can be as complicated as you like. You can even nest CASE statements:
CASE
WHEN TC.ClockingStatus = 1 THEN 24
ELSE CASE OP.Status
WHEN 'C' THEN 99
WHEN 'I' THEN 50
ELSE 0
END
END
I think your problem is that you are trying to use the CASE form:
CASE <Field> WHEN <Value> THEN <Result>
What you need to use is the form:
CASE WHEN <Any condition no matter how complicated> THEN <Result>
Example:
CASE OP.Status WHEN 'C' THEN 99 ELSE 0 END
Can also be used as:
CASE WHEN OP.Status='C' THEN 99 ELSE 0 END

Multi Column CASE WHEN in Teradata

I'm trying to consolidate a few sub-queries to avoid hitting a massive table (42B rows) multiple times and getting
"[3771] Illegal Expression in WHEN clause of CASE expression."
,SUM(CASE
WHEN (oh.LOCN_NBR,oh.WK_NBR) IN (SELECT LOCN_NBR,START_WK FROM VT_STORES)
THEN oh.TTL_UN_QT
ELSE NULL
END) AS BEGINNING_OH
Is there any way to do multi-column IN statements within a CASE statement, or am I stuck putting these in the join/where in a subquery as it is currently?
Edit: Full Query as requested:
SELECT
oh.LOCN_NBR AS LOCN_NBR
,item.ITEM_ID AS ITEM_ID
,SUM(CASE
WHEN oh.WK_NBR = (SELECT WK_NBR FROM ALEX_ARP_VIEWS_PRD.REF_CUSTOM_TIME WHERE cust_time_id=2 )
THEN oh.TTL_UN_QT
ELSE NULL
END) AS SALEABLE_QTY
,SUM(CASE
WHEN oh.WK_NBR = (SELECT LY_WK_NBR FROM ALEX_ARP_VIEWS_PRD.REF_CUSTOM_TIME WHERE cust_time_id=2 )
THEN oh.TTL_UN_QT
ELSE NULL
END) AS SALEABLE_QTY_LY
,SUM(CASE
WHEN (oh.LOCN_NBR,oh.WK_NBR) IN (SELECT LOCN_NBR,PRI_START_WK FROM VT_STORES)
THEN oh.TTL_UN_QT
ELSE NULL
END) AS BEGINNING_OH_LY
,SUM(CASE
WHEN (oh.LOCN_NBR,oh.WK_NBR) IN (SELECT LOCN_NBR,START_WK FROM VT_STORES)
THEN oh.TTL_UN_QT
ELSE NULL
END) AS BEGINNING_OH
FROM
ALEX_ARP_VIEWS_PRD.FACT_WKLY_OPR_INS oh
INNER JOIN VT_STORES stores ON oh.LOCN_NBR = stores.LOCN_NBR
INNER JOIN VT_ITEM item ON oh.VEND_PACK_ID = item.VEND_PACK_ID
WHERE
INS_TYP_CD='H'
AND TTL_UN_QT <> 0
AND WK_NBR >= (SELECT MIN(PRI_START_WK) FROM VT_STORES)
GROUP BY
oh.LOCN_NBR
,item.ITEM_ID
You don't need to use IN. You can use exists:
SUM(CASE WHEN EXISTS (SELECT 1 FROM VT_STORES v WHERE oh.LOCN_NBR = v.LOCN_NBR AND oh.WK_NBR = v.START_WK)
THEN oh.TTL_UN_QT
END) AS BEGINNING_OH
However, I'm not 100% sure the problem is the IN. Many databases do not allow subqueries as arguments to aggregation functions. I'm not sure if Teradata allows this functionality.
I'm trying to consolidate a few sub-queries to avoid hitting a massive table multiple times
Multi-column Subqueries are only allowed in WHERE, but not in CASE. Rewriting to EXISTS will not probably not improve performance, the plan might actually be more complex.
You simply try hiding complexity, but it's still an Outer Join in the background, like this:
,Sum(CASE WHEN stores.LOCN_NBR IS NOT NULL THEN oh.TTL_UN_QT END) AS BEGINNING_OH
...
FROM oh LEFT JOIN
(
SELECT LOCN_NBR,START_WK FROM VT_STORES
) AS stores
ON stores.LOCN_NBR = oh.LOCN_NBR
AND stores.START_WK = oh.WK_NBR
Can you show your current query (at least those parts you try to optimize)?
Edit:
When VT_STORES.locn_nbr is unique this should return the same result:
SELECT
oh.LOCN_NBR AS LOCN_NBR
,item.ITEM_ID AS ITEM_ID
,Sum(CASE
WHEN oh.WK_NBR = (SELECT Min(WK_NBR) FROM ALEX_ARP_VIEWS_PRD.REF_CUSTOM_TIME WHERE cust_time_id=2 )
THEN oh.TTL_UN_QT
ELSE NULL
END) AS SALEABLE_QTY
,Sum(CASE
WHEN oh.WK_NBR = (SELECT Min(LY_WK_NBR) FROM ALEX_ARP_VIEWS_PRD.REF_CUSTOM_TIME WHERE cust_time_id=2 )
THEN oh.TTL_UN_QT
ELSE NULL
END) AS SALEABLE_QTY_LY
,Sum(CASE
WHEN oh.WK_NBR= stores.PRI_START_WK
THEN oh.TTL_UN_QT
END) AS BEGINNING_OH_LY
,Sum(CASE
WHEN oh.WK_NBR = stores.START_WK
THEN oh.TTL_UN_QT
END) AS BEGINNING_OH
FROM
ALEX_ARP_VIEWS_PRD.FACT_WKLY_OPR_INS oh
INNER JOIN VT_STORES stores ON oh.LOCN_NBR = stores.LOCN_NBR
INNER JOIN VT_ITEM item ON oh.VEND_PACK_ID = item.VEND_PACK_ID
WHERE
INS_TYP_CD='H'
AND TTL_UN_QT <> 0
AND WK_NBR >= (SELECT Min(PRI_START_WK) FROM VT_STORES)
GROUP BY
oh.LOCN_NBR
,item.ITEM_ID
The other Scalar Subqueries should be fine, because they return only a single row and the optimizer knows that.
re: Is there any way to do multi-column IN statements within a CASE statement
no.
re: to avoid hitting a massive table (42B rows) multiple times
which one is large? I don't see how, even if a compound IN clause worked, you would avoid hitting a large table multiple times compared to using a join/adding columns to a where clause.
have you tried something like:
SELECT
...
,SUM(CASE
WHEN SELECT COUNT(*) FROM VT_STORES
WHERE LOCN_NBR = oh.LOCN_NBR AND
PRI_START_WK = oh.WK_NBR > 1
THEN oh.TTL_UN_QT
END) AS BEGINNING_OH_LY
,SUM(CASE
WHEN SELECT COUNT(*) FROM VT_STORES
WHERE LOCN_NBR = oh.LOCN_NBR AND
START_WK = oh.WK_NBR > 1
THEN oh.TTL_UN_QT
END) AS BEGINNING_OH
FROM
...
?
If it's VT_STORES that's large, try:
ALEX_ARP_VIEWS_PRD.FACT_WKLY_OPR_INS oh INNER JOIN
(select
LOCN_NBR,
PRI_START_WK,
START_WK
from
VT_STORES) stores ON
oh.LOCN_NBR = stores.LOCN_NBR and
(PRI_START_WK = oh.WK_NBR OR
START_WK = oh.WK_NBR)
although I've seen performance hits from using OR clauses in joins, you might be better off with two inner joins, one for each week you want.

SQL - Improve pivot query performance

I am performing a pivot operation in my stored procedure as follows, but its affecting the performance as i am using it for the report.
Is there any way/ substitute to this pivot operation to improve the performance? or can i apply indexes for this?
SELECT colId,colSequence,colDescription,
ISNULL([1],0) AS 'IESO',ISNULL([2],0) AS 'RFRC',ISNULL([3],0) AS 'EAL',ISNULL([4],0) AS 'HNS',ISNULL([5],0) AS 'PTE',ISNULL([6],0) AS 'EOC',ISNULL([7],0) AS 'MU'
FROM
(
SELECT PF.FeatureId,PF.Sequence,PF.[Description],PTB.BenefitId,
FROM PSP.table1 PF
LEFT JOIN PSP.table2 PTB ON PF.FeatureId = PTB.FeatureId
left JOIN PSP.table3 PO ON PO.productID = PF.productId
WHERE PF.ProductId = #ProductId AND PF.IsDeleted = 0
) PS
PIVOT
(
MAX (BenefitId)
FOR BenefitId IN
( [1],[2],[3],[4],[5],[6],[7])
) AS pvt
ORDER BY colSequence
Your query use left JOIN PSP.table3 PO but this table don't show in SELECT field list of subquery.
If this table is unuseful, you can remove it, so you'll gain an operation.
Check the indexes on your query tables, but I suppose you have on FeatureId an index as on productID field
not sure if it's super beneficial, but instead of PIVOT you can use aggregate case expressions to get the values you need. you can use OUTER APPLY so you're not having to group by 3 columns, one being a description column.
SELECT colId = PF.FeatureId,
colSequence = PF.Sequence,
colDescription = PF.[Description],
PTB.*
FROM PSP.table1 PF
OUTER APPLY (
SELECT 'IESO' = COUNT(CASE WHEN BenefitId = 1 THEN 1 END),
'RFRC' = COUNT(CASE WHEN BenefitId = 2 THEN 1 END),
'EAL' = COUNT(CASE WHEN BenefitId = 3 THEN 1 END),
'HNS' = COUNT(CASE WHEN BenefitId = 4 THEN 1 END),
'PTE' = COUNT(CASE WHEN BenefitId = 5 THEN 1 END),
'EOC' = COUNT(CASE WHEN BenefitId = 6 THEN 1 END),
'MU' = COUNT(CASE WHEN BenefitId = 7 THEN 1 END)
FROM PSP.table2 PTB
WHERE PF.FeatureId = PTB.FeatureId
) PTB
WHERE PF.ProductId = #ProductId
AND PF.IsDeleted = 0

Error cannot generate SQL for Custom SQL at BO

I'm using business object 4 and currently developing a report using custom SQL. Total object and data type selected using custom sql and object at webbi already the same. But when I try to validate webbi always sends error cannot generate sql.
How to fix this and what is the cause of this error?
My sql syntax is as follows:
select * from(
SELECT
DISTINCT
CASE WHEN TRIM(msv26A.PROJECT_NO) IS NULL THEN msvPRJ.PROJECT_NO ELSE msv26A.PROJECT_NO END,
msv660.PROJ_DESC,
msv26A.PO_NO,
msv200.SUPPLIER_NAME,
msv26A.SUPPLIER_NO,
msv260.EXT_INV_NO,
msv200.SUP_TYPEX1,
msv260.CURRENCY_TYPE,
msv000_DC0001.DSTRCT_CODE,
msv000_DC0001.DSTRCT_NAME,
msv260.PMT_STATUS,
msv260.DUE_DATE,
msv260.INV_DATE,
msv260.FOR_INV_ORIG,
msv260.LOC_INV_ORIG,
msv260.FOR_INV_AMD,
msv260.LOC_INV_AMD,
msv260.AMT_RETAINED,
msv260.PRESC_PMT_AMT,
msv260.PP_AMT_LOC,
msv260_1.AMT_PAID_FOR,
msv071.REF_CODE,
CASE WHEN EMV260_AGING_RETENTION.LOC_INV_RETENTION IS NULL THEN 0 ELSE EMV260_AGING_RETENTION.LOC_INV_RETENTION END,
CASE WHEN EMV260_AGING_RETENTION.FOR_INV_RETENTION IS NULL THEN 0 ELSE EMV260_AGING_RETENTION.FOR_INV_RETENTION END
FROM
msv200 RIGHT OUTER JOIN msv26A ON (msv26A.SUPPLIER_NO = msv200.SUPPLIER_NO)
INNER JOIN msv000_DC0001 ON (msv000_DC0001.DSTRCT_CODE = msv26A.DSTRCT_CODE)
INNER JOIN msv260 ON (msv26A.DSTRCT_CODE = msv260.DSTRCT_CODE AND msv26A.SUPPLIER_NO = msv260.SUPPLIER_NO AND msv26A.INV_NO = msv260.INV_NO)
LEFT OUTER JOIN msvPRJ ON (msvPRJ.DSTRCT_CODE = msv26A.DSTRCT_CODE AND TRIM(msvPRJ.PO_NO) = trim(msv26A.PO_NO))
LEFT OUTER JOIN msv660 ON (msv26A.DSTRCT_CODE = msv660.DSTRCT_CODE AND (CASE WHEN TRIM(msv26A.PROJECT_NO) IS NULL
THEN msvPRJ.PROJECT_NO ELSE msv26A.PROJECT_NO END) = msv660.PROJECT_NO)
LEFT OUTER JOIN msv260 msv260_1 ON (msv260_1.DSTRCT_CODE = msv260.DSTRCT_CODE and msv260_1.SUPPLIER_NO = msv260.SUPPLIER_NO and msv260_1.INV_NO = msv260.INV_NO)
LEFT OUTER JOIN msv071 ON (msv071.ENTITY_VALUE=msv260.SUPPLIER_NO AND msv071.ENTITY_TYPE='SUP')
LEFT OUTER JOIN (SELECT A.DSTRCT_CODE,
A.SUPPLIER_NO,
A.ORIG_INV_NO,
SUM(CASE WHEN A.LOC_INV_AMD <> 0
THEN A.LOC_INV_AMD ELSE A.LOC_INV_ORIG END) LOC_INV_RETENTION,
SUM(CASE WHEN A.FOR_INV_AMD <> 0
THEN A.FOR_INV_AMD ELSE A.FOR_INV_ORIG END) FOR_INV_RETENTION
FROM msv260 A
WHERE A.FULL_PER_LOADED <= #prompt('Enter Full Period(From):','A','260\Full Per Loaded',Mono,Free,Persistent,,User :3)
AND TRIM(A.PMT_STATUS) >= '30' AND TRIM(A.PMT_STATUS) <= '55'
GROUP BY
A.DSTRCT_CODE,
A.SUPPLIER_NO,
A.ORIG_INV_NO) EMV260_AGING_RETENTION
ON (msv260.DSTRCT_CODE = EMV260_AGING_RETENTION.DSTRCT_CODE
AND msv260.SUPPLIER_NO = EMV260_AGING_RETENTION.SUPPLIER_NO
AND msv260.INV_NO = EMV260_AGING_RETENTION.ORIG_INV_NO)
WHERE
msv26A.DSTRCT_CODE in #prompt('Enter value(s) for Dstrct Code:','A','msv26a\Dstrct Code',Multi,Free,Persistent,,User:5)
AND
TRIM(msv260.PMT_STATUS) >= '30' AND TRIM(msv260.PMT_STATUS) <= '55'
AND
(
( msv260.FULL_PER_LOADED <= #prompt('Enter Full Period(From):','A','260\Full Per Loaded',Mono,Free,Persistent,,User :3)
AND msv260.FULL_PER_PAID = '000000' )
OR
( msv260.FULL_PER_PAID > #prompt('Enter Full Period(To):','A','260\Full Per Paid',Mono,Free,Persistent,,User :4)
AND msv260.FULL_PER_LOADED <= #prompt('Enter Full Period(From):','A','260\Full Per Loaded',Mono,Free,Persistent,,User :3) )
)
AND msv260.CURRENCY_TYPE <> ' '
ORDER BY msv000_DC0001.DSTRCT_CODE, msv260.SUPPLIER_NO, msv200.SUP_TYPEX1, msv260.CURRENCY_TYPE)
WHERE (DSTRCT_CODE,SUPPLIER_NO,EXT_INV_NO) IN (SELECT
DISTINCT DSTRCT_CODE,SUPPLIER_NO,EXT_INV_NO FROM msv900
WHERE DSTRCT_CODE in #prompt('Enter value(s) for Dstrct Code:','A','msv900\Dstrct Code',Multi,Free,Persistent,,User:1)
AND FULL_PERIOD <= #prompt('Enter Full Period(From):','A','msv900\Full Period',Mono,Free,Persistent,,User :2)
AND ACCOUNT_CODE IN ('21101')
)
ORDER BY
PROJECT_NO,
SUPPLIER_NO

Excel: Incorrect Syntax near the keyword 'SELECT'

Scenario: I am building a report in Excel to calculate commissions. This is based on Invoices from the previous month.
I created the following tsql query and created a connection using MSQuery. I tested the query and it works perfect until I change my Where statement to use the parameter "?" so I can , then I get the following error:
Incorrect Syntax near the keyword `'SELECT'`
Here is the query:
SELECT v_rpt_Invoices.Invoice_Number, v_rpt_Invoices.Territory, v_rpt_Company.Account_Nbr, v_rpt_Invoices.Company_Name, v_rpt_Invoices.Date_Invoice,
v_rpt_Invoices.Location, v_rpt_Invoices.TicketNbr, v_rpt_Invoices.Project_ID, v_rpt_Invoices.Invoice_Type, v_rpt_Invoices.Status_Description,
CASE WHEN TicketNbr <> 0 THEN 'Service Ticket' WHEN Project_ID IS NOT NULL THEN 'Project' ELSE 'Other' END AS Invoice_For,
CASE WHEN ticketNbr <> 0 THEN
(SELECT v_rpt_Service.Board_Name
FROM v_rpt_Service
WHERE v_rpt_Invoices.TicketNbr = v_rpt_Service.TicketNbr) WHEN Project_ID IS NOT NULL THEN Project_ID ELSE 'Other' END AS Service_Board_Project,
CASE WHEN TicketNbr <> 0 THEN
(SELECT Bill_Method
FROM SR_Service
WHERE v_rpt_Invoices.TicketNbr = SR_Service.SR_Service_RecID) WHEN project_id IS NOT NULL THEN
(SELECT PM_Billing_Method_ID
FROM PM_Project
WHERE v_rpt_Invoices.PM_Project_RecID = PM_Project.PM_Project_RecID) ELSE 'NONE' END AS BillingMethod, v_rpt_Invoices.Invoice_Amount,
CASE WHEN (TicketNbr <> 0 AND
(SELECT Bill_Method
FROM SR_Service
WHERE v_rpt_Invoices.TicketNbr = SR_Service.SR_Service_RecID) = 'A') THEN Invoice_Amount * 0.7 WHEN (TicketNbr <> 0 AND
(SELECT Bill_Method
FROM SR_Service
WHERE v_rpt_Invoices.TicketNbr = SR_Service.SR_Service_RecID) = 'F') THEN 0.01 WHEN (project_id IS NOT NULL AND
(SELECT PM_Billing_Method_ID
FROM PM_Project
WHERE v_rpt_Invoices.PM_Project_RecID = PM_Project.PM_Project_RecID) = 'A') THEN Invoice_Amount * 0.7 WHEN (project_id IS NOT NULL AND
(SELECT PM_Billing_Method_ID
FROM PM_Project
WHERE v_rpt_Invoices.PM_Project_RecID = PM_Project.PM_Project_RecID) = 'F') THEN 0.01 ELSE 0.00 END AS Cost
FROM v_rpt_Invoices INNER JOIN
v_rpt_Company ON v_rpt_Invoices.Company_RecID = v_rpt_Company.Company_RecID
**WHERE (v_rpt_Invoices.Date_Invoice >= ?)**
order by Territory, Invoice_For
Remove this line
**WHERE (v_rpt_Invoices.Date_Invoice >= ?)**
That is not valid SQL -- looks like you want to comment use double dash.
Unless you are just putting the ** to show what you changed. In that case you need to have a value where the ? is the SQL won't work.
As an asside, this query could be made much clearer and faster. Consider consolidating sub-queries into a join. For example, the following sub-query
SELECT Bill_Method
FROM SR_Service
WHERE v_rpt_Invoices.TicketNbr = SR_Service.SR_Service_RecID
MUST be called for every row -- if you make this a join you go from O(nm) to O(n+m) Where n is the size of v_rpt_Invoices and m is the size of SR_Service.
This is just one of the potential sub-queries you can optimize.
Here is an example of rolling in the sub-queries to your example
(I can't test so it might have bugs / typos)
SELECT
v_rpt_Invoices.Invoice_Number,
v_rpt_Invoices.Territory,
v_rpt_Company.Account_Nbr,
v_rpt_Invoices.Company_Name,
v_rpt_Invoices.Date_Invoice,
v_rpt_Invoices.Location,
v_rpt_Invoices.TicketNbr,
v_rpt_Invoices.Project_ID,
v_rpt_Invoices.Invoice_Type,
v_rpt_Invoices.Status_Description,
CASE WHEN TicketNbr <> 0 THEN 'Service Ticket'
WHEN Project_ID IS NOT NULL THEN 'Project'
ELSE 'Other'
END AS Invoice_For,
CASE WHEN ticketNbr <> 0 THEN v_rpt_Service.Board_Name
WHEN Project_ID IS NOT NULL THEN Project_ID
ELSE 'Other'
END AS Service_Board_Project,
CASE WHEN TicketNbr <> 0 THEN SR_Service.Bill_Method
WHEN project_id IS NOT NULL THEN PM_Project.PM_Billing_Method_ID
ELSE 'NONE'
END AS BillingMethod, v_rpt_Invoices.Invoice_Amount,
CASE WHEN (TicketNbr <> 0 AND SR_Service.Bill_Method ='A') THEN Invoice_Amount * 0.7
WHEN (TicketNbr <> 0 AND SR_Service.Bill_Method ='F') THEN 0.01
WHEN (project_id IS NOT NULL AND PM_Project.PM_Billing_Method_ID = 'A') THEN Invoice_Amount * 0.7
WHEN (project_id IS NOT NULL AND PM_Project.PM_Billing_Method_ID = 'F') THEN 0.01
ELSE 0.00
END AS Cost
FROM v_rpt_Invoices
INNER JOIN v_rpt_Company ON v_rpt_Invoices.Company_RecID = v_rpt_Company.Company_RecID
LEFT JOIN SR_Service ON v_rpt_Invoices.TicketNbr = SR_Service.SR_Service_RecID
LEFT JOIN PM_Project ON v_rpt_Invoices.PM_Project_RecID = PM_Project.PM_Project_RecID
LEFT JOIN v_rpt_Service ON v_rpt_Invoices.TicketNbr = v_rpt_Service.TicketNbr
WHERE (v_rpt_Invoices.Date_Invoice >= '1/1/2013')
order by Territory, Invoice_For