SQL Server - WHERE clause with CASE - sql-server

ALTER PROCEDURE GetVendor_RMA_CreditMemo
(#HasCreditMemoNo INT)
BEGIN
SELECT
*
FROM
(SELECT
CreditMemoNumber,
CASE WHEN CreditMemoNumber != ''
THEN 1
ELSE 0
END AS HasCreditMemoNo
FROM
XYZ) as C
WHERE
(C.HasCreditMemoNo = #HasCreditMemoNo OR #HasCreditMemoNo = -1)
END
CreditMemoNumber is a varchar column
I want to achieve this:
CASE
WHEN #HasCreditMemoNo = 0
THEN -- select all rows with no value in CreditMemoNumber Column,
WHEN #HasCreditMemoNo = 1
THEN -- all rows that has some data,
WHEN #HasCreditMemoNo = -1
THEN -- everything regardless..

You can't do this kind of thing with a CASE.
The correct way to do it is with OR:
WHERE (#HasCreditMemoNo = 0 AND {no value in CreditMemoNumber Column})
OR
(#HasCreditMemoNo = 1 AND {all rows that has some data})
OR
(#HasCreditMemoNo = -1)

Would this work for you? I'm not sure if it would improve your performance. You may be better off writing an if else if else statement and three separate select statements with an index on the CreditMemoNumber column.
ALTER PROCEDURE GetVendor_RMA_CreditMemo(#HasCreditMemoNo int)
BEGIN
select
CreditMemoNumber,
case when CreditMemoNumber != '' then 1 else 0 end as HasCreditMemoNo
from XYZ
where
(#HasCreditMemoNo = 0 and (CreditMemoNumber is null or CreditMemoNumber = ''))
or (#HasCreditMemoNo = 1 and CreditMemoNumber != '')
or (#HasCreditMemoNo = -1)
END

Related

Visual Studio debugging stored procedure , focus on T-SQL CASE WHEN line by line

Discovering Visual Studio's ability to step debug on SQL stored procedures and UDF's I want to ask the following: is there any way to step debug between an inner query of a function (line by line) and specifically between a case when of a T-SQL, in order to be sure which one of all conditions is executed with a specific parameter of #Customercode ?
I know that 99% will be "no!" and I suppose that an answer to this would be "Remove the cases from the inner of the query and put them in terms of if ... then of the function... but it seems hard for me to believe that there is no way to do something like this even if an alternative method..
Sometimes you have to debug something that is already written in terms of CASE WHEN of the inner query..
The following is a very small example but what if the was a huge query ? There is no way to debug an SQL query line by line and get SQL's definitions of what is SQL doing with your statement ?
CREATE FUNCTION [dbo].[Fn_SalutSmallName]
(#CustomerCode varchar(50))
RETURNS varchar(100)
AS
BEGIN
DECLARE #res Varchar(100)
BEGIN
SELECT
#res = CASE
WHEN ESGOPERSON.PersonKind = 0 THEN 'Mr/Mrs'
WHEN ESGOPERSON.PersonKind = 1 AND ESGOPerson.SEX = 1
THEN 'Dear Mr ' + ISNULL(ESGOZCASES.Vocative, '')
WHEN ESGOPERSON.PersonKind = 1 AND ESGOPerson.SEX = 2
THEN 'Dear Mrs ' + ISNULL(ESGOZCASES.Vocative, '')
WHEN ESGOPERSON.PersonKind = 1 AND ESGOPerson.SEX = 0 AND ESGOPERSON.fTitleCode = 'Κος' AND ESGOZCASES.Vocative IS NULL
THEN 'Mr'
WHEN ESGOPERSON.PersonKind = 1 AND ESGOPerson.SEX = 0 AND ESGOPERSON.fTitleCode = 'Κα' AND ESGOZCASES.Vocative IS NULL
THEN 'Mrs'
WHEN ESGOPERSON.PersonKind = 1 AND ESGOPerson.SEX = 0 AND ESGOPERSON.fTitleCode = 'Κος' AND ESGOZCASES.Vocative IS NOT NULL
THEN 'Dear Mr ' + ISNULL(ESGOZCASES.Vocative, '')
WHEN ESGOPERSON.PersonKind = 1 AND ESGOPerson.SEX = 0 AND ESGOPERSON.fTitleCode = 'Κα' AND ESGOZCASES.Vocative IS NOT NULL
THEN 'Dear Mrs ' + ISNULL(ESGOZCASES.Vocative, '')
ELSE 'Dear'
END
FROM
ESFITradeAccount
LEFT OUTER JOIN
ESGOPerson ON ESFITradeAccount.fPersonCodeGID = ESGOPerson.GID
LEFT OUTER JOIN
ESGOZCases ON ESGOPerson.FirstName = ESGOZCASES.KeyID
AND ESGOPerson.Sex = ESGOZCases.Gender
WHERE
ESFITradeAccount.Code = #CustomerCode
AND ISNULL(ESGOZCases.KeyType, 1) = 1
RETURN #res
END
END

Is there any tool to convert stored procedure SQL to string with EscapeConcatenation?

I have over 50 stored procedures that I need to convert so that I can use a dynamic whereclause in them. My select statemement looks like this in SQL. I need to change this to a varchar(max) string and use Execute(#SQL) or sp_executesql #SQL
Is there any tool online or purchased that can convert this where clause into the proper string format with the correct escape sequences for the #Parameters?
;WITH TempResult AS(SELECT
DataDt
,EffDt
,SettlementDt
,BankId
,SeqNum
,DeleteFlag
,LoanNum
,BondLoanSaleType
,PurchaseProceedsAmt
,SettledPrinBal
,IntRecMiscAmt
,BuydownCashClearingAmt
,ARClearingDAPAmt
,ARCashClearingAmt
,ARSuspenseAmt
,ImpoundsSoldLoansAmt
,BondCommitmentFeesAmt
,SRPAmt
,OtherFeeAmt
,ActiveFlagBit = case ActiveFlagBit when 1 then 1 else 0 end
,UploadByCfcUserId
,UploadDtTm
,UploadedFileName
,ApprovedFlagBit = case ApprovedFlagBit when 1 then 1 else 0 end
,ApproveRejectByCfcUserId
,ApproveRejectDtTm
,ApprovalTaskId
,ArchiveDtTm
FROM guiUploadBondLoanSales u (nolock)
WHERE
(#LoanList.exist('/NewDataSet/Table1') = 0 or LoanNum in (select LoanNum from #tmpLoan))
and (#DataDtTo = '01/01/1900' or DataDt between #DataDtFrom and #DataDtTo)
and (#SettlementDtTo = '01/01/1900' or SettlementDt between #SettlementDtFrom and #SettlementDtTo)
and (#ShowOnlyLatest = 0 or (ActiveFlagBit = 1 and ApprovedFlagBit = 1 and u.DataDt =
(select max(DataDt) from guiUploadBondLoanSales u1 (nolock)
where u1.LoanNum = u.LoanNum and u1.ActiveFlagBit = 1 and u1.ApprovedFlagBit = 1)))
and (#TaskId = 0 or ApprovalTaskId = #TaskId)
and (#FileName = '' or UploadedFileName like '%' + #FileName + '%')
and (#UploadedByUsers.exist('/NewDataSet/Table1') = 0 or UploadByCfcUserId in (select UploadedByUsers from #UploadedByUsers))
and (#ApprovedByUsers.exist('/NewDataSet/Table1') = 0 or ApproveRejectByCfcUserId in (select ApprovedByUsers from #ApprovedByUsers))
and (#UploadDtTo = '01/01/1900' or UploadDtTm between #UploadDtFrom and #UploadDtTo)
and (#ApprovedDtTo = '01/01/1900' or ApproveRejectDtTm between #ApprovedDtFrom and #ApprovedDtTo)
and (#HideArchive = 0 or u.ArchiveDtTm = '1/1/1900' )
), TempCount AS ( SELECT COUNT(*) AS MaxRows FROM TempResult) SELECT *, TempCount.MaxRows FROM TempResult, TempCount ORDER BY TempResult.UploadDtTm OFFSET #OFFSET ROWS FETCH NEXT #FETCH ROWS ONLY OPTION(RECOMPILE)

TSQL IF THEN WHERE something ELSE WHERE something else

I need to transform this c# line into a SQL query:
from t in table where type == 0 ? t.colA=1 : t.ColB=1
I've tried something like
select * from table t where
BEGIN IF #type=0 THEN t.colA=1 END
BEGIN IF #type=1 THEN t.colB=1 END
but I get
Incorrect syntax near the keyword 'BEGIN'.
and
Incorrect syntax near the keyword 'THEN'.
What am I doing wrong? It is even possible to do this as a SQL command?
Just use boolean expressions:
select *
from table t
where (#type = 0 and t.colA = 1) or
(#type = 1 and t.colB = 1)
If you want everything when #type is not 0 or 1, then include:
select *
from table t
where (#type = 0 and t.colA = 1) or
(#type = 1 and t.colB = 1) or
(#type not in (0, 1)) -- adjust if #type could be NULL
You could use CASE:
select * from table t
where (CASE #type WHEN 0 THEN colA
WHEN 1 THEN colB
END) = 1
CASE is the "if" function in TSQL
https://learn.microsoft.com/en-us/sql/t-sql/language-elements/case-transact-sql?view=sql-server-2017

Add multiple in clauses depending if variable is blank or not (stored procedure) SQL Server

How am I able to get this to work I want it to add in clause if the value is not blank and not write the in clause if the value is blank. I have already tried with using OR and It runs but does not give me the results I want. I am using SQL Server 2008.
My variables are:
#orderNumber varchar(max),
#itemCode varchar(max),
#shipTo varchar(max),
#orderQty varchar(max),
#orderType varchar(max)
Now I took out a bunch of the stored procedure as it is a total of 600 lines but this should explain exactly what I want to do. I have searched high and low and have not found any solutions for this.
The query is:
SELECT
u.INVENTORY_ITEM_ID, u.ORDER_TYPE,
u.ORDER_QTY, u.ORDER_NUMBER,
u.SHIP_TO_NAME, u.ITEM_CODE AS SET_BOX,
ii.ITEM_CODE,
U.LANGUAGE_DESC
FROM
UnReleased_DeliveriesSet u
JOIN
SetDetails s ON u.item_code = s.SetCode
FULL OUTER JOIN
InventorySetBox i ON u.ITEM_CODE = i.ITEM_CODE
FULL OUTER JOIN
InventorySetBox ii ON ii.ITEM_CODE = s.ItemCode
FULL OUTER JOIN
SET_BOX_TYPE SB ON SB.ITEM_CODE = u.ITEM_CODE
WHERE
u.item_code LIKE '%.set%'
AND u.item_code NOT LIKE '%NN-%SET%'
AND ii.ITEM_CODE IS NOT NULL
AND ii.SUBINVENTORY_CODE <> 'BMS'
AND u.ITEM_CODE NOT IN ('inner query')
This is what I want to do:
AND
CASE WHEN #itemCode != ''
THEN u.ITEM_CODE IN (SELECT items FROM dbo.Split(#itemCode,','))
WHEN #orderType != ''
THEN u.ORDER_TYPE IN (SELECT items FROM dbo.Split(#orderType,','))
WHEN #orderQty != ''
THEN u.ORDER_QTY IN (SELECT items FROM dbo.Split(#orderQty, ','))
WHEN #orderNumber != ''
THEN u.ORDER_NUMBER IN (SELECT items FROM dbo.Split(#orderNumber, ','))
WHEN #shipTo != ''
THEN u.SHIP_TO_NAME in (SELECT items FROM dbo.Split(#shipTo, ','))
END
GROUP BY
u.INVENTORY_ITEM_ID, u.ITEM_CODE,
U.LANGUAGE_DESC,
i.item_box_quantity,
sb.BOX_TYPE, sb.set_box_qty,
ii.ITEM_CODE,
S.SetCode, RELEASED_STATUS,
u.ORDER_TYPE, u.ORDER_QTY, u.ORDER_NUMBER, u.SHIP_TO_NAME
and 1 = case
when #itemCode != '' then case
when u.ITEM_CODE in (SELECT items FROM dbo.Split(#itemCode,',')) then 1
else 0
end
when #orderType != '' then case
when u.ORDER_TYPE in (SELECT items FROM dbo.Split(#orderType,',')) then 1
else 0
end
when #orderQty != '' then case
when u.ORDER_QTY in (SELECT items FROM dbo.Split(#orderQty,',')) then 1
else 0
end
when #orderNumber != '' then case
when u.ORDER_NUMBER in (SELECT items FROM dbo.Split(#orderNumber,',')) then 1
else 0
end
when #shipTo != '' then case
when u.SHIP_TO_NAME in (SELECT items FROM dbo.Split(#shipTo,',')) then 1
else 0
end
else 0
end
A really hacky way using case expressions:
and 1 = case when #itemCode = '' or u.ITEM_CODE in (SELECT items FROM dbo.Split(#itemCode,',') s) then 1 else 0 end
and 1 = case when #orderType = '' or u.ORDER_TYPE in (SELECT items FROM dbo.Split(#orderType,',') s) then 1 else 0 end
and 1 = case when #orderQty = '' or u.ORDER_QTY in (SELECT items FROM dbo.Split(#orderQty,',') s) then 1 else 0 end
and 1 = case when #orderNumber = '' or u.ORDER_NUMBER in (SELECT items FROM dbo.Split(#orderNumber,',') s) then 1 else 0 end
and 1 = case when #shipTo = '' or u.SHIP_TO_NAME in (SELECT items FROM dbo.Split(#shipTo,',') s) then 1 else 0 end
A still rather hacky way using or
and (#itemCode = '' or u.ITEM_CODE in (SELECT items FROM dbo.Split(#itemCode,',') s))
and (#orderType = '' or u.ORDER_TYPE in (SELECT items FROM dbo.Split(#orderType,',') s))
and (#orderQty = '' or u.ORDER_QTY in (SELECT items FROM dbo.Split(#orderQty,',') s))
and (#orderNumber = '' or u.ORDER_NUMBER in (SELECT items FROM dbo.Split(#orderNumber,',') s))
and (#shipTo = '' or u.SHIP_TO_NAME in (SELECT items FROM dbo.Split(#shipTo,',') s))
A much better way would use dynamic sql to conditionally build your where statement and pass your parameters to sp_executesql
Reference:
An Updated "Kitchen Sink" Example - Aaron Bertand
Dynamic Search Conditions - Erland Sommarskog
Catch-all queries - Gail Shaw
Parameter Sniffing, Embedding, and the RECOMPILE Options - Paul White

SQL Server TSQL - How to achieve "NOT IN" statements within a CASE

I have the following working code:
INSERT INTO #resultado
SELECT 1,
v.idReqVoucher,
v.dtSolicitacao,
v.idFuncionario_solicitante,
v.idFuncionario_beneficiario,
v.idStatus,
NULL as valor
FROM reqVoucher v
WHERE
v.idReqVoucher =
CASE WHEN #idRequisicao = 0 THEN v.idReqVoucher
ELSE #idRequisicao END
AND v.idStatus =
CASE WHEN #status = 0 THEN v.idStatus
ELSE #status END
AND v.dtSolicitacao >= CASE WHEN #dtSolicitacaoIni IS NULL THEN v.dtSolicitacao ELSE #dtSolicitacaoIni END
AND v.dtSolicitacao <= CASE WHEN #dtSolicitacaoFim IS NULL THEN v.dtSolicitacao ELSE #dtSolicitacaoFim+' 23:59:59' END
But what I need to achieve is something like that:
AND v.idStatus
CASE WHEN #status = 99 THEN NOT IN (5,1,4,20)
ELSE WHEN #status != 0 THEN = #status END
And I have no idea on how achieve that in my code. I'm fairly new in TSQL and SQL Server, so please be gentle.
Or use a CASE expression:
and case
when #status = 99 and v.idStatus not in ( 5, 1, 4, 20 ) then 1
when #status !=0 and v.idStatus = #status then 1
else 0
end = 1
The CASE expression returns a value which you must then use, e.g. by comparing it to 1. It is generally good practice to include an ELSE clause to supply a default value should the unexpected arise.
The CASE statement returns a value, it does not act as an IF statement by changing the SQL query (if this, then do that). You would need to modify your where statement to something like the following:
AND (
(#status = 99 AND v.idStatus NOT IN (5, 1, 4, 20))
OR (#status NOT IN (0, 99) AND v.idStatus = #status)
)
Edit: Commenter is correct, the 2nd check needs to ensure the #status is not 99.
This should be equivalent to what you want:
AND (
(#status = 99) AND (v.idStatus NOT IN (5,1,4,20))
OR
(#status <> 99) AND (#status <> 0) AND (v.idStatus = #status)
)
CASE expression can only be used to return a scalar value, so it cannot be used to return a predicate like NOT IN (5,1,4,20).

Resources