I've written a simple stored procedure which uses a scalar function for 4 of the selected data.
I pass an ID which is part of the hole select as parameter of this function.
And finally that stored procedure is matching if ids are IN a Temp_Table I've created at the beginning of the stored procedure.
Problem : the stored procedure is running into an infinite loop.
I know the problem surely comes from the multiple parameter passe as Id in the function but I don't get the logic here !
I tried testing seperately and got the results as expected.
Here is the stored procedure:
ALTER PROCEDURE GetBordereauCotisations
#annee INT,
#sectionId INT
AS
BEGIN
SET NOCOUNT ON;
--Creation table temporaire pour stocker les adhérents d'une section
IF OBJECT_ID('tempdb.dbo.#table_adherent_ids', 'U') IS NOT NULL
DROP TABLE #table_adherent_ids;
CREATE TABLE #table_adherent_ids (AdherentId INT);
BEGIN
INSERT INTO #table_adherent_ids
SELECT p.RessourceId
FROM Personnes p
INNER JOIN PersonneAdherentSituations ps ON ps.RessourceId = p.RessourceId
WHERE p.SectionId = #sectionId AND ps.StatutAdhesion = 880
END
SELECT DISTINCT
pas.NumeroAdherent AS NumAdherent,
CONCAT(ppi.Nom, ' ', ppi.Prenom) AS NomPrenom,
si.Numero AS CodeSection,
'CodeTarif?' AS CodeTarif,
dbo.GetCodeTarifByTrimestrePaye(pas.RessourceId, #annee, 1) AS T1,
dbo.GetCodeTarifByTrimestrePaye(pas.RessourceId, #annee, 2) AS T2,
dbo.GetCodeTarifByTrimestrePaye(pas.RessourceId, #annee, 3) AS T3,
dbo.GetCodeTarifByTrimestrePaye(pas.RessourceId, #annee, 4) AS T4
FROM
PersonneAdherentSituations pas
INNER JOIN
PersonnePersoIdentites ppi ON pas.RessourceId = ppi.RessourceId
INNER JOIN
SectionIdentifications si ON si.RessourceId = #sectionId
INNER JOIN
PersonneAdherentFinancesVersements pfv ON pfv.SectionNumero = si.Numero
WHERE
YEAR(pfv.[Date]) = #annee
GROUP BY
pas.NumeroAdherent, ppi.Nom, ppi.Prenom, si.Numero, pas.RessourceId
HAVING
pas.RessourceId IN (SELECT tai.AdherentId FROM #table_adherent_ids tai)
BEGIN
DROP TABLE #table_adherent_ids;
END
END
GO
Here is the function:
ALTER FUNCTION GetCodeTarifByTrimestrePaye
(#adhrentId INT,
#annee INT,
#trimestre INT)
RETURNS NVARCHAR(MAX)
AS
BEGIN
-- Declare the return variable here
DECLARE #codeTarif nvarchar (MAX);
DECLARE #rowsSelected int = (SELECT CASE
WHEN #trimestre = 1 THEN 1
ELSE #trimestre - 1 END)
DECLARE #apayerAnnee int = (SELECT MAX(CONVERT(int, SUBSTRING(pfv.Apayer, 1, 4)))
FROM PersonneAdherentFinancesVersements pfv
WHERE YEAR(pfv.[Date]) = #annee
AND pfv.RessourceId = #adhrentId)
DECLARE #apayerTrimestre int = (SELECT MAX(CONVERT(int, SUBSTRING(pfv.Apayer, 7, 1)))
FROM PersonneAdherentFinancesVersements pfv
WHERE YEAR(pfv.[Date]) = #annee
AND pfv.RessourceId = #adhrentId)
SET #codeTarif = (SELECT CASE
WHEN #annee < #apayerAnnee
THEN l.Texte
WHEN #annee = #apayerAnnee AND #trimestre <= #apayerTrimestre
THEN l.Texte
ELSE
''
END
FROM PersonneAdherentFinancesVersements pfv
INNER JOIN ListeStatique l ON l.Id = pfv.CodeTarifId
WHERE pfv.IsValidated = 1
AND pfv.ValideParFede = 1
AND pfv.RessourceId = #adhrentId
ORDER BY l.Texte
OFFSET #rowsSelected ROWS
FETCH NEXT 1 ROWS ONLY)
RETURN #codeTarif;
END
GO
How could I obtain only one expected result using my scalar function?
I've a cursor which fetch dynamic number of columns because the "SELECT STATEMENT" which I use to declare this cursor is dynamic.
Since I do not know at any point of time, how many columns this cursor will have, I cannot declare fixed number of variables into fetch.
So I have built FETCH statement as dynamic and stored in one #variable... but when i run fetch statement using EXEC sp_executesql
its failing with error ..Must declare the scalar variable "#objcursor".
I know that #objcursor variable is not accessible becasue while sp_executesql run which run on isolate THREAD
is there any way someone can advise, how to handle this code to run without an error?
Here is my T-SQL code:
/* ==== Variable Declaration ==== */
declare #AllValues nvarchar(max)
declare #objcursor as cursor
declare #MonthCount integer
declare
#vsql as nvarchar(max)
,#vquery as nvarchar(max)
,#id as int
,#value as varchar(50)
BEGIN
SELECT #AllValues = CASE
WHEN t.column_id=1 THEN
(COALESCE(#AllValues +'"', '')+ t.name)+'"'
WHEN t.column_id > 1 THEN
(COALESCE(#AllValues + ',"', '') + t.name)+'"'
END
FROM
(
SELECT sc.name, sc.column_id FROM sys.objects o
INNER JOIN sys.columns sc ON o.object_id = sc.object_id
WHERE o.name = 'temp_daywise' AND o.type = 'U' AND (sc.name like '%Curr Yr%' or column_id=1)
) AS t
ORDER BY t.column_id
SET #AllValues='SELECT "'+#AllValues+' FROM dbo.temp_daywise'
set #vquery = #AllValues
set #vsql = 'set #cursor = cursor forward_only static for ' + #vquery + ' open #cursor;'
exec sys.sp_executesql
#vsql
,N'#cursor cursor output'
,#objcursor output
---Handling Dynamic number of columns in a cursor, get the column count first and build FETCH statement dynamically
Select #CurCount=COUNT(*) from sys.columns where object_id in(
SELECT object_id from sys.objects where name = 'dbo.temp_daywise' and type = 'U' )
and (name like '%Curr Yr%');
SET #LoopCount = 1
--here building my fetch statement
SET #fetchsql ='fetch next from #objcursor into #AgreementID'
WHILE #LoopCount <= #CurCount
BEGIN
SET #fetchsql = #fetchsql+','+'#CY_Day'+CONVERT(VARCHAR(2),#LoopCount)
SET #LoopCount = #LoopCount + 1
END
--EXEC #fetchsql
EXEC sp_executesql #fetchsql
while (##fetch_status = 0)
begin
BEGIN
'update ...here something'
END
EXEC #fetchsql
end
close #objcursor
deallocate #objcursor
END
Here is my data and expected resullts:
1) My dynamic cusror will read column name from sys.columns because coulmns are not static that's based on columns count I'm building FETCH statement. following code build cusrsor SELECT statement
SELECT #AllValues = CASE
WHEN t.column_id=1 THEN
(COALESCE(#AllValues +'"', '')+ t.name)+'"'
WHEN t.column_id > 1 THEN
(COALESCE(#AllValues + ',"', '') + t.name)+'"'
END
FROM
(
SELECT sc.name, sc.column_id FROM sys.objects o
INNER JOIN sys.columns sc ON o.object_id = sc.object_id
WHERE o.name = 'temp_daywise' AND o.type = 'U' AND (sc.name like '%Curr Yr%' or column_id=1)
) AS t
ORDER BY t.column_id
SET #AllValues='SELECT "'+#AllValues+' FROM dbo.temp_daywise'
set #vquery = #AllValues
set #vsql = 'set #cursor = cursor forward_only static for ' + #vquery + ' open #cursor;'
exec sys.sp_executesql
#vsql
,N'#cursor cursor output'
,#objcursor output
2) I want to update fetch data into following table for columns Day1...Day31. if cusrsor found 20 columns data will update until CY_Day20.
3) In short, i do not know the cusror retrieving columns at design time so i can't produce fetching variable. Since columns are known at run tiume, i have to build fetch & update statment in while loop as like below:
Note: ignore DECLARE which is on start of the code... but i placed here to get an idea.
DECLARE
#CY_Day1 Numeric(18,2), #CY_Day2 Numeric(18,2), #CY_Day3 Numeric(18,2), #CY_Day4 Numeric(18,2), #CY_Day5 Numeric(18,2),
, #CY_Day7 Numeric(18,2), #CY_Day8 Numeric(18,2), #CY_Day9 Numeric(18,2), #CY_Day10 Numeric(18,2), #PY_Day10 Numeric(18,2), #CY_Day11 Numeric(18,2), #CY_Day12 Numeric(18,2),........ #CY_Day31 Numeric(18,2)
Select #CurCount=COUNT(*) from sys.columns where object_id in(
SELECT object_id from sys.objects where name = 'dbo.temp_daywise' and type = 'U' )
and (name like '%Curr Yr%');
SET #LoopCount = 1
SET #fetchsql ='fetch next from #objcursor into #AgreementID'
SET #updatesql ='UPDATE dbo.TPDD_Report_Monthly_Details SET '
WHILE #LoopCount <= 2
BEGIN
SET #fetchsql = #fetchsql+','+'#CY_Day'+CONVERT(VARCHAR(2),#LoopCount)
SET #updatesql= #updatesql +'CY_Day'+CONVERT(VARCHAR(2),#LoopCount)+' = #CY_Day'+CONVERT(VARCHAR(2),#LoopCount)+',CY_TPDD_Day'+CONVERT(VARCHAR(2),#LoopCount)+' = (#CY_Day'+CONVERT(VARCHAR(2),#LoopCount)+'/1/1),'
SET #LoopCount = #LoopCount + 1
END
SET #updatesql =#updatesql + ' dss_update_time = #v_dss_update_time WHERE AgreementId = #AgreementID and TpddYear=CONVERT(VARCHAR(4),#Current_year)+CONVERT(VARCHAR(4),#Previous_year) and Running_Month = #MonthNo'
--EXEC #fetchsql
PRINT #fetchsql
PRINT #updatesql
---executing FETCH statement
EXEC sp_executesql #fetchsql
while (##fetch_status = 0)
begin
BEGIN
---updating table columns
EXEC sp_executesql #updatesql
END
EXEC #fetchsql
end
close #objcursor
deallocate #objcursor
Finally my cusrsor fetch & udpate statement will looks like below:
fetch next from #objcursor into #AgreementID,#CY_Day1,#CY_Day2,#CY_Day3,#CY_Day4,#CY_Day5,#CY_Day6,#CY_Day7,#CY_Day8,#CY_Day9,#CY_Day10
UPDATE dbo.TPDD_Report_Monthly_Details SET
CY_Day1 = #CY_Day1, CY_TPDD_Day1 = (#CY_Day1/1/1),
CY_Day2 = #CY_Day2, CY_TPDD_Day2 = (#CY_Day2/1/1),
CY_Day3 = #CY_Day3, CY_TPDD_Day3 = (#CY_Day3/1/1),
CY_Day4 = #CY_Day4, CY_TPDD_Day4 = (#CY_Day4/1/1),
CY_Day5 = #CY_Day5, CY_TPDD_Day5 = (#CY_Day5/1/1),
CY_Day6 = #CY_Day6, CY_TPDD_Day6 = (#CY_Day6/1/1),
CY_Day7 = #CY_Day7, CY_TPDD_Day7 = (#CY_Day7/1/1),
CY_Day8 = #CY_Day8, CY_TPDD_Day8 = (#CY_Day8/1/1),
CY_Day9 = #CY_Day9, CY_TPDD_Day9 = (#CY_Day9/1/1),
CY_Day10 = #CY_Day10, CY_TPDD_Day10 = (#CY_Day10/1/1),
dss_update_time = #v_dss_update_time
WHERE AgreementId = #AgreementID
Hope I;m able to present my problem correctly.
I have a good start. You're probably going to have to tweak a few things. I did my best to get it as close as possible as your actual situation. Hope this helps. If you have any questions, let me know.
NOTE I USE THE SAME TABLE NAMES AND DROP THEM.
IF OBJECT_ID('dbo.temp_daywise') IS NOT NULL
DROP TABLE dbo.temp_daywise;
IF OBJECT_ID('dbo.TPDD_report_Monthly_Details') IS NOT NULL
DROP TABLE dbo.TPDD_report_Monthly_Details;
CREATE TABLE dbo.temp_daywise
(
AgreementID CHAR(6),
RunningMonth INT,
[Curr Yr1] VARCHAR(100),
[Curr Yr2] VARCHAR(100),
[Curr Yr3] VARCHAR(100)
);
INSERT INTO temp_daywise
VALUES ('A10001',3,'col1_1','col2_1','col3_1'),
('A10003',3,'col1_2','col2_2','col3_2'),
('A10006',3,'col1_3','col2_3','col3_3'),
('A10008',3,'col1_4','col2_4','col3_4');
CREATE TABLE dbo.TPDD_report_Monthly_Details
(
TpddYear DATE,
AgreementID CHAR(6),
RunningMonth INT,
[CY_Day1] VARCHAR(100),
[CY_Day2] VARCHAR(100),
[CY_Day3] VARCHAR(100)
);
INSERT INTO TPDD_report_Monthly_Details
VALUES ('20131220','A10001',3,NULL,NULL,NULL),
('20131220','A10003',3,NULL,NULL,NULL),
('20131220','A10006',3,NULL,NULL,NULL),
('20131220','A10008',3,NULL,NULL,NULL);
--Now that I've created my versions of your table, here's the actual code
--Variable to hold columns that need to be updated
DECLARE #ColToBeUpdated VARCHAR(MAX);
--Gets your column information for temp_daywise
WITH CTE_temp_daywise_Cols
AS
(
SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'temp_daywise'
)
--Now join temp_daywise columns to TPDD_report columns
--QUOTENAME() add's brackets [] around each column
SELECT #ColToBeUpdated = COALESCE(#ColToBeUpdated + ',','') + QUOTENAME(A.COLUMN_NAME) + ' = B.' + QUOTENAME(B.COLUMN_NAME)
FROM INFORMATION_SCHEMA.COLUMNS A
INNER JOIN CTE_temp_daywise_Cols B
--The "+1" compensates for difference in ordinal positions
ON A.Ordinal_Position = B.ORDINAL_POSITION + 1
--This makes the table alisaed A to only get columns for TPDD_report
WHERE A.TABLE_NAME = 'TPDD_report_Monthly_Details'
--Don't return AgreementID
AND A.COLUMN_NAME != 'AgreementID'
AND B.COLUMN_NAME != 'AgreementID'
ORDER BY A.ORDINAL_POSITION
--Variable to hold code
DECLARE #sql VARCHAR(MAX);
SELECT #sql = 'UPDATE dbo.TPDD_Report_Monthly_Details
SET ' + #ColToBeUpdated +'
FROM dbo.TPDD_Report_Monthly_Details AS A
INNER JOIN temp_daywise AS B
ON A.AgreementID = B.AgreementID'
--Look at code
--Notice you can join on AgreementID and just set the columns equal to each other
SELECT #sql;
--To execute
--EXEC(#sql)
Results stored in #sql:
UPDATE dbo.TPDD_Report_Monthly_Details
SET [RunningMonth] = B.[RunningMonth],
[CY_Day1] = B.[Curr Yr1],
[CY_Day2] = B.[Curr Yr2],
[CY_Day3] = B.[Curr Yr3]
FROM dbo.TPDD_Report_Monthly_Details AS A
INNER JOIN temp_daywise AS B
ON A.AgreementID = B.AgreementID
I am creating a view using another view inner join(ed) with a table valued function ,
this table valued function calls a Scalar valued function to populate one of its column, when I execute the same,
i get error stating : Maximum stored procedure, function, trigger, or view nesting level exceeded(limit 32)
can anyone help .....plz
*Below is the table valued function
ALTER FUNCTION [dbo].[sstfnAllSubjectWithAASDID]
(
)
RETURNS
#tt TABLE
(
AASDID numeric(18,0),
SubjectString nvarchar(MAX),
SubjectCount int
)
AS
BEGIN
declare #pID numeric(18,0)
declare #pStr nvarchar(MAx)
declare #pCount int
Declare LAASDID Cursor Read_Only Fast_Forward for (SELECT AASDid from vwAcdAdmissionSessionDetailWithAcdAdmissionSessionSubjectDetail)
open LAASDID
FETCH next from LAASDID into #pID
while(##FETCH_STATUS =0)
BEGIN
set #pCount = (SELECT COUNT( MasterSubject.SubjectName ) as cnt
FROM AcdAdmissionSessionSubjectDetail INNER JOIN
MasterSubject ON AcdAdmissionSessionSubjectDetail.SubjectId = MasterSubject.SubjectId where
AcdAdmissionSessionSubjectDetail.AASDID = #pID
)
set #pStr = (SELECT [dbo].[ssspfnGetSubjectname] (#pID))
Insert Into #tt (AASDID,SubjectString,SubjectCount) values (#pID,#pStr,#pCount)
FETCH next from LAASDID into #pID
END
RETURN
END
And this is the scalar valued function which it calls
ALTER FUNCTION [dbo].[ssspfnGetSubjectname]
(
#pAASDID numeric(18,0)
)
RETURNS nvarchar(max)
AS
BEGIN
DECLARE #Cols1 as nvarchar(max)
set #Cols1 = STUFF( (SELECT DISTINCT SubjectName + ','
FROM ( SELECT AcdAdmissionSessionSubjectDetail.AASDID, MasterSubject.SubjectName as SubjectName
FROM AcdAdmissionSessionSubjectDetail INNER JOIN
MasterSubject ON AcdAdmissionSessionSubjectDetail.SubjectId = MasterSubject.SubjectId where
AcdAdmissionSessionSubjectDetail.AASDID = #pAASDID
) as ss
FOR XML PATH('')) ,1,1,'')
RETURN #Cols1
END
Try this code
SP_CONFIGURE 'nested_triggers',0
GO
RECONFIGURE
GO
I have a select statement which contains a number, description, date. when i try to add my date to the statement and run it i get a date conversion from character string error and i am not really sure how to go about it.
DECLARE #parties AS TABLE (
PartyId UNIQUEIDENTIFIER
, Cases NVARCHAR(MAX)
, CaseTypes VARCHAR(MAX)
, Assignment DateTime)
DECLARE #cases NVARCHAR(MAX)
DECLARE #casetypes VARCHAR(MAX)
DECLARE #assignment DateTime
DECLARE #linebreak AS VARCHAR(2)
SET #cases = NULL
SET #casetypes = NULL
SET #assignment = NULL
SET #linebreak = CHAR(13) + CHAR(10)
SELECT #cases = COALESCE(#cases+ #linebreak + C.CaseNumber, C.CaseNumber)+"-"+CT.[Description]+"-"+A.DateOn
FROM [Case] C
INNER JOIN CaseType CT ON C.CaseTypeId = CT.CaseTypeId
INNER JOIN #partyCases PC ON C.CaseId = PC.CaseId
INNER JOIN Appointment A ON C.CaseId = A.CaseId
WHERE PC.PartyId = #partyId
The error occurs after adding A.DateOn to my select statement and running it - any suggestions will be great. Thanks!
SQL returns Date values as datetime and such values can not be implicitly used as strings (varchars). You will have to explicitly convert or cast them. So, change your select statement in either of the 2 ways below:
SELECT #cases = COALESCE(#cases+ #linebreak + C.CaseNumber, C.CaseNumber)+"-"+CT.[Description]+"-"+CONVERT(varchar, A.DateOn)
OR
SELECT #cases = COALESCE(#cases+ #linebreak + C.CaseNumber, C.CaseNumber)+"-"+CT.[Description]+"-"+CAST(A.DateOn as varchar)
CONVERT has a slight advantage - you can apply formatting on the date, if you want.
We have an stored procedure that we created so that user can write comma separated search tags in their software product's admin. So he can add comma-separated tags and in case if he wants to edit them, we read from the table all the tags, recreate them as comma-separated values (CSV) in stored procedure and returns that to the calling code. What happened recently, the user complained that he could not see the new CSVs he wrote. I looked into it and found out that the stored procedure is truncating the string when it reads values from database and creates CSV string. The string is of type nvarchar, and because its exceeding the max characters of 4000 limit, the values gets truncated. Any ideas on how to work out that problem.
Find my code underneath.
BEGIN
BEGIN
Declare #Synonyms Table
(
RowID int Identity(1,1),
SynonymID int,
[Synonym] nvarchar(4000)
);
SET NOCOUNT ON;
Insert #Synonyms(SynonymID, [Synonym])
Select distinct SynonymID, [Synonym] From RF_SearchSynonyms with(nolock) Where SearchTermID = #SearchTermID And ActiveInd = 1
If((Select COUNT(RowID) From #Synonyms) <> 0)
BEGIN
Declare #CurrentRow int = (Select MIN(RowID) From #Synonyms),
#TotalRows int = (Select MAX(RowID) From #Synonyms),
#Synonyms_CSV nvarchar(4000) = '';
WHILE #CurrentRow <= #TotalRows
BEGIN
Declare #TempSyn nvarchar(500);
Select #TempSyn = [Synonym] + ',' From #Synonyms Where RowID = #CurrentRow;
Set #Synonyms_CSV = #Synonyms_CSV + LTRIM(RTRIM(LOWER(#TempSyn)));
SET #CurrentRow = #CurrentRow + 1
END
END
Else
BEGIN
Set #Synonyms_CSV = '';
END
END
BEGIN
Declare #SKUs Table
(
RowID int Identity(1,1),
SkuID int,
SKU nvarchar(15)
);
SET NOCOUNT ON;
Insert #SKUs(SkuID, SKU)
Select distinct SkuID, SKU From RF_SearchSkus with(nolock) Where SearchTermID = #SearchTermID And ActiveInd = 1
If((Select COUNT(RowID) From #SKUs) <> 0)
BEGIN
Declare #CurrentRow1 int = (Select MIN(RowID) From #SKUs),
#TotalRows1 int = (Select MAX(RowID) From #SKUs),
#Skus_CSV nvarchar(4000) = '';
WHILE #CurrentRow1 <= #TotalRows1
BEGIN
Declare #TempSku nvarchar(15);
Select #TempSku = SKU + ',' From #SKUs Where RowID = #CurrentRow1;
Set #Skus_CSV = #Skus_CSV + LTRIM(RTRIM(#TempSku));
SET #CurrentRow1 = #CurrentRow1 + 1
END
END
Else
BEGIN
Set #Skus_CSV = '';
END
END
BEGIN
Declare #Combined varchar(8000),
#syn_len int = 0,
#sku_len int = 0;
Select #syn_len = LEN(#Synonyms_CSV);
Select #sku_len = LEN(#Skus_CSV);
Select #Combined = #Synonyms_CSV + '-_-' + #Skus_CSV;
Select #Synonyms_CSV + '-_-' + #Skus_CSV;
END
END
I can't use text and ntext as they do not play nice with concatenation operations.
Thanks.
How are your declaring the string parameter?
nvarchar(max)
supports up to 2^32-1 (2GB)
See this link.