c# last insert id - c#

I'm using a stored procedure with this sql:
INSERT INTO [dbTblUsers]([strUsername], [strPassword])
VALUES (#p1,#p2);
SELECT ##IDENTITY;
And calling the procedure:
// Insert new user
nId = daUsers.InsertQuery(textBoxUsername.Text, textBoxPassword.Text);
// Insert new Twitter OAuth
daTwitterOAuth.Insert(nId, textBoxConsumerKey.Text, textBoxConsumerSecret.Text, textBoxToken.Text, textBoxTokenSecret.Text);
How do I cast the object ##IDENTITY int the int nId?
Like this?
nId = (int)daUsers.InsertQuery(textBoxUsername.Text, textBoxPassword.Text);

Firstly, don't use ##IDENTTY - use SCOPE_IDENTITY(); the first can give you unexpected answers if there are any triggers involved. Secondly; both of these return decimals; cast it at the call-site, IMO:
SELECT CAST(SCOPE_IDENTITY() as int)

Related

SQL procedure using OUTPUT clause doesn't return value

I have built a procedure which should insert a new row into a table and return its id.
CREATE PROCEDURE [InsertFood]
AS
DECLARE #ID TABLE (foodId INT)
insert into TblFood
OUTPUT INSERTED.foodId INTO #ID(foodId)
default values
select * from #ID
return
When I run this procedure it always returns 0.
REad this MSDN post provide example : Retrieving Identity or Autonumber Values
Example :
CREATE PROCEDURE dbo.InsertCategory
#CategoryName nvarchar(15),
#Identity int OUT
AS
INSERT INTO Categories (CategoryName) VALUES(#CategoryName)
SET #Identity = SCOPE_IDENTITY()
CREATE PROCEDURE [InsertFood]
AS
DECLARE #ID int
--insert data in table Example
----INSERT INTO Production.Location (Name, CostRate, Availability, ModifiedDate)
----VALUES ('Damaged Goods', 5, 2.5, GETDATE());
--insert data in table
select #ID = SCOPE_IDENTITY()
return #ID
You can use Scope_Identity() to get the last value.

How to i get result based on ids list passed as a varchar?

I am passing ids list as a varchar(500) and based upon that ids records are required.My sql code is
declare #Ids varchar(500) = '12964,12965,12966'
select *
from tblBooks
where BookID in (#Ids)
where BookID is varchar(50).Number of Ids can be 100.Converting #Ids into int gives following error
Conversion failed when converting the varchar value
'12964,12965,12966' to data type int
How do i find result as #Id are not converted into Int.
Use a table variable:
DECLARE #Ids TABLE (ID INT);
INSERT #Ids VALUES (12964),(12965),(12966);
SELECT *
FROM tblBooks
WHERE BookID in (SELECT ID FROM #Ids);
If you need to pass this to a procedure then you can use a table valued parameter:
CREATE TYPE dbo.ListOfInt AS TABLE (ID INT);
GO
CREATE PROCEDURE dbo.GetBooks #IDs dbo.ListOfInt READONLY
AS
BEGIN
SELECT *
FROM tblBooks
WHERE BookID in (SELECT ID FROM #Ids);
END
GO
DECLARE #IDs dbo.ListofInt;
INSERT #Ids VALUES (12964),(12965),(12966);
EXECUTE dbo.GetBooks #Ids;
Or From c#
var table = new DataTable();
table.Columns.Add("ID", typeof(int));
// ADD YOUR LIST TO THE TABLE
using (var connection = new SqlConnection("Connection String"))
using (var command = new SqlCommand("dbo.GetBooks", connection))
{
command.CommandType = CommandType.StoredProcedure;
var param = new SqlParameter("#Ids", SqlDbType.Structured);
param.TypeName = "dbo.ListofInt";
param.Value = table;
command.Parameters.Add(table);
connection.Open();
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
// do something
}
}
}
Once the TYPE is in place, you don't even need to use a stored procedure. You can simply call a normal query:
using (var connection = new SqlConnection("Connection String"))
using (var command = new SqlCommand("SELECT * FROM tblBooks WHERE BookID IN (SELECT ID FROM #IDs)", connection))
{
var param = new SqlParameter("#Ids", SqlDbType.Structured);
param.TypeName = "dbo.ListofInt";
param.Value = table;
command.Parameters.Add(table);
connection.Open();
// ETC
}
Doing the split in c# using String.Split() and passing the list to SQL will be more efficient than any approach that does the split in SQL
You can write the query as this:
declare #Ids varchar(500) = '12964,12965,12966'
select *
from tblBooks
where ','+cast(BookID as varchar(500))+',' like '%,'+#Ids+',%';
But you don't want to do that because the performance is bad -- the query cannot use indexes.
Three other options. Use dynamic SQL and plug the list directly into the query. Or use a split function to split the string. Or use a table variable:
declare #ids table (id int);
insert into #ids(id)
select 12964 union all select 12965 union all select 12966;
select b.*
from tblBooks b
where b.BookId in (select id from #ids);
This won't work. SQL Server does not split strings for you implicitly and there is no built in string split function in SQL Server either.
If you are driving this via C# you can use Table value parameters. You can also pass your query through Dapper-Dot-Net which will automatically parameterize an "In" query.
If you really must do this in T-SQL, you can also use a string splitting logic here is a relatively concise one.
SELECT i.value('./text()[1]', 'int') [id] into #ids
FROM( values(CONVERT(xml,'<r>' + REPLACE(#Ids+left(##dbts,0),',','</r><r>') + '</r>')) ) a(_)
CROSS APPLY _.nodes('./r') x(i)
select *
from tblBooks a
join #ids i on i.id = a.bookId
Create this function:
CREATE FUNCTION [dbo].[SplitDelimiterString] (#StringWithDelimiter VARCHAR(8000), #Delimiter VARCHAR(8))
RETURNS #ItemTable TABLE (Item VARCHAR(8000))
AS
BEGIN
DECLARE #StartingPosition INT;
DECLARE #ItemInString VARCHAR(8000);
SELECT #StartingPosition = 1;
--Return if string is null or empty
IF LEN(#StringWithDelimiter) = 0 OR #StringWithDelimiter IS NULL RETURN;
WHILE #StartingPosition > 0
BEGIN
--Get starting index of delimiter .. If string
--doesn't contain any delimiter than it will returl 0
SET #StartingPosition = CHARINDEX(#Delimiter,#StringWithDelimiter);
--Get item from string
IF #StartingPosition > 0
SET #ItemInString = SUBSTRING(#StringWithDelimiter,0,#StartingPosition)
ELSE
SET #ItemInString = #StringWithDelimiter;
--If item isn't empty than add to return table
IF( LEN(#ItemInString) > 0)
INSERT INTO #ItemTable(Item) VALUES (#ItemInString);
--Remove inserted item from string
SET #StringWithDelimiter = SUBSTRING(#StringWithDelimiter,#StartingPosition +
LEN(#Delimiter),LEN(#StringWithDelimiter) - #StartingPosition)
--Break loop if string is empty
IF LEN(#StringWithDelimiter) = 0 BREAK;
END
RETURN
END
Then call it like this:
declare #Ids varchar(500) = '12964,12965,12966'
select *
from tblBooks
where BookID in (SELECT * FROM dbo.SplitDelimiterString(#ids,','))
one way is to cast int to varchar. many other ways....
select *
from tblBooks
where CAST(BookID as varchar(50)) in (#Ids)
related: Define variable to use with IN operator (T-SQL)

must declare the scalar variable '#custid' using dbcontext.Database.SqlQuery?

I am trying to execute stored procedure from bcontext.Database.SqlQuery using EF5.
It is throwing an error must declare the scalar variable '#custid'
var results = _MiscContext.Database.SqlQuery<int>(
"exec sp_GetStaff #custid",
customerNumber).ToList<int>();
SP returns 1 if customerNumber is staff otherwise it return empty row.
ALTER PROCEDURE [dbo].[sp_GetStaff]
#custid varchar(12)
AS
BEGIN
SET NOCOUNT ON;
SELECT
1 AS [C1]
FROM [dbo].[Staff] with (nolock)
WHERE [CUSTOMER_ID] = #custid
END
How to manage this?
Since you're using named parameters, you have to specify the matching name for the parameter you're passing.
var results = _MiscContext.Database.SqlQuery<int>(
"exec sp_GetStaff #custid",
new SqlParameter("custid", customerNumber)).ToList<int>();
Try
var results = _MiscContext.Database.SqlQuery<int>(
"exec sp_GetStaff {0}",
customerNumber).ToList();

Parameters to the EXISTS clause in a stored procedure

I have a table DEPT, which holds 2 columns - ID, NAME.
A search form is presented with the IDs from the DEPT table and the user can chose any number of IDs and submit the form, to get the related NAMEs.
Clarification/Inputs:
I don't want to build a dynamic query - its not manageable.
I prefer a stored procedure using table-valued parameters
Any other solutions to proceed?
NOTE:
This example is simple with 1 table - in real life, I have to deal with more than 6 tables!
Thanks for any suggestions
CREATE TYPE dbo.DeptList
AS TABLE
(
ID INT
);
GO
CREATE PROCEDURE dbo.RetrieveDepartments
#dept_list AS dbo.DeptList READONLY
AS
BEGIN
SET NOCOUNT ON;
SELECT Name FROM dbo.table1 WHERE ID IN (SELECT ID FROM #dept)
UNION ALL
SELECT Name FROM dbo.table2 WHERE ID IN (SELECT ID FROM #dept)
-- ...
END
GO
Now in your C# code, create a DataTable, fill it in with the IDs, and pass it in to the stored procedure. Assuming you already have a list called tempList and the IDs are stored in id:
DataTable tvp = new DataTable();
tvp.Columns.Add(new DataColumn("ID"));
foreach(var item in tempList)
{
tvp.Rows.Add(item.id);
}
using (connObject)
{
SqlCommand cmd = new SqlCommand("StoredProcedure", connObject);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter tvparam = cmd.Parameters.AddWithValue("#dept_list", tvp);
tvparam.SqlDbType = SqlDbType.Structured;
...
}
You can also use a split function. Many exist, this is the one I like if you can guarantee that the input is safe (no <, >, & etc.):
CREATE FUNCTION dbo.SplitInts_XML
(
#List VARCHAR(MAX),
#Delimiter CHAR(1)
)
RETURNS TABLE
AS
RETURN
(
SELECT Item = y.i.value('(./text())[1]', 'int')
FROM
(
SELECT x = CONVERT(XML, '<i>'
+ REPLACE(#List, #Delimiter, '</i><i>') + '</i>').query('.')
) AS a
CROSS APPLY x.nodes('i') AS y(i)
);
GO
Now your procedure can be:
CREATE PROCEDURE dbo.RetrieveDepartments
#dept_list VARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
;WITH d AS (SELECT ID = Item FROM dbo.SplitInts(#dept_list, ','))
SELECT Name FROM dbo.table1 WHERE ID IN (SELECT ID FROM d)
UNION ALL
SELECT Name FROM dbo.table2 WHERE ID IN (SELECT ID FROM d)
-- ...
END
GO

Send a list of IDs to a SQL Server stored procedure from c#

Is it possible to send a list of IDs to a stored procedure from c#?
UPDATE Germs
SET Mutated = ~Mutated
WHERE (GermID IN (ids))
This may be a dirty hack, but you can create a temp table and then join to it from within your stored procedure (assuming they are accessed during the same connection). For example:
CREATE TABLE #ids (id int)
INSERT INTO #ids VALUES ('123') -- your C# code would generate all of the inserts
-- From within your stored procedure...
UPDATE g
SET Mutated = ~Mutated
FROM Germs g
JOIN #ids i ON g.GermID = i.id
You could try what i have made do with:-
Create a function called Split_String
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
CREATE FUNCTION [dbo].[Split_String]
(
#MyString varchar(5000)
)
RETURNS #Results TABLE
(
Value varchar(1000)
)
AS
BEGIN
DECLARE #Pos int
DECLARE #StrLen int
DECLARE #MyLen int
DECLARE #MyVal varchar
SET #pos = 1
SET #MyLen = 1
WHILE #MyString <> ''
BEGIN
SET #MyLen = charindex(',',#MyString)
IF #MyLen = 0 SET #MyLen = Len(#MyString)
INSERT #Results SELECT replace(substring(#MyString, #pos, #MyLen),',','')
SET #MyString = SUBSTRING(#MyString,#MyLen+1,len(#MyString))
END
RETURN
END
Then when you use IN() use in the following fashion with a comma separated string:-
SELECT * FROM [youDataBase].[dbo].[Split_String] (<#MyString, varchar(5000),>)
According to This article, you could try the Table Value Parameter.
Yep, you can use a chunk of XML to build your list of ID's. Then you can use OPENXML and select from that record set.
Look up OPENXML, sp_preparexmldocument, sp_removexmldocument

Categories