Table type parameter in a stored procedure cause operand type clash error - sql-server-2008

I want to give an array of identifiers as argument to a stored procedure.
The stored procedure looks like :
ALTER PROCEDURE [dbo].[SearchPerson]
#personType INT = NULL,
#city NVARCHAR(64) = NULL,
#siteIds IntegerList READONLY,
-- some other params...
AS
SELECT
-- some fields...
FROM dbo.PersonView AS pv
WHERE
(
(#personType IS NULL OR pv.PersonType = #personType) AND
(#city IS NULL OR pv.City LIKE '%' + #city + '%') AND
(pv.SiteId in (SELECT si.Value FROM #siteIds AS si)) AND
-- some other params filter...
)
The user table type looks like :
CREATE TYPE [dbo].[IntegerList] AS TABLE(
[Value] [int] NULL
)
When I call the stored procedure from a script in SSMS (I originally have the same problem calling it from .NET code) :
DECLARE #siteIds AS IntegerList,
#personType AS INT = 1
INSERT INTO #siteIds VALUES (1)
EXEC [dbo].[SearchPerson] #personType, #siteIds
I got the error :
Operand type clash: int is incompatible with IntegerList

I found the answer : it was the order of the table type parameter that caused the error !
The table type parameter must be the first in the stored procedure parameters AND ALSO in the arguments passed to the stored procedure call !
The stored procedure :
ALTER PROCEDURE [dbo].[SearchPerson]
#siteIds IntegerList READONLY, -- THIS PARAMETER HAS TO BE THE FIRST !
#personType INT = NULL,
#city NVARCHAR(64) = NULL,
-- some other params...
AS
SELECT
-- some fields...
FROM dbo.PersonView AS pv
WHERE
(
(#personType IS NULL OR pv.PersonType = #personType) AND
(#city IS NULL OR pv.City LIKE '%' + #city + '%') AND
(pv.SiteId in (SELECT si.Value FROM #siteIds AS si)) AND
-- some other params filter...
)
And the call :
DECLARE #siteIds AS IntegerList,
#personType AS INT = 1
INSERT INTO #siteIds VALUES (1)
EXEC [dbo].[SearchPerson] #siteIds, #personType -- PUT #siteIds FIRST !
A sql server bug or am I missing something ?

DECLARE #ErrMsg varchar(1000)
DECLARE #ServiceDates ServiceDatesType
INSERT #ServiceDates (indexId,unitOfDay,dayOfMonth,dateOfMonth)
VALUES
(0,1,11,'9/11/2016 12:00:00 AM'),
(1,1,12,'9/12/2016 12:00:00 AM'),
(2,1,13,'9/13/2016 12:00:00 AM')
EXEC [usp_SaveValidate] 427,4,12,9,2016,#ErrMsg output,#ServiceDates
PRINT #ErrMsg
*/
ALTER PROCEDURE [dbo].[usp_SaveValidate] (
#EpisodeNo INT
,#ProviderId INT
,#ServiceId INT
,#Month INT
,#Year INT
,#ErrorMessage VARCHAR(1000) OUTPUT
,#ServiceDates ServiceDatesType ReadOnly
)
AS
BEGIN
-- Code Here
END
SQL SERVER 2012 - location of table type parameter does not matter, you have to make sure sequence while passing data, you can check above code which is working fine where table type parameter is at the last.

Related

Trigger a stored procedure #2 within another stored procedure #1 based on input from the first stored procedure #1

I need to create a stored procedure which triggers another stored procedure based on what the first stored procedure ingests.
I have a master table called 'Data_Table' which ingests JSON strings. Within the JSON string is another JSON string which is the data of a separate table.
My objective is: when the master table ingests this data, based on the 'data_set_id', it directs the JSON embedded within the table to automatically be ingested into another table via a separate stored procedure already set up. For instance:
CREATE PROCEDURE INSERT_DATA_TABLE_JSON (
#JsonData NVARCHAR(MAX)
)
AS
BEGIN
DECLARE #err int
INSERT INTO Data_Table (
submission_id,
data_set_id,
data_string
)
SELECT *
FROM OPENJSON (#JsonData, N'$') WITH (
submission_id varchar(20) N'$.submission_id',
data_set_id varchar(20) N'$.data_set_id',
data_string varchar(1000) N'$.data_string'
)
SELECT #err = ##ERROR
RETURN (#err)
END
I would then execute this by running the following query:
DECLARE #RC int
DECLARE #JsonData nvarchar(max)
SET #JsonData = N'[{"submission_id":"1","data_set_id":"1","data_string":"[{\"student_id\":1,\"full_name\":\"John Smith\",\"submission_id\":\"1\",\"data_set_id\":\"1\"}]"}]
for json path'
EXECUTE #RC = [dbo].[INSERT_DATA_TABLE_JSON] #JsonData
IF #RC = 0 PRINT 'OK'
ELSE PRINT 'Error'
As you can see, within the 'data_string' column of the Data_Table, we have another JSON. This data_set_id =1 just means that this data is related to a specific table, in this case my Student table which has the following stored procedure:
CREATE PROCEDURE INSERT_STUDENTS_JSON (
#JsonData NVARCHAR(MAX)
)
AS
BEGIN
DECLARE #err int
INSERT INTO Students (
student_id,
full_name,
submission_id,
data_set_id
)
SELECT *
FROM OPENJSON (#JsonData, N'$') WITH (
student_id varchar(20) N'$.student_id',
full_name varchar(20) N'$.full_name',
submission_id varchar(20) N'$.submission_id',
data_set_id varchar(20) N'$.data_set_id'
)
SELECT #err = ##ERROR
RETURN (#err)
END
How do I automatically, allow the first stored procedure, to read the contents of the embedded JSON or otherwise, and then for it to know that it has to use that data to fill in the corresponding Students table.
Here is the JSON string just in case:
[{"submission_id":"1","data_set_id":"1","data_string":"[{\"student_id\":1,\"full_name\":\"John Smith\",\"submission_id\":\"1\",\"data_set_id\":\"1\"}]"}]
I have a second table called Lecturers which I've assigned with data_set_id = 2, so when the embedded JSON has data_set_id = 2, it directs it to the lecturers table.

How to declare and initialize user defined table type?

I created this user table type
CREATE TYPE [dbo].[IntArray] AS TABLE
(
IntValue INT
)
I also created a function
CREATE FUNCTION [dbo].[fnProcessIntArray]
(
#IntArray as dbo.intArray READONLY
)
RETURNS NVARCHAR(max)
AS
BEGIN
-- Input is table of int values
-- Output example : '1,2,3,4'
...
END
now I need to test a function but I don't know how, I tried
SELECT dbo.fnProcessIntArray((SELECT 1))
-- Error: Operand type clash: int is incompatible with IntArray
SELECT dbo.fnProcessIntArray((SELECT 1,2,3,4))
-- Error: Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
How can I DECLARE #intArray as dbo.IntArray ?

Syntax error when calling my stored procedure.

Stored Procedure
create procedure insertUser
#uname varchar(50),#udob date, #uadd varchar(100),#umob bigint
as
begin
insert into userInfo values(#uname,#udob,#uadd,#umob)
end
go
insertUser 'Samuel' '1990-14-04' 'Shivajinagar Pune' 12345630
Error msg:
Msg 102, Level 15, State 1, Line 1 Incorrect syntax near '1990-04-14'.
Your call to the SP is incorrect. Separate the parameters with , like below. Also, date should be entered in a standard format (mm-dd-yyyy or yyyy-mm-dd)
insertUser 'Samuel', '1990-04-14', 'Shivajinagar Pune', 12345630
It would be clear when you pass parameter name = value while calling stored procedure.
Call like this,
CREATE PROCEDURE insertUser #uname VARCHAR(50)
,#udob DATE
,#uadd VARCHAR(100)
,#umob BIGINT
AS
BEGIN
INSERT INTO userInfo
VALUES (
#uname
,#udob
,#uadd
,#umob
)
END
GO
EXEC insertUser #uname = 'Samuel'
,#udob = '1990-14-04'
,#uadd = 'Shivajinagar Pune'
,#umob = 12345630

How to fix error in procedure SQL?

there is a hranimka, when it was created, an error occurs. Maybe she who struck by the ...
The stored procedure:
CREATE PROCEDURE insert_log(
IN LogType INT,
IN LogIdNote INT,
IN LogName VARCHAR,
IN LogTime TIMESTAMP,
IN logTypeCategory INT,
IN LogIdUser INT)
begin
INSERT INTO log (LogType,
LogIdNote,
LogName,
LogTime,
logTypeCategory,
LogIdUser,
LogTypeUser,
LogUrl)
SELECT LogType, LogIdNote, LogName, LogTime, logTypeCategory, LogIdUser, url.URLCategorysubscribetotype, u.UsersTypeAccount FROM users u LEFT JOIN categorysubscribetotype url ON url.CategoryTypeCategorysubscribetotype = LogType WHERE u.idUsers = LogIdUser;
end //
Error:
1064 - You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use
near 'INT LogType, INT LogIdNote, VARCHAR LogName, TIMESTAMP LogTime,
I' at line 3
I tried only change data types at params.
I think, the next code will give me a good result, but I need save result from SELECT query at variable and insert it at query Insert:
DELIMITER |
CREATE PROCEDURE insert_log(
IN pLogType INT,
IN pLogIdNote INT,
IN pLogName VARCHAR(150),
IN pLogTime TIMESTAMP,
IN plogTypeCategory INT,
IN pLogIdUser INT)
BEGIN
DECLARE user_type INT DEFAULT 0;
DECLARE url VARCHAR(250) DEFAULT;
SET user_type = (SELECT UsersTypeAccount FROM users WHERE idUsers = pLogIdUser);
SET url = (SELECT URLCategorysubscribetotype FROM categorysubscribetotype WHERE CategoryTypeCategorysubscribetotype = pLogType);
INSERT INTO log (pLogType,
pLogIdNote,
pLogName,
pLogTime,
plogTypeCategory,
pLogIdUser,
pLogTypeUser,
pLogUrl)
VALUES (
LogType,
LogIdNote,
LogName,
LogTime,
logTypeCategory,
LogIdUser,
user_type,
url
);
END |
delimiter ;
Your issue is here:
INSERT INTO log (pLogType, //wrong!
pLogIdNote,
pLogName,
pLogTime,
plogTypeCategory,
pLogIdUser,
pLogTypeUser,
pLogUrl)
You have used the parameter as column while they should be VALUES try this Query
DELIMITER //
CREATE PROCEDURE insert_log(
IN pLogType INT,
IN pLogIdNote INT,
IN pLogName VARCHAR(150),
IN pLogTime TIMESTAMP,
IN plogTypeCategory INT,
IN pLogIdUser INT)
BEGIN
DECLARE user_type INT DEFAULT 0;
DECLARE url VARCHAR(250) DEFAULT;
SET user_type = (
SELECT UsersTypeAccount
FROM users
WHERE idUsers = pLogIdUser
);
SET url = (
SELECT URLCategorysubscribetotype
FROM categorysubscribetotype
WHERE CategoryTypeCategorysubscribetotype = pLogType
);
INSERT INTO log (
`LogType`,
`LogIdNote`,
`LogName`,
`LogTime`,
`logTypeCategory`,
`LogIdUser`,
`LogIdUserType`, /*I added this*/
`LogIdUrl`, /*this one too */
)VALUES (
pLogType,
pLogIdNote,
pLogName,
pLogTime,
plogTypeCategory,
pLogIdUser,
user_type,
url
);
END //
DELIMITER ;
Please note You need to adjust this stored procedure, there was few mistakes. for example pLogTypeUser and pLogUrl are undefined and I added comments where you need to change the column name.
Your syntax is wrong. The data types come after the parameter names, the IN/OUT specifiers come before. Something like this:
CREATE PROCEDURE insert_log(
IN LogType INT,
IN LogIdNote INT,
IN LogName VARCHAR(10),
IN LogTime TIMESTAMP,
IN logTypeCategory INT,
IN LogIdUser INT)
begin
...
Edit: Also note that I added a size specifier to the VARCHAR data type, since it requires one. I guessed at 10, but you can replace that value with whatever yours is.

serialising rows in a table

I have a table which contains header information for transactions. The transactions belong to different projects.
In the header I have columns:
rhguid - uniqueidentifier
rhserial - int
rh_projectID - int
First I insert the row (there's more columns)
Then I calculate the serial number for that project:
update responseheader
set rhSerial = 1 + (select isnull(max(rhSerial), 0)
from responseheader
where (rhstatus = 0) AND (rh_projectID = 1234))
where
(rhGUID = <preassignedGUID>);
However when there are many transactions happening at the same time for a project I am finding duplicate rhserial values.
I'm doing this in classic ASP with SQL Server 2008.
Is there a better way?
From your example, it doesn't look like you're using a transaction. My guess is that the SELECT portion of the statement is running as READ UNCOMMITTED, otherwise you would not see duplicates. There are ways to start transactions with ADO, but I prefer using stored procedures instead.
Try implementing something like this:
CREATE PROC dbo.ResponseHeader_Insert
<more data to insert>,
#ProjectID INT,
#Status SMALLINT
as
insert responseheader (column names here)
select <param values here>, isnull(max(rhSerial), 0) + 1
from responseheader
where (rhstatus = #Status) AND (rh_projectID = #ProjectID))
If this doesn't work for ya, try creating sequence tables (one for each sequence).
create table <tablename> (
SeqID int identity(1,1) primary key,
SeqVal varchar(1)
)
Create a procedure to get the next identity:
create procedure GetNewSeqVal_<tablename>
as
begin
declare #NewSeqValue int
set NOCOUNT ON
insert into <tablename> (SeqVal) values ('a')
set #NewSeqValue = scope_identity()
delete from <tablename> WITH (READPAST)
return #NewSeqValue
end
If there are too many sequence tables that need to be created or you want to create sequences on the fly, try this approach:
Create table AllSequences (
SeqName nvarchar(255) primary key, -- name of the sequence
Seed int not null default(1), -- seed value
Incr int not null default(1), -- incremental
Currval int
)
Go
create procedure usp_CreateNewSeq
#SeqName nvarchar(255),
#seed int = 0,
#incr int = 1
as
begin
declare #currval int
if exists (
select 1 from AllSequences
where SeqName = #SeqName )
begin
print 'Sequence already exists.'
return 1
end
if #seed is null set #seed = 1
if #incr is null set #incr = 1
set #currval = #seed
insert into AllSequences (SeqName, Seed, Incr, CurrVal)
values (#SeqName, #Seed, #Incr, #CurrVal)
end
go
create procedure usp_GetNewSeqVal
#SeqName nvarchar(255)
as
begin
declare #NewSeqVal int
set NOCOUNT ON
update AllSequences
set #NewSeqVal = CurrVal = CurrVal+Incr
where SeqName = #SeqName
if ##rowcount = 0 begin
print 'Sequence does not exist'
return
end
return #NewSeqVal
end
go