I have a collection of record ids(x,y,z,..) which is pass to a stored procedure as a string value. My stored procedure is:
CREATE PROCEDURE [dbo].[Sp_Getvalue](#recordId varchar(30))
AS
BEGIN
SET NOCOUNT ON;
-- Insert statements for procedure here
select
x.record_Id,
x.name,
x.address from dbo.tblvalue x where x.record_Id in (#recordId)
END
in code behind
var obj = context.Sp_Getvalue(value);
I am getting error as
An exception of type 'System.Data.EntityCommandExecutionException' occurred in System.Data.Entity.dll but was not handled in user code
You can not use the parameter directly in IN clause
Please check the following syntax where I used a SQL split string function
CREATE PROCEDURE [dbo].[Sp_Getvalue](#recordId varchar(30))
AS
BEGIN
SET NOCOUNT ON;
select
x.record_Id,
x.name,
x.address
from dbo.tblvalue x
where
x.record_Id in (
select val from dbo.split(#recordId,',')
)
END
You can copy the split function codes from here: http://www.kodyaz.com/articles/t-sql-convert-split-delimeted-string-as-rows-using-xml.aspx
and create on your target database
You cannot directly use the comma separated values in IN clause and no need of any create any functions for that. There are two approaches to do that
1. Use Dynamic Sql to get records according to values in #recordId
CREATE PROCEDURE [dbo].[Sp_Getvalue](#recordId varchar(30))
AS
BEGIN
SET NOCOUNT ON;
DECLARE #query NVARCHAR(MAX)
SET #query = 'INSERT INTO TABLETOINSERT(COL,COL2,COL3)
SELECT record_Id,name,address
FROM tblvalue
WHERE record_Id IN('+#recordId+')'
EXEC SP_EXECUTESQL #query
END
Click here to view result
If you do not want to insert, and just want select statement, remove the
INSERT INTO TABLETOINSERT(COL,COL2,COL3) from the dynamic sql.
2. Using XML format to split comma separated values to row and using IN
CREATE PROCEDURE [dbo].[Sp_Getvalue](#recordId varchar(30))
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO TABLETOINSERT(COL1,COL2,COL3)
SELECT record_Id,NAME,[ADDRESS]
FROM tblvalue
WHERE record_Id IN
(
-- Convert comma separated values to rows
SELECT LTRIM(RTRIM(Split.a.value('.', 'VARCHAR(100)'))) 'KeyWords'
FROM
(
SELECT CAST ('<M>' + REPLACE(#recordId, ',', '</M><M>') + '</M>' AS XML) AS Data
) AS A
CROSS APPLY Data.nodes ('/M') AS Split(a)
)
END
Click here to view result
Related
I have a list of CheckBoxes:
List<CheckBox> checkBoxes = new List<CheckBox>();
I want to update it via a stored procedure, so I have:
private void btnSave_Click(object sender, EventArgs e)
{
SQLConnMgr db = new SQLConnMgr();
foreach (var c in checkBoxes)
{
db.ExeSQL($"exec test #CheckBoxName = {c.Name}, #CheckBoxValue = {c.Checked} ");
}
}
Stored procedure:
CREATE OR ALTER PROCEDURE test
-- Add the parameters for the stored procedure here
#CheckBoxName VARCHAR(255),
#CheckBoxValue BIT
AS
BEGIN
SET NOCOUNT ON;
-- Insert statements for procedure here
UPDATE MyTable SET #CheckBoxName = #CheckBoxValue
END
My question is: is there another way to do this? Like sending multiple petitions in the foreach statement instead of only one at a time?
UPDATE
So to be more clear every bool is a column so I need something like:
DECLARE #CurrentCheckboxName VARCHAR(255) = (SELECT
[CheckBoxName]
FROM #CheckBoxList)
UPDATE [m]
SET
#CurrentCheckboxName = [c].[CheckBoxValue]
FROM [RedMarkItems] [m]
JOIN #CheckBoxList [c] ON [c].[CheckBoxName] = #CurrentCheckboxName
but how can iterate on each checkboxName in my DECLARE?
Depending on the version of SQL Server you are using, you could use a TABLE parameter type for your stored proc and call it only once.
CREATE TYPE dbo.MyCheckBoxValues AS TABLE(
CheckBoxName VARCHAR(255) NOT NULL,
CheckBoxValue BIT NOT NULL )
Then you modify your stored proc to use the type.
CREATE OR ALTER PROCEDURE test
-- Add the parameters for the stored procedure here
#CheckBoxList MyCheckBoxValues READONLY
AS
BEGIN
SET NOCOUNT ON;
-- Insert statements for procedure here
UPDATE m SET CheckBoxValue=c.CheckBoxValue
FROM MyTable m
JOIN #CheckBoxList c ON c.CheckBoxName=m.CheckBoxName
END
You can also use Dynamic SQL in your stored proc. For Each checkboxValues :
DECLARE #Query nvarchar(max);
SET #Query = 'UPDATE Table SET ' + #CheckboxName + '='+ #CheckBoxValue;
exec sp_executeSql #Query
Then you only have to get the values in your code.
Something like this should do it.
StringBuilder builder = new StringBuilder();
builder.Append("DECLARE #MyCheckboxes MyCheckBoxValues; ");
foreach (Guid id in _equipmentToMerge)
{
builder.Append(String.Format("INSERT INTO #MyCheckboxes (CheckBoxName, CheckBoxValue) VALUES ('{0}',{1}); ", name, ischecked));
}
builder.Append("exec dbo.test #MyCheckboxes ");
I think there is a problem with your Update statement in your stored procedure. Could you change it thusly?
Update MyCheckBoxValues SET CheckBoxValue = #CheckBoxValue Where CheckBoxName = #CheckBoxName
I don't know why you want to complicate things. Use a single connection for the loop and I can't imagine that you could have a prohibitive number of check boxes on your form. If it is still too slow, get rid of entity framework or whatever orm you are using and try dealing with the server directly.
I am using Entity Framework 6 and Microsoft SQL Server 2012.
Here is my stored procedure:
ALTER PROCEDURE SPDeleteRegion
#siteId int,
#regionId int
AS
BEGIN
SET NOCOUNT ON;
DECLARE #isDeleted BIT
IF EXISTS (SELECT 1 FROM SiteObjects WHERE SiteRegionId = #regionId)
BEGIN
SET #isDeleted = 0 ; --not deleted
RETURN #isDeleted;
END
ELSE
BEGIN
--do what needs to be done if not
DELETE FROM SiteRegions
WHERE Id = #regionId;
SET #isDeleted = 1; -- deleted
RETURN #isDeleted;
END
END
Here how I call the stored procedure in C#:
var t = _context.Database.SqlQuery<bool>("SPDeleteRegion #siteId, #regionId",
new SqlParameter("#siteId", siteId),
new SqlParameter("#regionId", regionId));
On the line of code above I get this exception:
The data reader has more than one field. Multiple fields are not valid for EDM primitive or enumeration types.
Any idea why I get the excewption and how to fix it?
Your procedure doesn't selecting anything. Change it like this:
ALTER PROCEDURE SPDeleteRegion
-- Add the parameters for the stored procedure here
#siteId int,
#regionId int
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE
#isDeleted BIT
IF EXISTS (SELECT 1 FROM SiteObjects WHERE SiteRegionId = #regionId)
BEGIN
SET #isDeleted = 0 ; --not deleted
SELECT #isDeleted [IsDeleted]; --HERE
END
ELSE
BEGIN
--do what needs to be done if not
DELETE FROM SiteRegions WHERE Id = #regionId;
SET #isDeleted = 1;--deleted
SELECT #isDeleted [IsDeleted]; -- AND HERE
END
END
I need to run three Insert queries in SQL Server 2008 via stored procedure and expected three OUTPUT values to read in C#. In following Stored Procedure, my first query only runs and remain I am getting Null error
Cannot insert the value NULL into column
'AssessmentElectronicSignatureID'
USE [myDB]
GO
/****** Object: StoredProcedure [dbo]. [p_assessment_dfn_statementAnswer_insert] Script Date: 10/05/2015 13:24:22 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[p_assessment_dfn_statementAnswer_insert]
#StatementID AS bigint,
#StaffID AS int,
#AssessmentID As bigint,
#StatementText AS nvarchar(MAX),
#StatementDate AS Date,
#StatementAnswerID AS bigint OUTPUT,
--
#SignatureCheck AS bit,
#SignatureDate AS Date,
#ElectronicSignatureID AS bigint OUTPUT,
--
#AssessmentElectronicSignatureID AS bigint OUTPUT
AS
SET NOCOUNT ON
SET XACT_ABORT ON
-- local variables
DECLARE #l_object AS SYSNAME = OBJECT_NAME(##PROCID)
,#l_error_msg AS NVARCHAR(2000)
BEGIN TRY
BEGIN TRAN
INSERT INTO [adb_TestDb].[dbo].[Assessment_Statement_Answer]
([StatementID],[StaffID],[AssessmentID],[StatementText],[Date])
VALUES (#StatementID, #StaffID, #AssessmentID, #StatementText, #StatementDate)
SELECT #StatementAnswerID = SCOPE_IDENTITY();
IF(#StatementAnswerID>0)
BEGIN
INSERT INTO [adb_TestDb].[dbo].[Assessment_ElectronicSignature]([AssessmentID],[ElectronicSignatureCheck],[SignatureDateAndTime])
VALUES (#AssessmentID, #SignatureCheck,#SignatureDate)
SELECT #ElectronicSignatureID = SCOPE_IDENTITY();
END
IF(#ElectronicSignatureID>0)
BEGIN
INSERT INTO [adb_TestDb].[dbo].[AssessorSignature]([AssessmentElectronicSignatureID],[StatementAnswerID],[AssessorID])
VALUES(#ElectronicSignatureID, #StatementAnswerID, #AssessmentID)
SELECT #AssessmentElectronicSignatureID = SCOPE_IDENTITY();
END
COMMIT TRAN
--RETURN SCOPE_IDENTITY();
END TRY
BEGIN CATCH
-- rollback any open/uncomitted transactions
IF XACT_STATE() IN ( -1, 1) ROLLBACK TRANSACTION
-- return an error containing the object, error number and error description
SELECT #l_error_msg = 'Error number : ' + CAST(ERROR_NUMBER()AS VARCHAR) + '. ' + ERROR_MESSAGE()
RAISERROR (#l_error_msg,16,1)
END CATCH
There is a known bug with SCOPE_IDENTITY(); Occurs occasionally when triggers are used. Google for the occurances if you want to dig deep. Or...
Try changing things like
SELECT #StatementAnswerID = SCOPE_IDENTITY();
to
SELECT #StatementAnswerID = ##IDENTITY;
Or
SET #StatementAnswerID = ##IDENTITY;
and other similar assignments. I think the problem here is causing because of being the #StatementAnswerID as Null.
I had made a dynamic stored procedure like this
CREATE PROCEDURE [dbo].[MyProcedure]
#pSelect nvarchar(max)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQL nvarchar(max)
SET #SQL = 'select ' + #pSelect + ' from tabel1';
EXEC (#SQL)
END
And on updating my entitydatamodel the in context.cs the above stored procedure is in the form of
virtual int MyProcedure(string pSelect)
{
var pSelectParameter = pSelect != null ?
new ObjectParameter("pSelect", pSelect) :
new ObjectParameter("pSelect", typeof(string));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction("MyProcedure", pSelectParameter);
}
on calling the stored procedure from c# code
var result = myDataModel.MyProcedure("Select * From table1").tolist();
the above code is showing error because MyProcedure is returning a integer return type
so how could i set the return type of the stored procedure according to tje select query I am passing to it
HOW DO I MODIFY MY STORED PROCEDURE SO THAT ITS RETURN TYPE IS OF ANY SPECIFIC TABLE TYPE
In this case you have to trick the code.
CREATE PROCEDURE [dbo].[MyProcedure]
#pSelect nvarchar(max)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQL nvarchar(max)
SET #SQL = 'select ' + #pSelect + ' from tabel1';
EXEC (#SQL)
--Remove the below line once you have added the stored procedure to the dbml file.
select * from table1
END
After creating the sp, drag and drop to the c# dbml file. then you can alter the sp by removing the line " select * from table1".
NOTE : if you dont have those columns in the table1, the direct values(any datatype) in the select statement like "select 1 as colmumn1, 'string' as colmumn2, cast('10/01/1900' as datetime) as colmumn3 from table1"
just add # sign in your parameter.
var pSelectParameter = pSelect != null ?
new ObjectParameter("#pSelect", pSelect) :
new ObjectParameter("#pSelect", typeof(string));
may be this should work and i believe your are passing only column name in this parameter.
I have an application right now that has special user roles hardwired into the executable. It is tamper proof, but is a bit of a mess when it comes to new hires, role changes, etc.
So, I want to create a stored procedure that can return the appropriate employee badge numbers for any given operation.
My expertise is in C# development, but I am also the guy who works on the SQL Server (2000) database.
Here is what I'm starting out with, but T-SQL does not like this at all!
CREATE PROCEDURE sp1_GetApprovalBadges(#operation varchar(50)) as
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from interfering with SELECT statements.
SET NOCOUNT ON;
declare #op varchar(50);
declare #num varchar(50);
declare #table table (NUM varchar(50) null);
select #op=upper(#operation);
case
when #op='CLERK' then
insert into #table (NUM) values (#num) where #num in ('000988','001508','003790','007912') end
when #op='HRMANAGER' then
insert into #table (NUM) values (#num) where #num in ('003035') end
when #op='HUMANRESOURCES' then
insert into #table (NUM) values (#num) where #num in ('002864','005491') end
when #op='INFORMATIONTECHNOLOGY' then
insert into #table (NUM) values (#num) where #num in ('001258','003423','007135','007546') end
end;
SELECT NUM from #table order by NUM;
END
GO
I realize this is very much like code that I write and is not database related, but having the database there affords me a great way to store and execute some scripts that I can modify as needed to keep my application working.
I see at least two issues
Replace case with if elses
execute table variables using dynamic sql
for example
if #op='CLERK'
begin
exec 'insert into ' + #table + '(NUM) values (' + #num + ') where' + #num + 'in (''000988'',''001508',''003790',''007912'')'
end
else if #op='HRMANAGER'
begin
i-- see above
end
else if #op='HUMANRESOURCES'
begin
-- see above
end
else if #op='INFORMATIONTECHNOLOGY'
begin
-- see above
end
exec 'SELECT NUM from' + #table + 'order by NUM;'
Syntax may not be exact, but the idea will work
CASE is an EXPRESSION that returns a single value. You can't use it for control-of-flow logic like you're attempting. Based on the conditions (hard-coded sets of strings) you probably meant something like this (quietly glazing over several other problems with the syntax you've attempted):
...
SELECT #op=upper(#operation);
IF #op = 'CLERK'
BEGIN
INSERT #table (NUM)
SELECT '000988'
UNION ALL SELECT '001508'
UNION ALL SELECT '003790'
UNION ALL SELECT '007912';
END
IF #op = 'HRMANAGER'
BEGIN
INSERT #table (NUM)
SELECT '003035';
END
IF #op = 'HUMANRESOURCES'
BEGIN
INSERT #table (NUM)
SELECT '002864'
UNION ALL SELECT '005491';
END
IF #op = 'INFORMATIONTECHNOLOGY'
BEGIN
INSERT #table (NUM)
SELECT '001258'
UNION ALL SELECT '003423'
UNION ALL SELECT '007135'
UNION ALL SELECT '007546'
END
SELECT NUM from #table order by NUM;
...