Delimited query not listing all values - stored-procedures

Thru SP i am trying to get all the product id from the product table....in the below format: prod1,prod2, prod3, prod4....etc. but it is not listing all the product id from the table. Here is my SP:
create procedure spGetAllProductID
#productcode varchar(500) output
as
BEGIN
BEGIN TRY
declare #DelimitedString varchar(500)
Select #DelimitedString = isnull(#DelimitedString + ',','') + Productid
from prdtable
Select #DelimitedString
set #productcode=#DelimitedString
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER() as ErrorNumber, ERROR_MESSAGE() as ErrorMessage
END CATCH
END

Could it be because your string is at varchar(500) and it is truncating at 500 characters so will omit the later product codes. What about being bold and using varchar(max) for your variables/parameters?

Related

Error -206 creating Interbase stored procedure

I am attempting to create a stored procedure using an IBConsole interactive SQL window. The intent of the procedure is to gather data from two tables, do some processing on that data, insert rows containing that data into a working table, then return the rows from the working table as the stored procedure result. The stored procedure:
SET TERM ^;
CREATE PROCEDURE BIBLIO_SUBJECT
RETURNS (ID INTEGER, SUBJECT VARCHAR(200))
AS
DECLARE VARIABLE CUR_SUBJECT VARCHAR(200);
DECLARE VARIABLE SUBJECT_LIST VARCHAR(500);
DECLARE VARIABLE BIBLIOID INTEGER;
DECLARE VARIABLE NEXTPOS INTEGER;
BEGIN
DELETE FROM TSUBJECTS;
FOR SELECT BIBLIO.ID, BIBLIO.SUBJECTS
FROM BIBLIO
WHERE BIBLIO.PUBLISH = TRUE
INTO :BIBLIOID, :SUBJECT_LIST
DO
BEGIN
SUBJECT_LIST = BIBLIO.SUBJECTS + ';';
NEXTPOS = LOCATE(";", SUBJECT_LIST);
WHILE (:NEXTPOS > 1) DO
BEGIN
CUR_SUBJECT = SUBSTR(:SUBJECT_LIST, 1, NEXTPOS - 1);
SUBJECT_LIST = SUBSTR(:SUBJECT_LIST, NEXTPOS + 1, STRLEN(SUBJECT_LIST));
INSERT INTO TSUBJECTS (SUBJECT, ID) VALUES(:CUR_SUBJECT, :BIBLIOID);
NEXTPOS = LOCATE(";", SUBJECT_LIST);
END
END
FOR SELECT BIBLIO_BEAST.BIBLIO_ID, BEAST.BEAST_NAME
FROM BIBLIO_BEAST
INNER JOIN BEAST ON (BEAST.ID = BIBLIO_BEAST.BEAST_ID)
INNER JOIN BIBLIO ON (BIBLIO.ID = BIBLIO_BEAST.BIBLIO_ID)
WHERE BIBLIO.PUBLISH = TRUE
INTO :BIBLIOID, :CUR_SUBJECT
DO
BEGIN
INSERT INTO TSUBJECTS (SUBJECT, ID) VALUES(:CUR_SUBJECT, :BIBLIOID);
END
FOR SELECT ID, SUBJECT
FROM TSUBJECTS
INTO :ID, :SUBJECT
DO
SUSPEND;
END^
SET TERM ;^
When I execute the above code in IBConsole I get the error:
Error at line 2
Dynamic SQL Error
SQL error code = -206
Column unknown
SQL - CREATE PROCEDURE BIBLIO_SUBJECT
RETURNS (ID INTEGER, SUBJECT VARCHAR(200))
AS
DECLARE VARIABLE CUR_SUBJECT VARCHAR(200);
DECLARE VARIABLE SUBJECT_LIST VARCHAR(500);
DECLARE VARIABLE BIBLIOID INTEGER;
DECLARE VARIABLE NEXTPOS INTEGER;
BEGIN
DELETE FROM TSUBJECTS;
FOR SELECT BIBLIO.ID, BIBLIO.SUBJECTS
FROM BIBLIO
WHERE BIBLIO.PUBLISH = TRUE
INTO :BIBLIOID, :SUBJECT_LIST
DO
BEGIN
SUBJECT_LIST = BIBLIO.SUBJECTS + ';';
NEXTPOS = LOCATE(";", SUBJECT_LIST);
WHILE (:NEXTPOS > 1) DO
BEGIN
CUR_SUBJECT = SUBSTR(:SUBJECT_LIST, 1, NEXTPOS - 1);
SUBJECT_LIST = SUBSTR(:SUBJECT_LIST, NEXTPOS + 1, STRLEN(SUBJECT_LIST));
INSERT INTO TSUBJECTS (SUBJECT, ID) VALUES(:CUR_SUBJECT, :BIBLIOID);
NEXTPOS = LOCATE(";", SUBJECT_LIST);
END
END
FOR SELECT BIBLIO_BEAST.BIBLIO_ID, BEAST.BEAST_NAME
FROM BIBLIO_BEAST
INNER JOIN BEAST ON (BEAST.ID = BIBLIO_BEAST.BEAST_ID)
INNER JOIN BIBLIO ON (BIBLIO.ID = BIBLIO_BEAST.BIBLIO_ID)
WHERE BIBLIO.PUBLISH = TRUE
INTO :BIBLIOID, :CUR_SUBJECT
DO
BEGIN
INSERT INTO TSUBJECTS (SUBJECT, ID) VALUES(:CUR_SUBJECT, :BIBLIOID);
END
FOR SELECT ID, SUBJECT
FROM TSUBJECTS
INTO :ID, :SUBJECT
DO
SUSPEND;
END
It doesn't say which column is "unknown", and line 2 is (apparently) the RETURNS clause of the CREATE PROCEDURE. Not at all helpful.
Each of the SQL statements in the stored procedure (3 SELECTs, a DELETE, 2 INSERTs) work without error if executed separately in an Interactive SQL window, so all of their columns are "known". BIBLIO_SUBJECT is not the name of an existing stored procedure, nor is it the name of an existing table, or anything else in the database.
This has me baffled. Online searches provide no answer. So I am hoping the clever Stack Overflow people can help me get this working.
David
Well, I figured it out. It was the statement:
SUBJECT_LIST = BIBLIO.SUBJECTS + ';';
The SUBJECT_LIST variable is already used in the preceding select. A silly mistake, but I am old.
Not that it matters since the Interbase UDF functions Locate() and Substr() can only handle 80 character strings, which makes them really useless to me... and probably useless to most.

Using a Cursor in a Stored Procudure

I have the following code extremely slow code in a MS SQL 2016 Stored Procedure (I think it is stuck in a never ending loop):
#DBID Integer
AS
BEGIN
DECLARE TagCursor CURSOR FOR SELECT MemberID
FROM ADMIN_API_Master_Members_List
WHERE DBID= #DBID AND Len(Pending) > 0
DECLARE #ProgramCode VARCHAR(10)
DECLARE #Values VARCHAR(MAX)
DECLARE #tag nvarchar(10)
OPEN TagCursor
FETCH NEXT FROM TagCursor INTO #tag
WHILE (##FETCH_STATUS = 0)
BEGIN
SELECT #ProgramCode = Program_Code, #Values= Pending FROM ADMIN_API_Master_Members_List WHERE MemberID= #tag
DELETE FROM ADMIN_API_PMID_PROGRAM_CODE_HOLDING_TABLE
WHERE (MemberID =#tag)
INSERT INTO ADMIN_API_PMID_PROGRAM_CODE_HOLDING_TABLE ( ProgramCode, MemberID, DBID, PMID)
SELECT #ProgramCode, #tag, #DBID , Value FROM STRING_SPLIT(#Values, ',')
END
CLOSE TagCursor
DEALLOCATE TagCursor
END
This Procedure is only a maintenance process and does not get run very often but when it does it would be nice to only take a few seconds. The purpose is to normalize in a Table one record for each comma seperated value in the ADMIN_API_Master_Members_List Table and put it into the ADMIN_API_PMID_PROGRAM_CODE_HOLDING_TABLE with the Program_Code and MemberID and DBID.
There are only about 150 records in the Master Table and the comma separated strings may have 5 values. I am receptive to other solutions.
Thanks in advance
I haven't tested this, but like I mentioned in the comments, using a CURSOR is a bad idea; they are inherently slow as SQL Server excels at set based methods not iterative tasks (and a CURSOR is the latter).
I suspect that this achieves the answer you're after and avoids the CURSOR all together:
CREATE PROC YourProc #DBID integer
AS
BEGIN
DECLARE #Deleted table (ProgramCode varchar(10),
[Value] varchar(MAX),
Tag nvarchar(10));
DELETE HT
OUTPUT deleted.Program_Code,
deleted.Pending,
deleted.MemberID
INTO #Deleted (ProgramCode,
[Value],
Tag)
FROM ADMIN_API_PMID_PROGRAM_CODE_HOLDING_TABLE AS HT
JOIN ADMIN_API_Master_Members_List AS MML ON HT.MemberID = MML.MemberID
WHERE MML.[DBID] = #DBID
--AND LEN(Pending) > 0; --Changed this to below to be SARGable, as only a string with the value '' will have a length of 0.
AND Pending != '';
INSERT INTO ADMIN_API_PMID_PROGRAM_CODE_HOLDING_TABLE (ProgramCode,
MemberID,
DBID,
PMID)
SELECT D.ProgramCode,
D.Tag,
#DBID,
SS.Value
FROM #Deleted AS D
CROSS APPLY STRING_SPLIT(D.[Value], ',') AS SS;
END;
The reason for the infinite loop may be that you have no "Fetch next" inside your loop
Try the below:
#DBID Integer
AS
BEGIN
DECLARE TagCursor CURSOR FOR SELECT MemberID
FROM ADMIN_API_Master_Members_List
WHERE DBID= #DBID AND Len(Pending) > 0
DECLARE #ProgramCode VARCHAR(10)
DECLARE #Values VARCHAR(MAX)
DECLARE #tag nvarchar(10)
OPEN TagCursor
FETCH NEXT FROM TagCursor INTO #tag
WHILE (##FETCH_STATUS = 0)
BEGIN
SELECT #ProgramCode = Program_Code, #Values= Pending FROM ADMIN_API_Master_Members_List WHERE MemberID= #tag
DELETE FROM ADMIN_API_PMID_PROGRAM_CODE_HOLDING_TABLE
WHERE (MemberID =#tag)
INSERT INTO ADMIN_API_PMID_PROGRAM_CODE_HOLDING_TABLE ( ProgramCode, MemberID, DBID, PMID)
SELECT #ProgramCode, #tag, #DBID , Value FROM STRING_SPLIT(#Values, ',')
FETCH NEXT FROM TagCursor INTO #tag
END
CLOSE TagCursor
DEALLOCATE TagCursor
END

How can I create a stored procedure to only allow inserts in a particular month?

I want to create a stored procedure that only does inserts in the month of March. The stored procedure should accept values for the table but use the system date to determine if the records should be inserted.
This is what I was trying but procedure created with errors.
CREATE OR REPLACE PROCEDURE sp_time_1203383 (
p_sales_id IN sales_1203383.SALES_ID%TYPE,
p_product IN sales_1203383.PRODUCT%TYPE,
p_unitcost IN sales_1203383.UNITCOST%TYPE,
p_quantity IN sales_1203383.QUANTITY%TYPE
)
IS
BEGIN
IF( MONTH( GETDATE() ) = 3 )
BEGIN
INSERT INTO sales_1203383 ("SALES_ID", "PRODUCT", "UNITCOST", "QUANTITY")
VALUES (p_sales_id, p_product,p_unitcost, p_quantity);
END
ELSE
BEGIN
SELECT 'Can Only insert during the month of March'
END
COMMIT;
END;
I think Praveen gave you the right advice.
I personally would not use the
SELECT count(1) into v_cnt FROM dual WHERE month(sysdate) = 3;
but you can check in a if ... then ... else ... end; statement with the following code:
if to_char(sysdate,'mm') = '03' then ... end;
There are a few errors in your stored procedure:
You cannot have select with if statement
Use then with IF statement and at end End if
; has to be used with End statement
You cannot return a select set from a procedure/function/block (ref cursor should be used)
If you want raise error in the else part use raise_application_error.
If your select statement is like select 'something' use dummy table dual, select 'something' from dual
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
CREATE OR REPLACE PROCEDURE sp_time_1203383 (
p_sales_id IN sales_1203383.SALES_ID%TYPE,
p_product IN sales_1203383.PRODUCT%TYPE,
p_unitcost IN sales_1203383.UNITCOST%TYPE,
p_quantity IN sales_1203383.QUANTITY%TYPE
)
IS
v_cnt NUMBER;
BEGIN
SELECT count(1) into v_cnt FROM dual WHERE month(sysdate) = 3;
IF v_cnt > 0 THEN
INSERT INTO sales_1203383 ("SALES_ID", "PRODUCT", "UNITCOST", "QUANTITY")
VALUES (p_sales_id, p_product, p_unitcost, p_quantity);
ELSE
raise_application_error(-20101, 'Can Only insert during the month of March');
END IF;
END;

How to read output value from stored procedure in c#?

Here is my stored procedure:
ALTER PROCEDURE sp_searchupdate
(
#id int,
#id_student int,
#output varchar(50) output,
#Tamil Varchar (100),
#English varchar (50),
#Maths Varchar (50),
#Science Varchar (50),
#SocialScience Varchar (50)
)
AS
IF EXISTS (SELECT * FROM studentresult WHERE id=#id)
BEGIN
UPDATE studentresult SET Tamil = #Tamil,English = #English, Maths = #Maths,Science = #Science,SocialScience = #SocialScience WHERE id = #id
SET #output='Updated'
RETURN
END
Else
BEGIN
IF EXISTS (SELECT * FROM student WHERE id=#id_student)
SET #output='EXIST'
RETURN
BEGIN
INSERT into studentresult (id_student,Tamil,English,Maths,Science,SocialScience) values (#id_student,#Tamil,#English,#Maths,#Science,#SocialScience)
SET #output='Inserted'
RETURN
END
END
If inserted data in front-end it need to shows 'inserted' or update means 'updated' or else 'exist'.
But for the above query didn't show notification message.
May i know, what my mistake in my code?
Can anyone guide me, I'M new stored procedure and .net.
Thanks,
It's rather unclear exactly what you are trying to achieve - why would you only insert into the studentresult record if the student record did NOT exist? Anyway, currently if no studentresult record exists then the procedure will always return after the check for the student record. There is no BEGIN...END after the IF EXISTS so only the first statement after the IF will be dependent on the result. Try:
ALTER PROCEDURE sp_searchupdate
(
#id int,
#id_student int,
#output varchar(50) output,
#Tamil Varchar (100),
#English varchar (50),
#Maths Varchar (50),
#Science Varchar (50),
#SocialScience Varchar (50)
)
AS
BEGIN
IF EXISTS (SELECT * FROM studentresult WHERE id=#id)
BEGIN
UPDATE studentresult SET Tamil = #Tamil,English = #English, Maths = #Maths,Science = #Science,SocialScience = #SocialScience WHERE id = #id
SET #output='Updated'
END
Else
BEGIN
IF EXISTS (SELECT * FROM student WHERE id=#id_student)
BEGIN
SET #output='EXIST'
END
ELSE
BEGIN
INSERT into studentresult (id_student,Tamil,English,Maths,Science,SocialScience) values (#id_student,#Tamil,#English,#Maths,#Science,#SocialScience)
SET #output='Inserted'
END
END
RETURN
END

insert multi value with SP

I have two tables.
1- student table & 2- Score table
I want to insert value at student table & insert multi value at Score table with SP to SQL Server 2008.
for EX:
ALTER proc [dbo].[InsertIntoScore]
(
#DateReg datetime,
#stdLastName nvarchar(50),
#stdFirstName nvarchar(50),
#Description nvarchar(500),
multi value as score table...
)
AS
DECLARE #Id AS INT
BEGIN TRY
BEGIN TRANSACTION
INSERT INTO Student(DateReg,stdLastName,stdFirstName,[Description])
VALUES (#DateReg,#stdLastName,#stdFirstName,#Description)
set #Id = SCOPE_IDENTITY()
insert multi value at Score table...
COMMIT
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK
END CATCH
please help me...
You should use Table-Valued Parameters
Create a Sql Type for the table you will pass in
CREATE TYPE dbo.ScoreType AS TABLE ( ScoreID int, StudentID int, etc.... )
pass your datatable from C# code into the stored procedure using the above defined type
ALTER proc [dbo].[InsertIntoScore]
( #DateReg datetime, #stdLastName nvarchar(50), #stdFirstName nvarchar(50),
#Description nvarchar(500), #tvpScore ScoreType)
AS
.....
INSERT INTO dbo.Score (ScoreID, StudentID, ....)
SELECT dt.ScoreID, #id, .... FROM #tvpScore AS dt;
in c# pass the datatable in this way
SqlCommand insertCommand = new SqlCommand("InsertIntoScore", sqlConnection);
SqlParameter p1 = insertCommand.Parameters.AddWithValue("#tvpScore", dtScore);
p1.SqlDbType = SqlDbType.Structured;
p1.TypeName = "dbo.ScoreType";
.....
insertCommand.ExecuteNonQuery();

Resources