Related
I have 3 tables in SQL Server that are exactly the same. I am trying to write a stored procedure to get the value of 2 columns from 2 tables and update the 3rd table with the difference. These are the 3 tables:
Current
Proposed
Final
I am passing in rfds_processing_id. It is similar to an order number and contains multiple rows, so matching has to be done on rfds_processing_id, type, sector, and position.
I need to match every row from the 3 tables and then subtract the value of Current.qty from Final.qty and update the Proposed.qty with the difference. It also needs to update Proposed.model with the value of Final.model (when Proposed.qty > 0). Currently it is setting every row to the same value. I'm assuming I need to loop through the rows. What should that look like?
ALTER PROCEDURE [dbo].[CalculateProposedAntennas]
(
#rfds_processing_id uniqueidentifier = null,
#id uniqueidentifier OUTPUT
)
AS
BEGIN
SET NOCOUNT ON
UPDATE P
SET qty = (F.qty - C.qty) , model = F.model
FROM Proposed_Antenna P
INNER JOIN Final_Antenna F
ON P.rfds_processing_id = F.rfds_processing_id
INNER JOIN Current_Antenna C
ON F.rfds_processing_id = C.rfds_processing_id
WHERE
F.rfds_processing_id = C.rfds_processing_id
AND F.sector = C.sector
AND F.type = C.type
AND F.position = C.position
RETURN
END
The following query should do what you want:
ALTER PROCEDURE [dbo].[CalculateProposedAntennas]
(
#rfds_processing_id uniqueidentifier = null,
#id uniqueidentifier OUTPUT
)
AS
BEGIN
SET NOCOUNT ON
UPDATE P
SET P.qty = F.qty - C.qty
,P.model = CASE WHEN Proposed.qty > 0 THEN F.model ELSE NULL END
FROM Proposed_Antenna P
INNER JOIN Final_Antenna F
ON F.rfds_processing_id = P.rfds_processing_id AND F.sector = P.sector AND F.type = P.type AND F.position = P.position
INNER JOIN Current_Antenna C
ON C.rfds_processing_id = P.rfds_processing_id AND C.sector = P.sector AND C.type = P.type AND C.position = P.position
RETURN
END
I highly recommend you to create a [UID] column in all three of your tables - the unique identifier case can be generated as below, the generated key is of varbinary type which is far better than string comparison in joins
select [UID] = HashBytes('MD5',rfds_processing_id+type+sector+position)
I have the below queries and I want to get #BillCardName:
DECLARE
#BillSet int,
#BillCardName varchar(50)
-- get #BillCardName from a table 1st
SELECT #BillSet = BillSet,
#BillCardName = vInvBriefDesc
FROM BillTableA
WHERE ID = 1234
--If we have a iBillingSetID, we need the description from another table
IF #BillSet <> 0
BEGIN
SELECT #BillCardName = vBillDescription
FROM BillTableB
WHERE BillSet = #BillSet
END
I am able to write the above and wondering if the above can be combined into one query?
LEFT join both table and use CASE WHEN to check for BillSet <> 0
SELECT BillCardName = CASE WHEN a.BillSet <> 0
THEN b.vBillDescription
ELSE a.vInvBriefDesc
END
FROM BillTableA a
LEFT JOIN BillTableB b ON a.BillSet = b.BillSet
WHERE a.ID = 1234
I think what you're aiming for here can be accomplished using a left (outer) join and coalesce (which returns the first non-null value in a given sequence).
DECLARE
#BillSet int,
#BillCardName varchar(50)
SELECT #BillSet = bta.BillSet,
#BillCardName = coalesce (btb.vBillDescription, bta.vInvBriefDesc)
FROM BillTableA as bta
LEFT JOIN BillTableB as btb
ON bta.BillSet = btb.BillSet
--uncomment the line below if 0 is a valid value for BillSet in BillTableB
--AND bta.BillSet <> 0
WHERE bta.ID = 1234
END
I have a VERY long running, heavy stored procedure, so I would like to change it over to a job that runs every night and updates a table so the user can run it quickly during the day. My problem is that it takes parameters IN THE LEFT JOIN, so I don't see how I could do it. I tried to remove the parameters from the joins and just take all the records, but first problem with that is that these left joins are joins to table valued functions with group by clauses (so it's tons of records now) and also when I did it, it crashed my whole server. I will post part of my stored proc to give you an idea of what i'm doing for now.
--alternatively, i would take an answer that could change my query perfomance from 2 minutes to 10 seconds. :)
--btw, another thing that is slowing down this query is that the functions are querying a linked server...
create PROC [dbo].[mySP]
#FromDate DateTime,
#ToDate DateTime = NULL,
#Style NVARCHAR(max),
#ItemType NVARCHAR(300),
#ItemCode NVARCHAR(150)= null,
#ItemsNotSold INT,
#MultiplyUsage DECIMAL(18,4),
#SParts BIT,
#vendorId nvarchar(50),
#currentPage int,
#largeOrderSoNumbers nvarchar(300) = null,
#excludeprojTag BIT,
#hasOrderQty BIT = null,
#createPO BIT = null,
#excludeTestOrders BIT = null,
#refresh BIT = null,
#userid int = null,
#positiveOverUse BIT = null
AS
SELECT #FROMDATE = #FROMDATE
,#ToDate=#ToDate
,#Style=#Style
,#ItemType=#ItemType
,#ItemCode=#ItemCode
,#ItemsNotSold=#ItemsNotSold
,#MultiplyUsage=#MultiplyUsage
,#SParts=#SParts
,#vendorId=#vendorId
,#currentPage=#currentPage
,#largeOrderSoNumbers=#largeOrderSoNumbers
,#excludeprojTag=#excludeprojTag
,#hasOrderQty =#hasOrderQty
,#createPO =#createPO
,#excludeTestOrders =#excludeTestOrders
,#refresh =#refresh
,#userid =#userid
,#positiveOverUse=#positiveOverUse
DECLARE #amountPerPage int = 400;
DECLARE #startingPoint int = (#currentpage - 1) * #amountPerPage
SET #TODATE = NULLIF(#TODATE,'1/1/4000');
SET #ITEMCODE = NULLIF(#ITEMCODE,'');
SET #largeOrderSoNumbers = NULLIF(#LARGEORDERSONUMBERS,'');
BEGIN
IF #Style = '-1'
SET #Style = NULL
IF #ItemType = '-1'
SET #ItemType = NULL
END
SELECT
ISNULL(c.NewQB_ListID,iit.ListID) ListID,
(select salesdesc from iteminventory i where i.listid = ISNULL(c.NewQB_ListID,iit.ListID)) as SalesDesc,
isnull(inl.linename,'') + isnull(c.NewName,Name) as ItemCode ,
max(il.CubicMeterKD) as CubicMeterKD,
sum(CONVERT(decimal(18,4),inl.Quantity) )
- sum(CONVERT(decimal(18,4),inl.qtyRuleTag))
+ CONVERT(decimal(18,4),isnull(ai.qty,0))
-CONVERT(decimal(18,4),isnull(ai.QtyRuleTag,0))
AS TotalQtyUesd,
sum(convert(decimal(18,4),isnull(inl.QtyRuleTag,0)))
as QtyUsedWithProjectTag,
Convert(decimal(18,4),QuantityOnHand) as OnHand,
CONVERT(int,ISNULL(EzQtyOnSO.Qty,0)) as OnSalesOrder,
CONVERT(int,ISNULL(EzQtyAnyStatus.QtyLgO,0))as OnLgOrder,
Convert(decimal(18,4),QuantityOnOrder) as OnPO,
Convert(decimal(18,4),isnull(LargePO.lgOrderQtyOnPO,0)) as lgOrderQtyOnPO ,
fl.LineName
INTO #Q
FROM
iteminventory iit
LEFT JOIN Lines fl
ON iit.ParentRef_ListID = QB_LisiID
LEFT JOIN tb_ItemList il
ON iit.ListID = il.QBListID
LEFT JOIN InlSales(#FromDate,#ToDate, #excludeprojtag, #excludeTestOrders) INL
ON IIT.LISTID = INL.ITEMREF_LISTID
LEFT JOIN tb_CombinedItems c
ON iit.ListID = c.ListID
LEFT JOIN [QuantityInvoice](#FromDate, #ToDate,#excludeprojTag,#excludeTestOrders) as ai
ON ai.QBID = iit.ListID
LEFT JOIN fn_QuantityOnSalesOrder(#excludeTestOrders) AS EzQtyOnSO
ON iit.ListID = EzQtyOnSO.QBID
LEFT JOIN QuantityAnyStatus(#largeOrderSoNumbers, #excludeprojTag) AS EzQtyAnyStatus
ON iit.ListID = EzQtyAnyStatus.QBID
LEFT JOIN dbo.[FN_LargePO](#excludeTestOrders) LargePO --WITH (nolock)
ON LargePO.QBID = iit.ListID
WHERE
(#Style is null or ISNULL(c.ParentListID,ParentRef_ListID) in (SELECT Value From fn_MultiValueParameter(#Style))) AND
(#ItemType is null or ItemTypeCode in (SELECT Value From fn_MultiValueParameter(#ItemType))) AND
(#ItemCode is null or il.ItemCode like '%' + #ItemCode + '%') AND
(IsActive = 1 OR c.ListID IS NOT NULL)
GROUP BY
ISNULL(c.NewQB_ListID,iit.ListID),
ISNULL(c.NewName,Name),
inl.LineName,
QuantityOnHand,
iit.QuantityOnOrder,
CONVERT(int,ISNULL(EzQtyOnSO.Qty,0)),
fl.LineName,
CONVERT(decimal(18,4),isnull(ai.qty,0)),
Convert(decimal(18,4),isnull(LargePO.lgOrderQtyOnPO,0)),
CONVERT(int,ISNULL(EzQtyAnyStatus.QtyLgO,0)),
CONVERT(decimal(18,4),isnull(ai.QtyRuleTag,0))
IF #ItemsNotSold = 1
BEGIN
DELETE FROM #Q
WHERE isnull(TotalQtyUesd,0) <> 0
END
IF #ItemsNotSold = 2
BEGIN
DELETE FROM #Q
WHERE isnull(TotalQtyUesd,0) = 0
END
SELECT
q.ListID,
q.SalesDesc,
q.ItemCode,
MAX(isnull(q.CubicMeterKD,0)) as CubicMeterKD,
SUM(q.TotalQtyUesd)
TotalQtyUesd,
SUM(q.QtyUsedWithProjectTag) as QtyUsedWithProjectTag,
SUM(q.OnHand) OnHand,
SUM(q.OnSalesOrder) OnSalesOrder,
SUM(q.OnLgOrder) OnLgOrder,
SUM(q.OnPO)
- isnull(SUM(q.lgOrderQtyOnPO),0)
OnPO,
SUM(q.lgOrderQtyOnPO) as lgOrderQtyOnPO,
LineName
INTO #QTY
FROM
#Q q
GROUP BY
q.ListID,
q.salesdesc,
q.ItemCode,
q.LineName
;WITH Results AS
(
SELECT
isnull(P.listid,'') as ListID,
isnull(P.SalesDesc,'') as SalesDesc,
isnull(P.itemcode,'') as ItemCode,
ISNULL(CubicMeterKD,0) AS CubicMeterKD,
isnull(TotalQtyUesd,0) as TotalQtyUsed,
isnull(QtyUsedWithProjectTag,0) as QtyUsedWithProjectTag,
isnull(onhand,0) as OnHand,
isnull((OnHand - OnSalesOrder - OnLgOrder),0) as available,
isnull(OnLgOrder,0) as OnLgOrder,
isnull(OnPO,0) as OnPo,
isnull(lgOrderQtyOnPO,0) as lgOrderQtyOnPO,
isnull(((OnHand - OnSalesOrder) + OnPO) ,0) AS [AvailableAndOnPo],
isnull((TotalQtyUesd * #MultiplyUsage) - ((OnHand - OnSalesOrder) + OnPO),0) AS [AvlOnPOminusUsed],
isnull((((TotalQtyUesd * #MultiplyUsage) - ((OnHand - OnSalesOrder) + OnPO)) / CASE WHEN TotalQtyUesd > 0 THEN TotalQtyUesd END)*100,0) AS PctOver
,isnull(linename,0) as LineName,
isnull((select price from qbdb.dbo.tb_iteminfodetail where vendorlistid = #vendorid and itemcode =isnull(P.itemcode,'')),0.0) as price
,isnull(pod.qtytoReOrder,0) as qtyToReOrder
,isnull(pod.qtytoOrder,0) as qtyToOrder
,isnull(pod.includePO,0) as includePO
,ROW_NUMBER() OVER (ORDER BY ITEMCODE) AS RowNum
FROM #qty AS p
left join dbo.purchaseorderpreliminarydetails pod on pod.listid = P.listid and pod.deleteFlag = 0
and headerid = (select top 1 headerid from purchaseorderpreliminary where deleteFlag = 0)
WHERE
CASE WHEN #positiveOverUse = 1 THEN
isnull((((TotalQtyUesd * #MultiplyUsage) - ((OnHand - OnSalesOrder) + OnPO)) / CASE WHEN TotalQtyUesd > 0 THEN TotalQtyUesd END)*100,0)
ELSE 1 END >0
AND
case when #hasOrderQty = 1 then isnull(pod.QtyToReOrder,0) else 1 end > 0
and
CASE WHEN #SPARTS = 1 THEN CASE WHEN
ItemCode IN (
'APP',
'CD',
'-S',
'L0',
'L/42',
'L01',
'Lfrgs2',
'Lfad2',
'Sfasdf9',
'SdafdsA',
'Sfasdf3',
'Sasdf6',
'asdf0',
'Sf6',
'fasdfadf2',
'fasdfasdf',
'S2236',
'S12342',
'Sdf 30',
'SdfE 36',
'fgsfgs',
'fasdf-fdasf',
'fadf',
'fasdf-fasdf',
'sdaf',
'adf 11"',
'fda 14"',
'fdas 24"') THEN 1 ELSE 0 END ELSE 1 END = 1
)
SELECT (select count(rownum) from results) as totalItems,* FROM Results WHERE
rownum between #startingPoint + 1 and #startingPoint + #amountPerPage
Have a form the users can put their parameters into before they go home, and save them into a new table in the database. Change the stored procedure to either get the parameters from this new table or to use the new table in the joins &c. The SP now doesn't need the parameters to sent to it. Finally call the SP via a Job.
In my stored procedure I have a case statement that is supposed to test whether a field is numeric and handle that but I get the same error no matter what. I have tried below:
CASE WHEN ISNUMERIC(subScores.ScoreValue) = 1 THEN CAST(subScores.ScoreValue AS REAL) ELSE -1 END
I also used a custom convert function because I have read that isnumeric isn't 100% reliable but that received the same error. I also tried using CONVERT but no success there. I even replaced the isnumeric with 0=1 which should always fail but I still get the same error which I find really strange. This is my error:
Error converting data type nvarchar to real
The values that it is checking look like:
A0, A10, A23, B9, B51, C90, C100, etc
Any ideas for this behavior?
Here is the full procedure. The issue happening on the first case in the where clause after the THEN instead of using -1 its using the actual field. It also contain my usage of ISNUMERIC and my custom function:
#strDemoCodeIds nvarchar(100),
#strYearIds nvarchar(100),
#intRosterSetId int,
#intSchoolId int,
#intTeachId int,
#intGradeId int,
#intDeptId int,
#intCourseId int,
#intPeriodId int,
#strTestInstIds nvarchar(100),
#intTestTypeId int,
#intSubjectId int,
#intScoreTypeId int,
#strSuppScoreTypeId nvarchar(20),
#intClusterScoreTypeId int,
#intClusterColorScoreTypeId int,
#intLocalReportId int,
#strSortMethod nvarchar(20),
#intAnchorYear int
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #topYearID INT
DECLARE #subs TABLE (subId int)
IF #intSubjectId < 100
BEGIN
INSERT INTO #subs
SELECT MM_Test_Subjects.pkTestSubjectID
FROM MM_Test_Subjects
WHERE MM_Test_Subjects.fkCSTStrandID = #intSubjectId
END
ELSE
BEGIN
INSERT INTO #subs VALUES (#intSubjectId)
END
DECLARE #years TABLE (yearId int)
INSERT INTO #years
SELECT number FROM itot(#strYearIds, N',')
SET #topYearID = #intAnchorYear
SELECT s.pkStudentID,
s.LastName,
s.FirstName,
s.StudentNumber,
st.fkTestInstanceID,
bands.Description AS 'PL',
bands.Color,
subScoresSupp.scoreValue AS 'SuppScore',
clusters.pkTestClusterID,
clusterScores.ScoreValue,
colors.ScoreValue,
ti.TestInstanceName,
tp.TestPeriodTitle,
subScores.ScoreValue AS 'PLScore',
ScoreType.pkScoreTypeID,
bands.StackPosition AS 'StackPosition'
FROM Students s
INNER JOIN StudentTests st ON s.pkStudentID = st.fkStudentID
INNER JOIN StudentTests baseSt ON s.pkStudentID = baseSt.fkStudentID
AND baseSt.fkGradeID = CASE #intGradeId WHEN 99 THEN baseSt.fkGradeID ELSE #intGradeId END
AND EXISTS (SELECT * FROM StudentScores_Subject baseSubScores WHERE baseSubScores.fkStudentTestID = baseSt.pkStudentTestID
AND baseSubScores.fkTest_SubjectID IN (SELECT subId FROM #subs)
AND baseSubScores.fkScoreTypeID = #intScoreTypeId)
INNER JOIN StudentTestDemographics d ON d.fkStudentTestID = baseSt.pkStudentTestID
INNER JOIN itot(#strDemoCodeIds, N',') tblDemoCodes ON d.fkDemographicCodeID = CASE #strDemoCodeIds WHEN '0' THEN d.fkDemographicCodeID ELSE tblDemoCodes.number END
INNER JOIN StudentScores_Subject subScores ON subScores.fkStudentTestID = st.pkStudentTestID
AND subScores.fkTest_SubjectID IN (SELECT subId FROM #subs)
AND subScores.fkScoreTypeID = #intScoreTypeId
LEFT JOIN PerformanceLevelReportBands bands ON bands.fkPerformanceLevelReportID = #intLocalReportId
LEFT JOIN MMARS_Web_TestInfo_California.dbo.PerfLevelReportBandCutScores cutScores ON cutScores.fkPerformanceLevelReportBandID = bands.pkPerformanceLevelReportBandID
AND cutScores.fkGradeID = #intGradeId
AND cutScores.fkTestSubjectID IN (SELECT subId FROM #subs)
RIGHT JOIN PerfLevelReportBandComponents bandComponents ON bandComponents.fkPerformanceLevelReportBandID = bands.pkPerformanceLevelReportBandID
LEFT JOIN StudentScores_Subject subScoresSupp ON subScoresSupp.fkStudentTestID = st.pkStudentTestID
AND subScoresSupp.fkTest_SubjectID IN (SELECT subId FROM #subs)
AND subScoresSupp.fkScoreTypeID IN (SELECT tblsubScoresSupp.number FROM itot(#strSuppScoreTypeId, N',') tblsubScoresSupp)
LEFT JOIN MM_ScoreTypes ScoreType ON ScoreType.pkScoreTypeID = subScoresSupp.fkScoreTypeID
LEFT JOIN StudentScores_Cluster clusterScores ON clusterScores.fkStudentTestID = st.pkStudentTestID
AND clusterScores.fkTest_SubjectID IN (SELECT subId FROM #subs)
AND clusterScores.fkScoreTypeID = #intClusterScoreTypeId
LEFT JOIN StudentScores_Cluster colors ON colors.fkStudentTestID = st.pkStudentTestID
AND colors.fkTest_SubjectID IN (SELECT subId FROM #subs)
AND colors.fkScoreTypeID = #intClusterColorScoreTypeId
AND colors.fkTest_ClusterID = clusterScores.fkTest_ClusterID
LEFT JOIN MM_Test_Clusters clusters ON clusters.pkTestClusterID = clusterScores.fkTest_ClusterID
INNER JOIN TestInstances ti ON ti.pkTestInstanceID = st.fkTestInstanceID
INNER JOIN TestInstances baseTi ON baseTi.pkTestInstanceID = baseSt.fkTestInstanceID
AND baseTi.fkSchoolYearID = #topYearID
INNER JOIN CAHSEE_TestPeriods tp on tp.pkTestPeriodID = ti.fkTestPeriodID
INNER JOIN CAHSEE_TestPeriods baseTp on baseTp.pkTestPeriodID = baseTi.fkTestPeriodID
INNER JOIN Roster_Students rs ON rs.fkStudentID = s.pkStudentID
INNER JOIN Roster_Groups rg ON rg.fkTestInstanceID = baseTi.pkTestInstanceID
AND ti.pkTestInstanceID IN (SELECT tblTestInstances.number FROM itot(#strTestInstIds, N',') tblTestInstances)
AND baseTi.pkTestInstanceID IN (SELECT tblTestInstances.number FROM itot(#strTestInstIds, N',') tblTestInstances)
AND rg.fkRosterSetID = #intRosterSetId
AND rg.pkRosterGroupID = rs.fkRosterGroupID
AND (rg.fkSchoolID = #intSchoolId OR #intSchoolId = 0)
AND (rg.fkTeacherID = #intTeachId OR #intTeachId = 0)
AND (rg.fkGradeID = baseSt.fkGradeID)
AND (rg.fkDepartmentID = #intDeptId OR #intDeptId = 0)
AND (rg.fkCourseID = #intCourseId OR #intCourseId = 0)
AND (rg.fkPeriodID = #intPeriodId OR #intPeriodId = 0)
WHERE (bandComponents.ScoreValue = subScores.ScoreValue)
OR
((CASE WHEN ISNUMERIC(subScores.ScoreValue) = 1 THEN CAST(subScores.ScoreValue AS REAL) ELSE subScores.ScoreValue END)
BETWEEN (CASE WHEN dbo.TryConvertInt(bandComponents.minScore) = 1 THEN CAST(bandComponents.minScore AS REAL) ELSE bandComponents.minScore END) and
(CASE WHEN dbo.TryConvertInt(bandComponents.maxScore) = 1 THEN CAST(bandComponents.maxScore AS REAL) ELSE bandComponents.maxScore END)/*CAST(ISNULL(bandComponents.maxScore,'0') AS INT)*/)
OR
((CASE WHEN ISNUMERIC(subScores.ScoreValue) = 1 THEN CAST(subScores.ScoreValue AS REAL) ELSE -1 END)
BETWEEN ISNULL(cutScores.minScore,0) and ISNULL(cutScores.maxScore,0))
GROUP BY s.pkStudentID, s.LastName, s.FirstName, s.StudentNumber, st.fkTestInstanceID, bands.Description, bands.Color, subScoresSupp.scoreValue,
clusters.pkTestClusterID, clusterScores.ScoreValue, colors.ScoreValue, ti.TestInstanceName, tp.TestPeriodTitle, subScores.ScoreValue,
ScoreType.pkScoreTypeID, bands.StackPosition
ORDER BY
CASE WHEN #strSortMethod = 'ScoreDesc'
THEN bands.StackPosition END DESC,
CASE WHEN #strSortMethod = 'ScoreAsc'
THEN bands.StackPosition END ASC,
CASE WHEN #strSortMethod = 'ScoreDesc' AND ISNUMERIC(subScores.ScoreValue) = 1
THEN CONVERT(int, subScores.ScoreValue) END DESC,
CASE WHEN #strSortMethod = 'ScoreAsc' AND ISNUMERIC(subScores.ScoreValue) = 1
THEN CONVERT(int, subScores.ScoreValue) END ASC,
s.LastName, s.FirstName, s.pkStudentID, st.fkTestInstanceID
END
The problem is that the case statement is trying to return only one type of value so if the THEN is trying to convert to real and return that back then the ELSE is going to try and do the same so even if there is no cast it is going to try to convert it implicitly. This explains why this works:
DECLARE #scoreValue nvarchar(10)
SET #scoreValue = N'A53'
SELECT CASE WHEN ISNUMERIC(#scoreValue) = 1 THEN CAST(#scoreValue AS REAL) ELSE 1.0 END
But this does not:
DECLARE #scoreValue nvarchar(10)
SET #scoreValue = N'A53'
SELECT CASE WHEN ISNUMERIC(#scoreValue) = 1 THEN CAST(#scoreValue AS REAL) ELSE #scoreValue END
So the key is to use sql_variant so this works:
CASE WHEN ISNUMERIC(#scoreValue) = 1 THEN CAST(#scoreValue AS REAL) ELSE CAST(#scoreValue AS sql_variant) END
I will try for your stuff then find this iss
select CASE WHEN ISNUMERIC(CONVERT(nvarchar,'- 5')) = 1 THEN CAST(CONVERT(nvarchar,'- 5') AS REAL) ELSE -1 END
Isnumeric function should be return of this value true, and convert function should not convert value into real because space in value.
find data of this type in your column like scorevalue.
The problem is not the line you are pointing !
This line is ok :
CASE WHEN ISNUMERIC(subScores.ScoreValue) = 1 THEN CAST(subScores.ScoreValue AS REAL) ELSE -1 END
But in the first case, just after the WHERE clause you have this line
CASE WHEN ISNUMERIC(subScores.ScoreValue) = 1 THEN CAST(subScores.ScoreValue AS REAL) ELSE subScores.ScoreValue END
It cannot work as if ScoreValue is not numeric, you have a case with real datas and varchar data (I guess ScoreValue is varchar)
You have to put once again -1 instead of ScoreValue to make it work
/*Show how isnumeric differs from TRY_CONVERT*/
declare #temp table (dec int, chr char(1) , isnum int,tryconvert int)
declare #loop int = 1
declare #i int
while #loop < 127
begin
set #i = #loop
insert into #temp (dec,chr,isnum,tryconvert)
select #i,char(#i) charac, isnumeric(char(#i)), TRY_CONVERT(int,char(#i))
set #loop = #loop + 1
end
select * from #temp where isnum = 1
Our DBA has changed a function to be a procedure, so I am amending some of my procedures to cater for this. I've come across a problem with this in one of my procedures where I have a while loop.
I populate my temp table from the new procedure (#DGContol), and then have the following while loop:
SELECT #MinRcd = MIN(RcdNum) FROM #PortfolioDisclosure
SELECT #MaxRcd = MAX(RcdNum) FROM #PortfolioDisclosure
SET #RcdNum = #MinRcd
WHILE #RcdNum <= #MaxRcd
BEGIN
-- Temporarily assign values to variables
SELECT
#PortfolioGroup = PortfolioCode
, #EndDateTime = MaxPositionDate_DetailedDisclosure
FROM #PortfolioDisclosure
WHERE RcdNum = #RcdNum
INSERT INTO #PositionsTable
SELECT
fi.ID_ISIN AS [Fund_ISIN]
, RTRIM(a.acct_id) AS [Internal_Portfolio_Code]
, a.acct_desc AS [Portfolio/Fund_Name]
, CONVERT(CHAR(11),p.as_of_tms,103) AS [Portfolio_Date]
, a.alt_curr_cde AS [Portfolio_Base_Ccy]
, i.iss_desc AS [Security_Description]
, RTRIM(i.pref_iss_id) AS [Security_ID SEDOL/Internal]
, RTRIM(ia.iss_id) AS [Security_ID ISIN]
, i.denom_curr_cde AS [Denomination_Ccy]
, SUM(p.valval_alt_cmb_amt) OVER (PARTITION BY RTRIM(a.acct_id))
AS [Total_Fund_Value]
, p.orig_quantity AS [Shares/Par_Value]
, p.valval_alt_cmb_amt AS [Market_Value]
, p.fld5_rte AS [Pct_of_NAV]
, SUM(CASE WHEN i.issue_cls1_cde = '010' THEN p.valval_alt_cmb_amt ELSE 0 END) OVER (PARTITION BY a.acct_id)
AS [Cash/Cash_Equivalents]
, i.inc_proj_cmb_rte AS [Coupon_Rate]
, CONVERT(CHAR(11),i.mat_exp_dte,103) AS [Maturity_Date]
FROM dw_position_dg AS p
INNER JOIN #DGControl AS dgc -- [M]onthly, [M]ost recent position
ON dgc.DataGrpCtlNum = p.data_grp_ctl_num
INNER JOIN dw_ivw_acct AS a WITH (NOLOCK)
ON a.acct_id = p.acct_id
INNER JOIN dw_issue_dg AS i WITH (NOLOCK)
ON i.instr_id = p.instr_id
LEFT OUTER JOIN dw_issue_alt_id AS ia WITH (NOLOCK)
ON ia.instr_id = i.instr_id
AND ia.id_ctxt_typ = 'ISIN'
INNER JOIN #PortfolioDisclosure AS fi
ON fi.PortfolioCode = p.acct_id
and fi.MaxPositionDate_DetailedDisclosure >= p.as_of_tms
WHERE RTRIM(a.acct_id) NOT IN ( SELECT xref.internal_value FROM dbo.DP_CrossReference as xref
WHERE xref.Codeset_type_id = 10401
AND xref.Originator_id = 'DataVendorPortfolioExclusion')
-- Clear down variable values
SET #PortfolioGroup = NULL
--SET #StartDateTime = NULL
SET #EndDateTime = NULL
-- Move to next record
SET #RcdNum = #RcdNum + 1
END -- END WHILE LOOP
However this returns lots of duplicate records. If I replace the temp table #DGControl with the original function then I get the correct number of records.
I don't really know what the issue would be or how I could re code this while loop so that using the table #DGControl I get the correct number of records. Can anyone help?
Have you compared the output of SELECT * FROM OldFunction(args..) with EXEC NewStoredProcedure args...? If so, does the data returned look the same or has the duplication crept in when the DBA refactored the function to a proc.
If so you may need to de dupe the output from the sp first then run it through your remaining code. In short, if you are using the same arguments for both but they give you different results then you'll need to go back to the DBA.
You aren't using either of your local variables (#PortfolioGroup, #EndDateTime) in this code. It is just inserting the same record set N number of times. Also, I think you can write this as a single select query without using temp tables or while loops and it will make it less confusing.
Thank you for your feedback. i worked out the issue. My code looks like the following now:
BEGIN
SELECT #MinRcd = MIN(RcdNum) FROM #PortfolioDisclosure
SELECT #MaxRcd = MAX(RcdNum) FROM #PortfolioDisclosure
SET #RcdNum = #MinRcd
WHILE #RcdNum <= #MaxRcd
BEGIN
-- Temporarily assign values to variables
SELECT
#PortfolioGroup = PortfolioCode
, #EndDateTime = MaxPositionDate_DetailedDisclosure
FROM #PortfolioDisclosure
WHERE RcdNum = #RcdNum
-- Insert DGControl record into table based on the MaxPositionDate_DetailedDisclosure from Portfolio Disclosure function
INSERT INTO #DGControl
EXEC InfoPortal..usp_Generic_DGControl '', '', #PortfolioGroup, '1', #EndDateTime, #EndDateTime, #PeriodType, 'M', 'POSITION' -- [M]onthly, [M]ost recent position
-- Insert into #PositionsTable
INSERT INTO #PositionsTable
SELECT
fi.ID_ISIN AS [Fund_ISIN]
, RTRIM(a.acct_id) AS [Internal_Portfolio_Code]
, a.acct_desc AS [Portfolio/Fund_Name]
, CONVERT(CHAR(11),p.as_of_tms,103) AS [Portfolio_Date]
, a.alt_curr_cde AS [Portfolio_Base_Ccy]
, i.iss_desc AS [Security_Description]
, RTRIM(i.pref_iss_id) AS [Security_ID SEDOL/Internal]
, RTRIM(ia.iss_id) AS [Security_ID ISIN]
, i.denom_curr_cde AS [Denomination_Ccy]
, SUM(p.valval_alt_cmb_amt) OVER (PARTITION BY RTRIM(a.acct_id))
AS [Total_Fund_Value]
, p.orig_quantity AS [Shares/Par_Value]
, p.valval_alt_cmb_amt AS [Market_Value]
, p.fld5_rte AS [Pct_of_NAV]
, SUM(CASE WHEN i.issue_cls1_cde = '010' THEN p.valval_alt_cmb_amt ELSE 0 END) OVER (PARTITION BY a.acct_id)
AS [Cash/Cash_Equivalents]
, i.inc_proj_cmb_rte AS [Coupon_Rate]
, CONVERT(CHAR(11),i.mat_exp_dte,103) AS [Maturity_Date]
FROM dw_position_dg AS p
INNER JOIN #DGControl AS dgc
ON dgc.DataGrpCtlNum = p.data_grp_ctl_num
INNER JOIN dw_ivw_acct AS a WITH (NOLOCK)
ON a.acct_id = p.acct_id
INNER JOIN dw_issue_dg AS i WITH (NOLOCK)
ON i.instr_id = p.instr_id
LEFT OUTER JOIN dw_issue_alt_id AS ia WITH (NOLOCK)
ON ia.instr_id = i.instr_id
AND ia.id_ctxt_typ = 'ISIN'
INNER JOIN #PortfolioDisclosure AS fi
ON fi.PortfolioCode = p.acct_id
-- Clear down variable values
SET #PortfolioGroup = NULL
--SET #StartDateTime = NULL
SET #EndDateTime = NULL
-- Clear down #DGControl table to allow new record to be inserted
DELETE FROM #DGControl
-- Move to next record
SET #RcdNum = #RcdNum + 1
END -- END WHILE LOOP
Adding the execution of the stored proc usp_Generic_DGControl at the beginning and then clearing it down after each loop stopped the duplication of the records.