Fetch stored procedure value - sql

I have a table RhSeq which contains the following columns:
ScoTable (PK, varchar(20),not NULL)
ScoColonne (PK, varchar(50), not NULL)
ScoSequence (int, not NULL)
ScoDescription (varchar(100), not NULL)
I have a stored procedure which, given ScoTable and ScoColonne, increments ScoSequence and returns the incremented ScoSequence value:
EDITED - Here's the full stored procedure
CREATE PROCEDURE [dbo].[usp_RhSeqNextVal]
#table VARCHAR (20), #colonne VARCHAR (30), #sequence_id INT OUTPUT
AS
SET NOCOUNT ON
SET #sequence_id = -1
DECLARE #transaction AS BIT
SET #transaction = 0;
IF 0 = ##TRANCOUNT
BEGIN
BEGIN TRAN
SET #transaction = 1;
END
UPDATE dbo.RhSeq
SET ScoSequence = CASE WHEN Right(#colonne,1) = '-' THEN
ScoSequence - 1
ELSE
ScoSequence + 1
END
WHERE ScoTable = #table
AND ScoColonne = #colonne
SELECT #sequence_id = ScoSequence
FROM dbo.RhSeq
WHERE ScoTable = #table
AND ScoColonne = #colonne
IF 1 = #transaction
BEGIN
COMMIT TRAN
END
In Visual Studio, if I right click on the stored procedure (in Server Explorer) and choose 'Execute', I enter values for ScoTable and ScoColonne and set sequence_id to null and it executes fine, returning the new incremented sequence_id value. So no problem with the stored procedure.
The problem I have is when I try to get the returned sequence_id inside my code.
SqlParameter param1 = new SqlParameter("#ScoTable", "MyTable");
SqlParameter param2 = new SqlParameter("#ScoColonne", "MyColumn");
SqlParameter param3 = new SqlParameter("#sequence_id", DBNull.Value);
var numeroSequence = db.Database.SqlQuery<RhSeq>("usp_RhSeqNextVal #ScoTable,#ScoColonne, #sequence_id", param1, param2,param3).ToList();
I get an error
System.Data.Entity.Core.EntityCommandExecutionException: A member of the type, 'ScoTable', does not have a corresponding column in the data reader with the same name
From my understanding, the error comes from RhSeq, since the stored procedure returns only sequence_id, which is an int, it cannot create a RhSeq object with it. I try to cast the result to an int, but it's still not working.
How can I store the sequence_id returned by the stored procedure into my var numeroSequence?

Had a similar issue in LinqToSQL. Selecting #sequence_id in the procedure after setting it did the job:
In your SP after:
SELECT #sequence_id = ScoSequence
FROM dbo.RhSeq
WHERE ScoTable = #table
AND ScoColonne = #colonne
Add:
SELECT #sequence_id
And then of course:
db.Database.SqlQuery<int>...

Related

sql procedure returns 1 but vb.net gets 0

I have stored procedure which seems to be working fine when executing directly from management studio, but when it comes o vb.net code i always get 0. Can anyone look at that and tell me what is missing here. I read documentation and seems that should work as expected however it is not somehow.
stored procedure:
ALTER PROCEDURE [dbo].[IsPhraseConnectedAlready]
#PhraseId INT,
#KatSubkatId INT,
#WordId INT,
#SubsubkatId INT = NULL
AS
BEGIN
SET NOCOUNT ON;
DECLARE #temp_T_Html_Word_Categories TABLE(Id INT)
DECLARE #temp_T_Html_WordCat_Phrase TABLE(FK_Phrase_ID INT)
DECLARE #temp_T_Html_Phrase TABLE(Id INT, [Name] varchar(max))
IF #SubsubkatId IS NULL
BEGIN
INSERT INTO #temp_T_Html_Word_Categories(Id) SELECT Id FROM T_Html_Word_Categories WHERE FK_KatSubkat_ID = #KatSubkatId And FK_Word_ID = #WordId And FK_Subsubkat_ID IS NULL;
END
ELSE
BEGIN
INSERT INTO #temp_T_Html_Word_Categories(Id) SELECT Id FROM T_Html_Word_Categories WHERE FK_KatSubkat_ID = #KatSubkatId And FK_Word_ID = #WordId And FK_Subsubkat_ID = #SubsubkatId;
END
Declare #Id int;
Select #Id = Id From #temp_T_Html_Word_Categories;
INSERT INTO #temp_T_Html_WordCat_Phrase(FK_Phrase_ID) SELECT FK_Phrase_ID FROM T_Html_WordCat_Phrase WHERE FK_Word_Categorie_ID = #Id;
IF (##ROWCOUNT > 0)
BEGIN
Declare #FK_Phrase_ID int;
--it makes no difference what you SELECT in an EXISTS sub-query as it is just syntactical sugar. (ie Nothing is actually selected.) SELECT * or SELECT 1 ...
WHILE EXISTS(SELECT * FROM #temp_T_Html_WordCat_Phrase)
BEGIN
Select Top 1 #FK_Phrase_ID = FK_Phrase_ID From #temp_T_Html_WordCat_Phrase;
INSERT INTO #temp_T_Html_Phrase(Id, [Name]) SELECT Id, [Name] FROM T_Html_Phrase WHERE Id = #FK_Phrase_ID;
IF (#PhraseId = #FK_Phrase_ID)
RETURN 1
Delete #temp_T_Html_WordCat_Phrase Where FK_Phrase_ID = #FK_Phrase_ID;
END;
END
ELSE
BEGIN
Delete #temp_T_Html_Word_Categories;
RETURN 0
END
RETURN 0
END
This is my visual basic.net code below:
Public Function IsPhraseConnectedAlready(phraseId As Integer, katsubkatid As Integer, wordid As Integer, subsubkatid As Integer?) As Integer
Using con As New SqlConnection(_strcon)
Using cmd As New SqlCommand("IsPhraseConnectedAlready", con)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("#PhraseId", phraseId)
cmd.Parameters.AddWithValue("#KatSubkatId", katsubkatid)
cmd.Parameters.AddWithValue("#WordId", wordid)
If subsubkatid.HasValue Then 'check whether nullable field contain value
cmd.Parameters.AddWithValue("#SubsubkatId", subsubkatid.Value)
Else
cmd.Parameters.AddWithValue("#SubsubkatId", DBNull.Value)
End If
con.Open()
Dim i = CType(cmd.ExecuteScalar(), Integer)
If i = 1 Then
Return True
ElseIf i = 0 Then
Return False
End If
End Using
End Using
End Function
Executed from ssms directly shows it reaches RETURN 1, however with same values passed from vb.net i am getting 0:
in vb.net working with same values:
seems the resolution was to do like this:
instead of this:
RETURN 1 or RETURN 0
make it as:
SELECT 1 or SELECT 0
however to break execution when it reaches first select to add additional return after each SELECT.
Does anyone sees any issues with that? To me it works and wonder why just RETURN was not from vb.net
cmd.ExecuteScalar() will execute the query, and return the first column of the first row in the result set returned by the query. However, you're not returning a column/row, you're just returning a value.
So, either convert RETURN 1 to SELECT 1 or else declare a return parameter in your VB.Net code like so:
...
Dim returnParameter As SqlParameter = cmd.Parameters.Add("#ReturnVal", SqlDbType.Int)
returnParameter.Direction = ParameterDirection.ReturnValue
con.Open()
cmd.ExecuteNonQuery()
Dim i = CType(returnParameter.Value, Integer)
...

triggers are not firing when I use bulk copy in code

I have a trigger called "updateFriendlyURLTitle" in dbo.Aritcle table. When a individual article inserted, that trigger working fine.
But in article importing process: I've used the following codes. This codes make copy article but it doesn't fire the trigger to generate FriendlyUrl.
private void WriteArticlesToDatabase<TData>(DataSet ds, SqlTableDetails tableDetails, IEnumerable<TData> newArticles, SqlTransaction transaction)
{
var dt = WriteToDataTable(ds, tableDetails.Table, newArticles);
using (var bulkCopy = new SqlBulkCopy(_destConnection, SqlBulkCopyOptions.FireTriggers, transaction))
{
bulkCopy.DestinationTableName = tableDetails.ToString();
bulkCopy.WriteToServer(dt);
}
}
My trigger is like below:
ALTER TRIGGER [dbo].[updateFriendlyURLTitle] ON [dbo].[Articles]
AFTER INSERT, UPDATE
AS
IF ##ROWCOUNT > 0
BEGIN
IF COLUMNS_UPDATED() != 0x0000200000100000 -- columns other than newsCounterViews have been updated
BEGIN
DECLARE #oldestfulllucenebuild AS DATETIME
DECLARE #deletedNewsID INT
DECLARE #newsStatus BIT
DECLARE #maxcalcimp AS FLOAT
DECLARE #insertedCalculatedImportance INT
DECLARE #insertedNormalisedCalculatedImportance INT
DECLARE #insertedSeoURLTitle VARCHAR(255)
select #oldestfulllucenebuild = min(luceneIndexCreatedDate)
from Lucene_Indexes
where luceneIndexType = 'news'
select #oldestfulllucenebuild = dateAdd(year,10,#oldestfulllucenebuild)
select #maxcalcimp = cast(#oldestfulllucenebuild as float) * 48 *100 --the max importance
select #insertedCalculatedImportance = inserted.newsCalculatedImportance,
#insertedNormalisedCalculatedImportance = inserted.newsNormalisedCalculatedImportance,
#insertedSeoURLTitle = inserted.newsSeoURLTitle
from inserted
--if the current statement is updating the importance or seo columns then do not perform this query (so it doesn't get stuck in a loop)
IF (NOT UPDATE(newsCalculatedImportance)) AND (NOT UPDATE(newsNormalisedCalculatedImportance)) AND (NOT UPDATE(newsSeoURLTitle))
OR
--if it is inserting a new record then perform the query
(#insertedCalculatedImportance = 0 AND #insertedNormalisedCalculatedImportance is null AND #insertedSeoURLTitle = '')
BEGIN
update Articles
set newsCalculatedImportance = cast(cast(inserted.newsArticledate as float )*48 + inserted.newsimportance AS int)
, newsNormalisedCalculatedImportance = (1/ #maxcalcimp) * cast(cast(inserted.newsArticledate as float )*48 + inserted.newsimportance AS int)
, newsSeoURLTitle = LEFT(dbo.getSEOURLTitle(inserted.newstitle), 255)
from Articles inner join inserted on
Articles.newsid = inserted.newsid
END
SELECT #deletedNewsID = newsID, #newsStatus = newsStatus
FROM inserted
IF(#newsStatus = 0)
BEGIN
DELETE FROM tbl_DenormalisedNews WHERE newsid = #deletedNewsID
DELETE FROM News_Deleted_DateTime
WHERE NewsID = #deletedNewsID
INSERT INTO News_Deleted_DateTime
VALUES (#deletedNewsID, getDate())
END
ELSE
BEGIN
--news status is 1, remove it from the news_deleted_datetime table if it exists
DELETE FROM News_Deleted_DateTime
WHERE NewsID = #deletedNewsID
END
-- newsImage1 optimisation: if newsImage1 = '' THEN has_image = FALSE ELSE has_image = TRUE
IF UPDATE(newsImage1)
UPDATE Articles SET
has_image = CASE WHEN Articles.newsImage1 = '' THEN CAST(0 AS bit) ELSE CAST(1 AS bit) END
FROM
Articles INNER JOIN inserted ON Articles.newsid = inserted.newsid
END
END
Does anyone knows how to fix this issue ?

get return value from stored procedure without output parameter

I have a vb.net application that inserts records into a db table using a stored procedure that is supposed to return a value. This stored procedure was setup by someone else and initially was linked to a webservice through which my application made the insert and got the return value in the returned xml. I now have access to the db table and not sure how to receive the return value in my vb.net method.
SQl stored procedure snippet;
#urlname varchar(500),
#siteid varchar(16),
#origin varchar(50),
#queryid varchar(25)
AS
SET NOCOUNT ON;
declare #cnt int
declare #serverip varchar(16)
declare #mincnt int
declare #siteservercnt int
select #cnt=COUNT(*) from sites
where urlname=#urlname
if #cnt = 0
begin
insert into sites (urlname,siteid,exported,origin,queryid)
values(#urlname,#siteid,1,#origin,#queryid)
select #siteservercnt = COUNT(*) from siteserverip where siteid=#siteid
if #siteservercnt=0
begin
select top 1 #mincnt=COUNT(*),#serverip=serverip from siteserverip
group by serverip
order by COUNT(*)
select top 1 #mincnt=sitecount,
#serverip=serverip from serveripcounts
order by sitecount
insert into siteserverip values(#siteid,#serverip)
update serveripcounts set sitecount=sitecount+1
where serverip=#serverip
end
end
SELECT siteid from sites
where urlname=#urlname
return
and my vb.net code to do the insert
CommandObj.CommandText = "Getsite"
CommandObj.CommandTimeout = 90
Dim newUrl As String = String.Empty
CommandObj.Parameters.Clear()
Dim m_param As SqlParameter
m_param = CommandObj.Parameters.Add("#urlname", SqlDbType.VarChar, 500)
m_param.Direction = ParameterDirection.Input
m_param.Value = name
m_param = CommandObj.Parameters.Add("#siteid", SqlDbType.VarChar, 16)
m_param.Direction = ParameterDirection.Input
m_param.Value = siteid
m_param = CommandObj.Parameters.Add("#origin", SqlDbType.VarChar, 50)
m_param.Direction = ParameterDirection.Input
m_param.Value = method
m_param = CommandObj.Parameters.Add("#queryId", SqlDbType.VarChar, 25)
m_param.Direction = ParameterDirection.Input
m_param.Value = forumID
Dim recordsAffected As Integer = CommandObj.ExecuteNonQuery
You can use ExecuteScalar to get that value. ExecuteNonQuery returns number of rows affected while you want to get the value generated by last select. You could use ExecuteReader as well but that is useful when your SP might be returning more columns and/or more rows.
'Populate first column and first row value in siteID
Dim siteID As Integer = CommandObj.ExecuteScalar

execute a stored procedure that returns a " completed succesfully " clue

i have a stored procedure
UPDATE tblTime
SET TimeOut = DATEADD(HOUR,8,TimeIn)
WHERE tId =
(
SELECT MAX(tId)
FROM tblTime
WHERE UserId = 3571
)
although there's no question really, in that case if it did succeed in this query
cause even if the field is empty or if it has value,
it will in this case succeed
but i do need it for future other queries... and also ,
in this case i want the C# code to report
not only that it was requesting query to be execute - meaning it did happen,
but to get an actual answer from sql server
as a return value that c# could use or turn into Boolean
i have managed to do somthing about this so i can specify a condition inside sql server stored proc
declare an OUTPUT variable(PARAMETER) then
set its value to say 1 if condition is met and -1 if not
then
in c# set a function as follows
in this example outpout parameter is named ERROR
public static int UpdateTblViaStoredPRoc(string SPname, int UserID)
{
int message = 0;
using (SqlConnection con = new SqlConnection("server=(local);Initial Catalog=****DBNAME HERE***;Integrated Security=True"))
{
con.Open();
SqlCommand cmd = new SqlCommand(SPname, con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#Uid", UserID);
cmd.Parameters.Add("#ERROR", SqlDbType.Int);
cmd.Parameters["#ERROR"].Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery();
message =(int) cmd.Parameters["#ERROR"].Value;
con.Close();
}
return message;
}
stored proc is then allways following the same pattern
declare ERROR parameter, set a condition to output the ERROR accordingly :
ALTER PROCEDURE [dbo].[nameofProc]
#UId Int, #ERROR int OUT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #TimeOtVal varchar(50)
set #TimeOtVal = (SELECT CASE WHEN [TimeOut] IS NULL THEN '' ELSE CONVERT(NVARCHAR,[TimeOut]) END FROM tblTime WHERE tId = ( SELECT MAX(tId) FROM tblTime WHERE UserId = #UId))
IF (#TimeOtVal = '') -- condition for the update
BEGIN -- now action is taken if condition is met
SET NOCOUNT ON;
UPDATE tblTime SET TimeOut = DATEADD(HOUR,8,TimeIn) WHERE tId = ( SELECT MAX(tId) FROM tblTime WHERE UserId = #UId)
SET #ERROR = 1
END
else
BEGIN -- Other wise , if condition isnot met
SET #ERROR = -1
END
END
so it does what you want only if you allowed it by the condition
then reports the action so you can handle it in program code behind .

Stored Procedure Fill Variable with a ResultSet of a Query

I have a little Problem but don't know the Solution!
I have wrote a Stored Procedure. The function of this isn't necessary.
I want to declare a Variable from Type int.
This Variable must get the Value of a SQL Query.
My attempt:
DECLARE #ParentServiceProviderId int = null
SET #ParentServiceProviderId = (SELECT ParentServiceProviderId
FROM ServiceProvider
WHERE ServiceProviderId = #ServiceProviderId)
It didn't work! The ResultSet of the Query have one Row every Time!
I don't know how to solve this Problem!
Here is the complete Stored Procedure:
ALTER PROCEDURE [dbo].[InsertCarmakerPartnership_ChildToParent]
#ServiceProviderId int,
#CarmakerId int,
#ValidFrom datetime,
#ValidTo datetime
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #parentSPPId int, #parentSPPParentId int, #superParentId int, #ParentServiceProviderId int = null
SET #ParentServiceProviderId = (SELECT ParentServiceProviderId
FROM ServiceProvider
WHERE ServiceProviderId = #ServiceProviderId)
DECLARE ServiceProviderParent_Cursor CURSOR FOR
SELECT ServiceProviderId, ParentServiceProviderId
FROM ServiceProvider
WHERE ServiceProviderId = #ParentServiceProviderId
OPEN ServiceProviderParent_Cursor;
FETCH NEXT FROM ServiceProviderParent_Cursor INTO #parentSPPId, #parentSPPParentId
IF (#ParentServiceProviderId is NULL)
BEGIN
SET #superParentId = #ServiceProviderId
EXEC InsertCarmakerPartnership_ParentToChild #superParentId, #CarmakerId, #ValidFrom, #ValidTo;
END
WHILE ##FETCH_STATUS = 0
BEGIN
IF #ServiceProviderId > 0
BEGIN
EXEC InsertCarmakerPartnership_ChildToParent #parentSPPId, #CarmakerId, #parentSPPParentId, #ValidFrom, #ValidTo ;
IF (SELECT COUNT(*) FROM dbo.CarmakerPartnership WHERE ServiceProviderId = #parentSPPId AND CarmakerId = #CarmakerId AND IsDeleted = 0) = 0
BEGIN
INSERT INTO dbo.CarmakerPartnership (CarmakerId, ServiceProviderId, CreatedBy, ChangedBy, ValidityPeriodFrom, ValidityPeriodTo) VALUES (#CarmakerId, #parentSPPId, SYSTEM_USER, SYSTEM_USER, #ValidFrom, #ValidTo)
END
END
FETCH NEXT FROM ServiceProviderParent_Cursor INTO #parentSPPId, #parentSPPParentId
END;
CLOSE ServiceProviderParent_Cursor;
DEALLOCATE ServiceProviderParent_Cursor;
END
Thanks for your help and sorry for my bad english!
Best regards.
Anyway, use next code to populate a variable:
DECLARE #ParentServiceProviderId int
SELECT #ParentServiceProviderId = ParentServiceProviderId
FROM ServiceProvider
WHERE ServiceProviderId = #ServiceProviderId
do not assign default value to this variable and the rest of the code is:
DECLARE #ParentServiceProviderId int
SELECT #ParentServiceProviderId = ParentServiceProviderId
FROM ServiceProvider
WHERE ServiceProviderId = #ServiceProviderId