Parameters in Pivot - sql

I have a task to send a list of cost-centers(varchar) to the query and the query should provide data based on each input.
I have no understanding of dynamic SQL.
So I have a list of cost centers like 88115100, 88115200, 88115300......around 30.
declare #month integer
declare #month_2 integer
declare #startdate datetime
declare #enddate datetime
declare #costcenter varchar(20)
set #month_2= 3--/* t3.finncPriod=*/ '[%0]'
set #month=#month_2-1
set #costcenter='88115100'
set #startdate= '03/01/2019'--/*t0.docdate from oinm t0 where t0.docdate>=*/'[%1]'
set #enddate= '03/31/2019'--/*t0.docdate from oinm t0 where t0.docdate>=*/'[%2]'
select * from
(
select
t0.name+'-Budget' as 'toPivot',
t4.AcctCode as 'GLAccount',
t4.AcctName,
isnull(t2.DebLTotal,0) as 'value'
from obgs as t0
inner join obgt as t1 on t0.AbsId = t1.Instance
inner join bgt1 as t2
on t2.Instance = t1.Instance
and t2.AcctCode = t1.AcctCode
and t2.Line_ID = #month
inner join oact as t4 on t4.AcctCode = t2.AcctCode
where t0.name = #costcenter
union all
select
t0.name + '-Actual'as 't0Pivot',
t4.AcctCode as 'GLAccount',
t4.AcctName,
isnull(sum(debit-credit),0) as 'value'
from jdt1 as t3
left join oact t4 on t4.AcctCode = t3.Account
left join obgs t0 on t0.Name = t3.ProfitCode
left join obgt t1
on t1.Instance = t0.AbsId
and t4.AcctCode = t1.AcctCode
left join bgt1 as t2
on t1.Instance = t2.Instance
and t2.AcctCode = t1.AcctCode
and t2.line_ID = 2
where
t3.refdate between #startdate and #enddate
and t4.ExportCode is not null
and t0.name = #costcenter
group by
t0.name,
t4.AcctCode,
t4.AcctName
) as a
pivot
(
sum(a.value)
for a.topivot in
([88115100-Budget], [88115100-Actual])
)
as pivottable

Ok, so from what I can tell you probably want a stored procedure, and you're suggesting that it could/should be dynamic SQL. Now, you could do that, but the only time you need dynamic SQL is when you have to rewrite keywords depending on variables. You would have to do that with your code above - specifically the following bit:
pivot
(
sum(a.value)
for a.topivot in
([88115100-Budget], [88115100-Actual])
)
This is because [88115100-Budget] and [88115100-Actual] are keywords which depend on your variable (#costcenter). But there's no reason for them to be named like that in SQL! You're much better applying those names later, in whatever it is that you're sending this data to outside of SQL.
Instead, you probably want something like the following code:
CREATE PROCEDURE GetBudgetForCostCenter
#month integer = 2,
#month_2 integer = 3,
#startdate datetime = '03/01/2019',
#enddate datetime = '03/31/2019',
#costcenter varchar(20) = '88115100'
--you probably don't actually want the default values in here, but I've left them for demonstration.
AS
BEGIN
select * from
(
select
'Budget' as 'toPivot',
t4.AcctCode as 'GLAccount',
t4.AcctName,
isnull(t2.DebLTotal,0) as 'value'
from obgs as t0
inner join obgt as t1 on t0.AbsId = t1.Instance
inner join bgt1 as t2
on t2.Instance = t1.Instance
and t2.AcctCode = t1.AcctCode
and t2.Line_ID = #month
inner join oact as t4 on t4.AcctCode = t2.AcctCode
where t0.name = #costcenter
union all
select
'Actual'as 't0Pivot',
t4.AcctCode as 'GLAccount',
t4.AcctName,
isnull(sum(debit-credit),0) as 'value'
from jdt1 as t3
left join oact t4 on t4.AcctCode = t3.Account
left join obgs t0 on t0.Name = t3.ProfitCode
left join obgt t1
on t1.Instance = t0.AbsId
and t4.AcctCode = t1.AcctCode
left join bgt1 as t2
on t1.Instance = t2.Instance
and t2.AcctCode = t1.AcctCode
and t2.line_ID = 2
where
t3.refdate between #startdate and #enddate
and t4.ExportCode is not null
and t0.name = #costcenter
group by
t0.name,
t4.AcctCode,
t4.AcctName
) as a
pivot
(
sum(a.value)
for a.topivot in
([Budget], [Actual])
)
as pivottable
END
Note that I've changed your columns from 88115100-Budget and 88115100-Actual to just be Budget and Actual. This means that you can avoid using dynamic SQL which is something you should always aim to do.
This should now be able to be called via something like
exec GetBudgetForCostCenter #month = 2, #month_2 = 3, #startdate = '03/01/2019', #enddate = '03/31/2019', #costcenter = '88115100'
Disclaimer: I can't be bothered testing the syntax more than with the built-in syntax highlighting as it would require creating a new database and a lot of new objects, so sorry if there's any typos in there.

Related

Receiving duplicates in T SQL Query with Case Statement

I have created the following case statement to do some multiplication depending on the items sales unit of measure and for this example, even though I am declaring the SalesUoM Variable as Gallon, it is doing the math for both the gallons and the lbs.
declare #SalesUOM as nvarchar(30)
declare #drumqty as nvarchar(30)
Set #SalesUOM = 'GAL'
Set #drumqty = '3'
SELECT DISTINCT
Case
--- when #SalesUOM = 'DRUM' then ( #drumqty * T1.BaseQty )
-- when #SalesUOM = 'PALLET' then ( #drumqty * T4.BaseQty )
--when #SalesUOM = 'PAIL' then ( #drumqty * T6.BaseQty )
--when #SalesUOM = 'TOTE' then ( #drumqty * T8.BaseQty )
when #SalesUOM = 'LB' then ( #drumqty * T10.BaseQty )
When #SalesUOM = 'GAL' then (#drumQty * T12.BaseQty)
Else '0' End as 'Item Qty'
FROM OUGP T0
--INNER JOIN UGP1 T1 ON T0.[UgpEntry] = T1.[UgpEntry]
--INNER JOIN UGP1 T4 on T0.[UgpEntry] = T4.[UgpEntry]
--INNER JOIN UGP1 T6 on T0.[UgpEntry] = T6.[UgpEntry]
--INNER JOIN UGP1 T8 on T0.UgpEntry = T8.UgpEntry
inner JOIN UGP1 T10 on T0.UgpEntry = T10.UgpEntry
inner JOIN UGP1 T12 on T0.UgpEntry = T12.UgpEntry
--INNER JOIN OUOM T2 ON T0.[BaseUom] = T2.[UomEntry]
--Inner Join OUOM T3 on T1.[UomEntry] = T3.[UomEntry] AND T3.UOMCODE in ('DR-15', 'DR-30', 'DR-55')
--Inner Join OUOM T5 on T4.[UomEntry] = T5.[UomEntry] and T5.UOMCODE = 'PALLET'
--left Join OUOM T7 on T6.UoMEntry = T7.UomEntry and T7.UOMCODE = 'PAIL-5'
--left Join OUOM T9 on T8.UomEntry = T9.UomEntry AND T9.UomCode = 'TOTE'
Left Join OUOM T11 on T10.UomEntry = T11.UomEntry and T11.UomCode = 'LB'
Left Join OUOM T13 on T12.UomEntry = T13.UomEntry and T13.UomCode = 'GAL'
Left join OITM on T0.UgpCode = OITM.ItemCode
WHERE
OITM.ItemCode = '0000000'
because you are not filtering the result set on #SalesUOM in where clause or inner join.
T10 and T12 are pointing to the same table UGP1.
below are two ways that can resolve your problem
1. Add T11.UomCode = #SalesUOM And T13.UomCode = #SalesUOM in where clause
2. Replace below Statements
"Left Join OUOM T11 on T10.UomEntry = T11.UomEntry and T11.UomCode = 'LB'
Left Join OUOM T13 on T12.UomEntry = T13.UomEntry and T13.UomCode = 'GAL'"
with below statements
Inner Join OUOM T11 on T10.UomEntry = T11.UomEntry and T11.UomCode = #SalesUOM

Query is working fine in second execution but taking too much time in first execution

I am writing a query which is accepting a comma separated string and calculating the sum of transaction. which is working fine as result wise but taking too much time to execute in first attempt. I understand its need tuning but didn't find out the exact reason can any one point me whats wrong with my query.
Declare #IDs nvarchar(max)='1,4,5,6,8,9,43,183'
SELECT isnull(isnull(SUM(FT.PaidAmt),0) - isnull(SUM(CT.PaidAmt),0),0) [Amount], convert(char(10),FT.TranDate,126) [Date]
from FeeTransaction FT
Inner Join (
Select max(P.Id) [Id], P.TranMainId, isnull(SUM(P.AmtToPay),0) [Amt]
From Patient_Account P
Group By P.TranMainId
) PA ON FT.Id = PA.TranMainId
Inner Join Patient_Account XP ON PA.Id = XP.Id
Inner Join Master_Fee MF ON XP.FeeId = MF.Id
INNER Join Master_Patient MP ON FT.PID = MP.Id
Inner Join Master_FeeType TY ON MF.FeeTypeId = TY.Id
Left JOIN FeeTransaction CT on FT.TransactionId = CT.TransactionId AND CT.TranDate between '2019'+'08'+'01' and '2019'+'08'+'31' and CT.[Status] <> 'A' AND isnull(CT.IsCancel,0) = 1
Where convert(nvarchar,FT.TranDate,112) between '2019'+'08'+'01' and '2019'+'08'+'31' AND FT.[Status] = 'A' AND XP.FeeId in (SELECT val FROM dbo.f_split(#IDs, ','))
AND isnull(FT.IsCancel,0) = 0 AND FT.EntryBy = 'rajan'
Group By convert(char(10),FT.TranDate,126)
I would rephrase the query a bit:
select coalesce(SUM(FT.PaidAmt), 0) - coalesce(SUM(CT.PaidAmt), 0)as [Amount],
convert(char(10),FT.TranDate,126) [Date]
from FeeTransaction FT join
(select xp.*,
coalesce(sum(p.amttopay) over (TranMainId), 0) as amt
from Patient_Account XP ON PA.Id = XP.Id
) xp join
Master_Fee MF
on XP.FeeId = MF.Id join
Master_Patient MP
on FT.PID = MP.Id join
Master_FeeType TY
on MF.FeeTypeId = TY.Id left join
FeeTransaction CT
on FT.TransactionId = CT.TransactionId and
CT.TranDate between '20190801' and '20190831' and
CT.[Status] <> 'A' and
CT.IsCanel = 1
where FT.TranDate >= '20190801' and and
FT.TranDate < '20190901'
FT.[Status] = 'A' AND
XP.FeeId in (SELECT val FROM dbo.f_split(#IDs, ',')) and
(FT.IsCancel = 0 or FT.IsCancel IS NULL) and
FT.EntryBy = 'rajan'
Group By convert(char(10), FT.TranDate, 126)
Then for this version, you specifically an index on FeeTransaction(EntryBy, Status, TranDate, Cancel).
Note the following changes:
You do not need to aggregate Patient_Account as a subquery. Window functions are quite convenient.
Your date comparisons preclude the use of indexes. Converting dates to strings is a bad practice in general.
You have over-used isnull().
I assume that the appropriate indexes are in place for the joins.
I would use STRING_SPLIT and Common Table Expressions and do away with date conversions:
Declare #IDs nvarchar(max)='1,4,5,6,8,9,43,183'
;WITH CTE_ID AS
(
SELECT value AS ID FROM STRING_SPLIT(#IDs, ',');)
),
MaxPatient
AS
(
SELECT MAX(P.Id) [Id], P.TranMainId, isnull(SUM(P.AmtToPay),0) [Amt]
From Patient_Account P
Group By P.TranMainId
)
SELECT isnull(isnull(SUM(FT.PaidAmt),0) - isnull(SUM(CT.PaidAmt),0),0) As [Amount],
convert(char(10),FT.TranDate,126) [Date]
FROM FeeTransaction FT
INNER JOIN MaxPatient PA
ON FT.Id = PA.TranMainId
INNER JOIN Patient_Account XP
ON PA.Id = XP.Id
INNER JOIN Master_Fee MF
ON XP.FeeId = MF.Id
INNER Join Master_Patient MP
ON FT.PID = MP.Id
INNER JOIN Master_FeeType TY
ON MF.FeeTypeId = TY.Id
INNER JOIN CTE_ID
ON XP.FeeId = CTE_ID.ID
LEFT JOIN FeeTransaction CT
ON FT.TransactionId = CT.TransactionId AND
CT.TranDate >= '20190801' AND CT.TranDate < '20190831' AND
CT.[Status] <> 'A' AND isnull(CT.IsCancel,0) = 1
WHERE FT.TranDate >= '20190801' and FT.TranDate < '20190831' AND
FT.[Status] = 'A' AND
ISNULL(FT.IsCancel,0) = 0 AND
FT.EntryBy = 'rajan'
GROUP BY CAST(FT.TranDate AS Date)
Not only is your query slow, but it appear that it is giving incorrect output.
i) When you are not using any column of Patient_Account in your resultset then why are you writing this sub query?
Select max(P.Id) [Id], P.TranMainId, isnull(SUM(P.AmtToPay),0) [Amt]
From Patient_Account P
Group By P.TranMainId
ii) Avoid using <>.So Status must be either 'A' or 'I'
so write this instead CT.[Status] = 'I'
iii) What is the correct data type of TranDate ?Don't use function in where condition. .
iv) No need of isnull(CT.IsCancel,0) = 1,instead write CT.IsCancel = 1
So my script is just outline, but it is easy to understand.
Declare #IDs nvarchar(max)='1,4,5,6,8,9,43,183'
create table #temp(id int)
insert into #temp(id)
SELECT val FROM dbo.f_split(#IDs, ',')
declare #FromDate Datetime='2019-08-01'
declare #toDate Datetime='2019-08-31'
-- mention all column of FeeTransaction that you need in this query along with correct data type
-- Store TranDate in this manner convert(char(10),FT.TranDate,126) in this table
create table #Transaction()
select * from FeeTransaction FT
where FT.TranDate>=#FromDate and FT.TranDate<#toDate
and exists(select 1 from #temp t where t .val=ft.id)
-- mention all column of Patient_Account that you need in this query along with correct data type
create table #Patient_Account()
Select max(P.Id) [Id], P.TranMainId, isnull(SUM(P.AmtToPay),0) [Amt]
From Patient_Account P
where exists(select 1 from #Transaction T where t.id=PA.TranMainId)
Group By P.TranMainId
SELECT isnull(isnull(SUM(FT.PaidAmt),0) - isnull(SUM(CT.PaidAmt),0),0) [Amount], TranDate [Date]
from #Transaction FT
Inner Join #Patient_Account XP ON PA.Id = XP.Id
Inner Join Master_Fee MF ON XP.FeeId = MF.Id
INNER Join Master_Patient MP ON FT.PID = MP.Id
Inner Join Master_FeeType TY ON MF.FeeTypeId = TY.Id
Left JOIN #Transaction CT on FT.TransactionId = CT.TransactionId AND CT.[Status] = 'I' AND CT.IsCancel = 1
Where AND FT.[Status] = 'A' AND XP.FeeId in (SELECT val FROM #temp t)
AND FT.IsCancel = 0 AND FT.EntryBy = 'rajan'
Group By TranDate

Incorrect syntax for SQL query

So I have this SQL Server query:
declare #symbol varchar(8) = '180460';
declare #sdate DATE = '20170630';
declare #edate DATE = '20170704';
IF #symbol = 'TSE00081'
BEGIN
SELECT * from dbo.IndexNames
END
ELSE
BEGIN
SELECT t1.qcode, t4.Name,t1.effectivedate, t1.publishdate, EventMap.Description, t1.SharesChanged, t1.FFW, t1.OldFFW,
IIF(t1.EventCode='SK',t6.IndexName,''), IIF(t1.EventCode='SK',t7.Indexname,''), IIF(t1.Market<>'',t5.IndexName,''), IIF(t3.NameEn<>'',t3.NameEn,t2.NameEn),
IIF(t1.OldSector<>'',t8.NameEn,''), IIF(t1.Allotment1<>0 AND t1.EventCode<>'05', t1.Allotment2/t1.Allotment1,''), t1.SharesUnit
FROM ( dbo.AdvNoticeData as t1 , dbo.IdTable as t4 )
LEFT JOIN dbo.EventMap on t1.EventCode = dbo.EventMap.EventCode
LEFT JOIN dbo.Industries as t2 on t1.SectorAsOf = t2.IndNum
LEFT JOIN dbo.Industries as t3 on t1.Sector = t3.IndNum
LEFT JOIN dbo.Industries as t8 on t1.OldSector = t8.IndNum
LEFT JOIN dbo.IndexNames as t5 on t1.OldMarket = t5.Market
LEFT JOIN dbo.IndexNames as t6 on t1.Scale = t6.Scale
LEFT JOIN dbo.IndexNames as t7 on t1.OldScale = t7.Scale
WHERE (t1.Market=1 or t1.MarketAsOf=1 or (t1.OldMarket=1 and t1.MarketAsOf=''))
and t1.EffectiveDate >= #sdate and t1.EffectiveDate <= #edate and t1.Qcode = t4.Qcode
ORDER BY t1.EffectiveDate, t1.EventCode, t1.Qcode
END
the problem is after the FROM clause. I keep on getting incorrect syntax at ','
When I tried this command (with few modifications) on sqlyog, it works with that comma after the FROM clause. what seems to be the problem? here's the mysql counter part that works:
SELECT t1.qcode, t4.Name,t1.effectivedate, t1.publishdate,
EventMap.Description, t1.SharesChanged, t1.FFW, t1.OldFFW,
IF(t1.EventCode="SK",t6.IndexName,""),
IF(t1.EventCode="SK",t7.Indexname,""),
IF(t1.market<>"",t5.IndexName,""),
IF(t3.NameEn<>"",t3.NameEn,t2.NameEn),
IF(t1.oldSector<>"",t8.NameEn,""),
IF(t1.allotment1<>0 AND t1.eventcode<>"05",t1.allotment2/t1.allotment1,""),
t1.sharesunit
FROM (AdvNoticeData AS t1, IdTable AS t4)
LEFT JOIN EventMap ON t1.eventcode = EventMap.eventcode
LEFT JOIN Industries AS t2 ON t1.sectorasof = t2.IndNum
LEFT JOIN Industries AS t3 ON t1.sector = t3.IndNum
LEFT JOIN Industries AS t8 ON t1.oldsector = t8.IndNum
LEFT JOIN IndexNames AS t5 ON t1.oldmarket = t5.Market
LEFT JOIN IndexNames AS t6 ON t1.scale = t6.Scale
LEFT JOIN IndexNames AS t7 ON t1.oldscale = t7.Scale
WHERE (t1.market=1 OR t1.marketasof=1 OR (t1.oldmarket=1 AND t1.marketasof=""))
AND t1.effectivedate >= '20170630'
AND t1.effectivedate <= '20170703'
AND t1.Qcode = t4.Qcode
ORDER BY t1.effectivedate, t1.eventcode,t1.qcode
Don't mix legacy and new join syntax.
...
FROM dbo.AdvNoticeData as t1
JOIN dbo.IdTable as t4 ON t1.Qcode = t4.Qcode
LEFT JOIN dbo.EventMap on t1.EventCode = dbo.EventMap.EventCode
...
Modify your old JOIN syntax with an INNER JOIN
declare #symbol varchar(8) = '180460';
declare #sdate DATE = '20170630';
declare #edate DATE = '20170704';
IF #symbol = 'TSE00081'
BEGIN
SELECT * from dbo.IndexNames
END
ELSE
BEGIN
SELECT t1.qcode, t4.Name,t1.effectivedate, t1.publishdate, EventMap.Description, t1.SharesChanged, t1.FFW, t1.OldFFW,
IIF(t1.EventCode='SK',t6.IndexName,''), IIF(t1.EventCode='SK',t7.Indexname,''), IIF(t1.Market<>'',t5.IndexName,''), IIF(t3.NameEn<>'',t3.NameEn,t2.NameEn),
IIF(t1.OldSector<>'',t8.NameEn,''), IIF(t1.Allotment1<>0 AND t1.EventCode<>'05', t1.Allotment2/t1.Allotment1,''), t1.SharesUnit
FROM dbo.AdvNoticeData as t1
INNER JOIN dbo.IdTable as t4 ON t1.Qcode = t4.Qcode
LEFT JOIN dbo.EventMap on t1.EventCode = dbo.EventMap.EventCode
LEFT JOIN dbo.Industries as t2 on t1.SectorAsOf = t2.IndNum
LEFT JOIN dbo.Industries as t3 on t1.Sector = t3.IndNum
LEFT JOIN dbo.Industries as t8 on t1.OldSector = t8.IndNum
LEFT JOIN dbo.IndexNames as t5 on t1.OldMarket = t5.Market
LEFT JOIN dbo.IndexNames as t6 on t1.Scale = t6.Scale
LEFT JOIN dbo.IndexNames as t7 on t1.OldScale = t7.Scale
WHERE (t1.Market=1 or t1.MarketAsOf=1 or (t1.OldMarket=1 and t1.MarketAsOf=''))
and t1.EffectiveDate >= #sdate and t1.EffectiveDate <= #edate
ORDER BY t1.EffectiveDate, t1.EventCode, t1.Qcode
END

Invoke a column twice with different conditions

I really appreciate any help with this matter :)
Am Working on a Report now and I had faced some troubles
I have this Query and it work fine , now I want to add a coulmn that is already exist in the query(from the same table) , but this time i'll change the condition of it , BTW the conditions in both of the 2 column are based on one other column
like for example If I have this :
Select Price from ITM1 WHERE PriceList = '1'
and also this
Select Price from ITM1 WHERE PriceList = '10'
how I can write in the same query and let them display in two different column ?
I will put the Query here in case if some one can help me through it :
you can see THE Column Price & PriceList in the lower part of it ,Bolded.
I just need to make the samething again but with a new coulmn name thats it.
Using the IN Operator will give you what you want. However, there are other changes that you can make to your query which would boost performance - but it's out of scope to the question. I'm unclear as to what you're trying to do with the different "columns" Please help explain. Else see #Dave.Gugg's answer which does just that.
SELECT T0.ItemCode,
T0.ItemName,
T0.CardCode,
T0.CodeBars,
T2.UgpCode,
T3.AltQty,
T3.BaseQty,
CASE
WHEN T4.Uomentry = - 1
THEN T0.[BuyUnitMsr]
ELSE t4.UomName
END AS 'UoMName',
T4.UomEntry,
T0.U_CAT_CODE,
T0.U_CAT_NAME,
T1.CardName,
(
SELECT TOP (1) dbo.PDN1.U_AC_QTY_ORDER
FROM dbo.PDN1
INNER JOIN dbo.OPDN ON dbo.PDN1.DocEntry = dbo.OPDN.DocEntry
WHERE (dbo.PDN1.ItemCode = T0.ItemCode)
AND (dbo.OPDN.CardCode = T0.CardCode)
ORDER BY dbo.OPDN.DocDate DESC
) AS OQuantity,
(
SELECT TOP (1) PDN1_1.U_AC_QTY_BONUS
FROM dbo.PDN1 AS PDN1_1
INNER JOIN dbo.OPDN AS OPDN_1 ON PDN1_1.DocEntry = OPDN_1.DocEntry
WHERE (PDN1_1.ItemCode = T0.ItemCode)
AND (OPDN_1.CardCode = T0.CardCode)
ORDER BY OPDN_1.DocDate DESC
) AS BQuantity,
ITM1.Price,
T0.U_DISC_PER
FROM dbo.OITM AS T0
INNER JOIN dbo.OCRD AS T1 ON T0.CardCode = T1.CardCode
INNER JOIN dbo.OUGP AS T2 ON T0.UgpEntry = T2.UgpEntry
INNER JOIN dbo.UGP1 AS T3 ON T2.UgpEntry = T3.UgpEntry
INNER JOIN dbo.ITM1 ON T0.ItemCode = dbo.ITM1.ItemCode
AND dbo.ITM1.PriceList IN ('1', '10')
LEFT JOIN dbo.OUOM AS T4 ON T3.UomEntry = T4.UomEntry
WHERE (T0.Series = '65')
AND (
T4.UomEntry = 3
OR T4.UomEntry = '-1'
)
If you want a different column (this may perform better than two joins):
SELECT T0.ItemCode,
T0.ItemName,
T0.CardCode,
T0.CodeBars,
T2.UgpCode,
T3.AltQty,
T3.BaseQty,
CASE
WHEN T4.Uomentry = - 1
THEN T0.[BuyUnitMsr]
ELSE t4.UomName
END AS 'UoMName',
T4.UomEntry,
T0.U_CAT_CODE,
T0.U_CAT_NAME,
T1.CardName,
(
SELECT TOP (1) dbo.PDN1.U_AC_QTY_ORDER
FROM dbo.PDN1
INNER JOIN dbo.OPDN ON dbo.PDN1.DocEntry = dbo.OPDN.DocEntry
WHERE (dbo.PDN1.ItemCode = T0.ItemCode)
AND (dbo.OPDN.CardCode = T0.CardCode)
ORDER BY dbo.OPDN.DocDate DESC
) AS OQuantity,
(
SELECT TOP (1) PDN1_1.U_AC_QTY_BONUS
FROM dbo.PDN1 AS PDN1_1
INNER JOIN dbo.OPDN AS OPDN_1 ON PDN1_1.DocEntry = OPDN_1.DocEntry
WHERE (PDN1_1.ItemCode = T0.ItemCode)
AND (OPDN_1.CardCode = T0.CardCode)
ORDER BY OPDN_1.DocDate DESC
) AS BQuantity,
CASE
WHEN ITM1.PriceList = '1'
THEN ITM1.Price
ELSE '0'
END AS Price1,
CASE
WHEN ITM1.PriceList = '10'
THEN ITM1.Price
ELSE '0'
END AS Price2,
T0.U_DISC_PER
FROM dbo.OITM AS T0
INNER JOIN dbo.OCRD AS T1 ON T0.CardCode = T1.CardCode
INNER JOIN dbo.OUGP AS T2 ON T0.UgpEntry = T2.UgpEntry
INNER JOIN dbo.UGP1 AS T3 ON T2.UgpEntry = T3.UgpEntry
INNER JOIN dbo.ITM1 ON T0.ItemCode = dbo.ITM1.ItemCode
AND dbo.ITM1.PriceList IN ('1', '10')
LEFT JOIN dbo.OUOM AS T4 ON T3.UomEntry = T4.UomEntry
WHERE (T0.Series = '65')
AND (
T4.UomEntry = 3
OR T4.UomEntry = '-1'
)
You should be able to just join to the table a second time, but you will need to make the joins outer:
SELECT T0.ItemCode ,
T0.ItemName ,
T0.CardCode ,
T0.CodeBars ,
T2.UgpCode ,
T3.AltQty ,
T3.BaseQty ,
CASE WHEN T4.Uomentry = -1 THEN T0.[BuyUnitMsr]
ELSE t4.UomName
END AS 'UoMName' ,
T4.UomEntry ,
T0.U_CAT_CODE ,
T0.U_CAT_NAME ,
T1.CardName ,
( SELECT TOP ( 1 )
dbo.PDN1.U_AC_QTY_ORDER
FROM dbo.PDN1
INNER JOIN dbo.OPDN ON dbo.PDN1.DocEntry = dbo.OPDN.DocEntry
WHERE ( dbo.PDN1.ItemCode = T0.ItemCode )
AND ( dbo.OPDN.CardCode = T0.CardCode )
ORDER BY dbo.OPDN.DocDate DESC
) AS OQuantity ,
( SELECT TOP ( 1 )
PDN1_1.U_AC_QTY_BONUS
FROM dbo.PDN1 AS PDN1_1
INNER JOIN dbo.OPDN AS OPDN_1 ON PDN1_1.DocEntry = OPDN_1.DocEntry
WHERE ( PDN1_1.ItemCode = T0.ItemCode )
AND ( OPDN_1.CardCode = T0.CardCode )
ORDER BY OPDN_1.DocDate DESC
) AS BQuantity ,
dbo.ITM1.Price ,
ITM1Second.Price,
T0.U_DISC_PER
FROM dbo.OITM AS T0
INNER JOIN dbo.OCRD AS T1 ON T0.CardCode = T1.CardCode
INNER JOIN dbo.OUGP AS T2 ON T0.UgpEntry = T2.UgpEntry
INNER JOIN dbo.UGP1 AS T3 ON T2.UgpEntry = T3.UgpEntry
LEFT OUTER JOIN dbo.ITM1 ON T0.ItemCode = dbo.ITM1.ItemCode
AND dbo.ITM1.PriceList = '10'
LEFT OUTER JOIN dbo.ITM1 ITM1Second ON T0.ItemCode = ITM1Second.ItemCode
AND ITM1Second.PriceList = '1'
LEFT OUTER JOIN dbo.OUOM AS T4 ON T3.UomEntry = T4.UomEntry
WHERE ( T0.Series = '65' )
AND ( T4.UomEntry = 3
OR T4.UomEntry = '-1'
)

CAST to int used with LEFT on an nvarchar field not working properly?

I'm trying to create a view where I union 4 tables. One of the fields is a document number. The only way I can pull the related document number from one of the tables is by running a LEFT on the 6 left-most characters. But when I do this and then CAST to integer I still cannot query the field. It's like it's looking past my where clause and trying to convert ALL of the characters in the field.
This is what I'm doing:
SELECT dbo.OSLP.U_RepStatus AS RepStatus, dbo.OSLP.SlpCode, dbo.OPCH.CardCode, dbo.OPCH.CardName, 'IN' AS DocTypeDesc, dbo.OPCH.DocNum,
dbo.OPCH.DocEntry, dbo.OPCH.DocDate, dbo.OPCH.NumAtCard, dbo.OPCH.DocStatus, dbo.OPCH.DocTotal, dbo.OPCH.U_CommInvNo AS ARInvNo
FROM dbo.OPCH INNER JOIN
dbo.OCRD ON dbo.OPCH.CardCode = dbo.OCRD.CardCode INNER JOIN
dbo.OSLP ON dbo.OCRD.U_SalesRepNumber = dbo.OSLP.SlpCode
WHERE (dbo.OSLP.U_RepStatus IN ('Dir', 'Ind', 'Sal')) AND (dbo.OPCH.U_CommInvNo IS NOT NULL)
UNION
SELECT OSLP_1.U_RepStatus AS RepStatus, OSLP_1.SlpCode, dbo.ORPC.CardCode, dbo.ORPC.CardName, 'CM' AS DocTypeDesc, dbo.ORPC.DocNum, dbo.ORPC.DocEntry,
dbo.ORPC.DocDate, dbo.ORPC.NumAtCard, dbo.ORPC.DocStatus, - 1 * dbo.ORPC.DocTotal AS DocTotal, dbo.ORPC.U_CommInvNo AS ARInvNo
FROM dbo.ORPC INNER JOIN
dbo.OCRD AS OCRD_1 ON dbo.ORPC.CardCode = OCRD_1.CardCode INNER JOIN
dbo.OSLP AS OSLP_1 ON OCRD_1.U_SalesRepNumber = OSLP_1.SlpCode
WHERE (OSLP_1.U_RepStatus IN ('Dir', 'Ind', 'Sal')) AND (dbo.ORPC.U_CommInvNo IS NOT NULL)
UNION
SELECT T3.U_RepStatus AS RepStatus, T3.SlpCode, T0.ContraAct AS CardCode, T2.CardName, 'JE' AS DocTypeDesc, T1.TransId AS DocNum, T1.TransId AS DocEntry,
T1.RefDate AS DocDate, T0.LineMemo AS NumAtCard, T1.BtfStatus AS DocStatus, T0.Debit AS DocTotal, CAST(LEFT(T0.LineMemo, 6) AS INT) AS ARInvNo
FROM dbo.JDT1 AS T0 INNER JOIN
dbo.OJDT AS T1 ON T0.TransId = T1.TransId INNER JOIN
dbo.OCRD AS T2 ON T0.ContraAct = T2.CardCode INNER JOIN
dbo.OSLP AS T3 ON T2.U_SalesRepNumber = T3.SlpCode
WHERE (T0.ShortName = 'CompanyName') AND (T1.TransType = 30) AND (T0.Account = '_SYS00000000624') AND (T3.U_RepStatus IN ('Dir', 'Ind', 'Sal')) AND (T0.Debit > 0)
UNION
SELECT T7.U_RepStatus AS RepStatus, T7.SlpCode, T4.ContraAct AS CardCode, T6.CardName, 'JE' AS DocTypeDesc, T5.TransId AS DocNum, T5.TransId AS DocEntry,
T5.RefDate AS DocDate, T4.LineMemo AS NumAtCard, T5.BtfStatus AS DocStatus, - (1 * T4.Credit) AS DocTotal, CAST(LEFT(T4.LineMemo, 6) AS INT) AS ARInvNo
FROM dbo.JDT1 AS T4 INNER JOIN
dbo.OJDT AS T5 ON T4.TransId = T5.TransId INNER JOIN
dbo.OCRD AS T6 ON T4.ContraAct = T6.CardCode INNER JOIN
dbo.OSLP AS T7 ON T6.U_SalesRepNumber = T7.SlpCode
WHERE (T4.ShortName = 'CompanyName') AND (T5.TransType = 30) AND (T4.Account = '_SYS00000000624') AND (T7.U_RepStatus IN ('Dir', 'Ind', 'Sal')) AND (T4.Credit > 0)
If I query this view with WHERE ARInvNo = 295696 I get this error:
Msg 245, Level 16, State 1, Line 1
Conversion failed when converting the nvarchar value 'A/P In' to data type int.
If I take out the bottom 2 unions from my view I can query with WHERE ARInvNo = 295696 without an issue. If I run the second 2 parts of the query, nothing in my results includes 'A/P In', although that does exist in rows in JDT1 outside of the WHERE criteria I'm using. Any idea why SQL is looking past my WHERE statement and trying to LEFT and CAST every field before it returns any data?
To clarify, this returns no results:
SELECT T0.LineMemo
FROM JDT1 T0 INNER JOIN OJDT T1 ON T0.TransId = T1.TransId INNER JOIN OCRD T2 ON T0.ContraAct = T2.CardCode INNER JOIN OSLP T3 ON T2.U_SalesRepNumber = T3.SlpCode
WHERE T0.ShortName = 'CompanyName' AND T1.TransType = 30 AND T0.Account = '_SYS00000000624' AND T3.U_RepStatus IN ('Dir', 'Ind', 'Sal') AND left(T0.LineMemo,3)='A/P In'
I see it now.
It's seeing 'A/P in' in your values. It can't CAST the '/' character to INT
MSSQL cast( [varcharColumn] to int) in SELECT gets executed before WHERE clause filters out bad values
In short you will want to do this:
select (case when isnumeric(TO.LineMemo) = 1 then cast(TO.LineMemo as int) end)