Stored Procedure for Account Creation/Update/Delete/Authenticate - c#

I'm new to developing stored procedures so in my attempt I got a bit mind-boggled. I understand basically what they are conceptually, but having issues when implementing. For reference, I'm hand-coding, but intend to use SQL Server, ASP.NET, and C# technologies.
The basic idea is for a user to create their own user account, update their information as they see fit, delete their account, and authenticate the information as necessary (usernames&passwords, account information, etc). I presume this must be done with 4 different stored procedures: createAccount, modAccount, delAccount, authentAccount.
My understanding is that the C#/ASP should be doing the actual data collection and then transferring the data to SQL for insertion into the database. Please correct me if I'm wrong or if there's a more efficient method (speed is extremely important for this).
Getting started with the first stored procedure (create), I coded this:
CREATE PROC createAccount
AS
INSERT INTO Customer (cssn, first_name, middle_name, last_name, company, address, phone_number, email, account, occupation, nationality, social, successful_invites)
VALUES ()
GO
What do I put in for values? The variable that's used on the C# side?
I'm also not sure how I should incorporate security in this space and security is going to be important as well.
If you could provide examples with your explanation, that would be EXTREMELY helpful.

Here's the basic form of your SP (first 3 columns shown):
create procedure createAccount
(
#cssn varchar(100),
#first_name varchar(100),
#last_name varchar(100),
... -- remaining columns
)
as
begin
insert into Customer (cssn, first_name, last_name, ... )
values (#cssn, #first_name, #last_name, ... )
end

One side note, ASP has user accounts built in and set up automatically if you want to just use those (SqlMembershipProvider).
CREATE PROCEDURE createAccount
#cssn VARCHAR(100)
, #first_name VARCHAR(100)
, #middle_name VARCHAR(100)
, #last_name VARCHAR(100)
, #company VARCHAR(100)
, #address VARCHAR(150)
, #phone_number VARCHAR(20)
, #email VARCHAR(100)
, #account VARCHAR(100)
, #occupation VARCHAR(100)
, #nationality VARCHAR(100)
, #social VARCHAR(100)
, #successful_invites INT
AS
BEGIN
INSERT INTO Customer ( cssn, first_name, middle_name, last_name, company, address, phone_number, email, account, occupation, nationality, social, successful_invites )
VALUES ( #cssn, #first_name, #middle_name, #last_name, #company, #address, #phone_number, #email, #account, #occupation, #nationality, #social, #successful_invites )
END
I just guessed at the data types. As for security, the only thing you need to add is re-validation rules (i.e. blocking of HTML tags and stuff in your VARCHAR fields). Otherwise, security is built-in automatically because you are using parameters and variables (and not using dynamic sql).

If you want to use SqlMembershipProvider, you have already in asp.net a set of controls that will help you. You may have to use their tables and not your Customer table, but that is ok since the membership provider will take care of everything. Just google for more info about membership provider and the login controls.
You have in other answers examples of stored procedures, but why using stored procedures? An ORM is a much easier and more productive way of doing things. My favorite is NHiberntate. LINQ to SQL, Entity Framework are from Microsoft. Just google for a "linq to sql hello world" to see how it's done.
In 99.99% of the cases an ORM is just fine.There are rare cases when you need to replace the ORM with a sql query or sp.

Stored procedures are nice ways to store SQL scripts in a central location among other things. That's the basic, most simplest concept. If you have a script in your code with (update TABLE set EMAIL = '"+email+"'), you're better off putting into a stored procedure. You can even do additions and updates in the same procedure returning the ID of the existing/updated or newly created record. You can get VERY creative with them.
You can do updates and additions in the same procedure if it's secure of course.
create usp_AddEmail(
#email varchar(50)
)
AS
DECLARE #EMAILID INT;
SET #EMAILID = (SELECT ID FROM TABLE WHERE EMAIL = #EMAIL);
IF ISNULL(#EMAILID,0) = 0
BEGIN
INSERT INTO TABLE(EMAIL) VALUES(#email);
SET #EMAILID = (SELECT ID FROM TABLE WHERE EMAIL = #EMAIL);
END
SELECT #EMAILID AS EMAILID
In C#, you use CommandType = CommandType.StoredProcedure to let it know it's a stored procedure. Then you use .Parameters.AddWithValue(sqlParameter, value) to pass the value. (You can wrap it into a method):
SqlConnection connLoc = new SqlConnection(YourConnectionSring);
SqlCommand commLoc = new SqlCommand();
SqlDataReader drLoc;
commLoc.Connection = connLoc;
commLoc.CommandType = CommandType.StoredProcedure;
commLoc.CommandText = "usp_AddEmail";
commLoc.Parameters.AddWithValue(#email, emailString);
connLoc.Open();
drLoc = commLoc.ExecuteReader(CommandBehavior.CloseConnection);

Related

Stored Procedure for Employee Clock table

I have an Employee Clock table with these columns:
EmpID nvarchar(200) (FK)
EmpName nvarchar(100)
Password nvarchar(100)
punchTime datetime
punchType bit
I am going to design an application (in C#) that lets employees check in and check out.
The process will be: when an employee wants to check in, they will input their EmpID and Password, then hit Enter. In the backend, the app will run a stored procedure that enters the values of EmpID, Password, EmpName (will be retrieved from Employee table based on EmpID), punchTime and punchType (= 1 for Check In, 0 for Check Out).
The process of checking out is exactly same as checking in, the employee will just need to enter their EmpID and Password, then hit Enter.
I am looking for a stored procedure that could do something like:
when keyEnter.hit (from C#) => run the stored procedure:
if max(EmpID) has punch = 1 (the employee already checked in), then set punch = 0 with provided punchTime and EmpID
else if max(EmpID) has punch = 0 (the employee already checked out), then set punch = 1 with punchTime and EmpID
I have been messing around with the stored procedure, but did not get the result as I wanted. I appreciate any help.
Having worked on a clock in/out system, I can warn you now that it is not as simple as you think. If a user misses a clock in or out, you will have to manually insert a new record and then correct all the punch types after that point in time... get ready to write that stored procedure before you move to production! Also, I am going to ignore the odd format of the EmployeeClock table - why are you storing the password in it? Regardless, your question is about a stored procedure so let's deal with that.
I assume that there is an Employee table that stores the name and the password. The password should be validated before any record is created in the EmployeeClock so I will do that. Next, you should see if there is an existing record in EmployeeClock for the employee - it could be the first time they ever log in. Finally, if there is an existing record in EmployeeClock, create a new record and flip the bit for the punchType. Finally, you may want to return a result so you know whether it was successful or not. Additionally, you may want to log the information from a bad attempt somewhere (which I will not show). Putting this all together:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE dbo.EmployeeClockInOut
#EmpID NVARCHAR(200),
#Password NVARCHAR(100)
AS
BEGIN
SET NOCOUNT ON;
-- you should make sure that the employee password is
-- correct before you do anything... assume you have a
-- Employee table that you can look up
IF EXISTS(SELECT 1 FROM dbo.Employee WHERE EmpId = #EmpID AND [Password] = #Password)
BEGIN
-- have they ever clocked in?
IF EXISTS(SELECT 1 FROM dbo.EmployeeClock WHERE EmpID = #EmpID)
BEGIN
-- they have clocked in at least once - flip the punch type
-- from their last clock in
INSERT INTO dbo.EmployeeClock(EmpID, EmpName, [Password], punchTime, punchType)
SELECT TOP(1) #EmpID, e.EmpName, #Password, GETDATE(),
CASE WHEN c.punchType = 1 THEN 0 ELSE 1 END
FROM dbo.Employee AS e
INNER JOIN dbo.EmployeeClock AS c ON e.EmpID = c.EmpID
WHERE e.EmpID = #EmpID
ORDER BY c.punchTime DESC;
END
ELSE
BEGIN
-- there is no clock in record - create first clock in entry
INSERT INTO dbo.EmployeeClock(EmpID, EmpName, [Password], punchTime, punchType)
SELECT #EmpID, EmpName, #Password, GETDATE(), 1 FROM dbo.Employee WHERE EmpID = #EmpID
END
SELECT 'Clock in/out successful' AS [Result];
END
ELSE
BEGIN
-- log the attempt or alert the user...
SELECT 'EmpID or Password was invalid' AS [Result];
END
END
GO

SQL Server stored procedure parameter type array C# [duplicate]

How to pass an array into a SQL Server stored procedure?
For example, I have a list of employees. I want to use this list as a table and join it with another table. But the list of employees should be passed as parameter from C#.
SQL Server 2016 (or newer)
You can pass in a delimited list or JSON and use STRING_SPLIT() or OPENJSON().
STRING_SPLIT():
CREATE PROCEDURE dbo.DoSomethingWithEmployees
#List varchar(max)
AS
BEGIN
SET NOCOUNT ON;
SELECT value FROM STRING_SPLIT(#List, ',');
END
GO
EXEC dbo.DoSomethingWithEmployees #List = '1,2,3';
OPENJSON():
CREATE PROCEDURE dbo.DoSomethingWithEmployees
#List varchar(max)
AS
BEGIN
SET NOCOUNT ON;
SELECT value FROM OPENJSON(CONCAT('["',
REPLACE(STRING_ESCAPE(#List, 'JSON'),
',', '","'), '"]')) AS j;
END
GO
EXEC dbo.DoSomethingWithEmployees #List = '1,2,3';
I wrote more about this here:
Handling an unknown number of parameters in SQL Server
Ordered String Splitting in SQL Server with OPENJSON
SQL Server 2008 (or newer)
First, in your database, create the following two objects:
CREATE TYPE dbo.IDList
AS TABLE
(
ID INT
);
GO
CREATE PROCEDURE dbo.DoSomethingWithEmployees
#List AS dbo.IDList READONLY
AS
BEGIN
SET NOCOUNT ON;
SELECT ID FROM #List;
END
GO
Now in your C# code:
// Obtain your list of ids to send, this is just an example call to a helper utility function
int[] employeeIds = GetEmployeeIds();
DataTable tvp = new DataTable();
tvp.Columns.Add(new DataColumn("ID", typeof(int)));
// populate DataTable from your List here
foreach(var id in employeeIds)
tvp.Rows.Add(id);
using (conn)
{
SqlCommand cmd = new SqlCommand("dbo.DoSomethingWithEmployees", conn);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter tvparam = cmd.Parameters.AddWithValue("#List", tvp);
// these next lines are important to map the C# DataTable object to the correct SQL User Defined Type
tvparam.SqlDbType = SqlDbType.Structured;
tvparam.TypeName = "dbo.IDList";
// execute query, consume results, etc. here
}
SQL Server 2005
If you are using SQL Server 2005, I would still recommend a split function over XML. First, create a function:
CREATE FUNCTION dbo.SplitInts
(
#List VARCHAR(MAX),
#Delimiter VARCHAR(255)
)
RETURNS TABLE
AS
RETURN ( SELECT Item = CONVERT(INT, Item) FROM
( SELECT Item = x.i.value('(./text())[1]', 'varchar(max)')
FROM ( SELECT [XML] = CONVERT(XML, '<i>'
+ REPLACE(#List, #Delimiter, '</i><i>') + '</i>').query('.')
) AS a CROSS APPLY [XML].nodes('i') AS x(i) ) AS y
WHERE Item IS NOT NULL
);
GO
Now your stored procedure can just be:
CREATE PROCEDURE dbo.DoSomethingWithEmployees
#List VARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
SELECT EmployeeID = Item FROM dbo.SplitInts(#List, ',');
END
GO
And in your C# code you just have to pass the list as '1,2,3,12'...
I find the method of passing through table valued parameters simplifies the maintainability of a solution that uses it and often has increased performance compared to other implementations including XML and string splitting.
The inputs are clearly defined (no one has to guess if the delimiter is a comma or a semi-colon) and we do not have dependencies on other processing functions that are not obvious without inspecting the code for the stored procedure.
Compared to solutions involving user defined XML schema instead of UDTs, this involves a similar number of steps but in my experience is far simpler code to manage, maintain and read.
In many solutions you may only need one or a few of these UDTs (User defined Types) that you re-use for many stored procedures. As with this example, the common requirement is to pass through a list of ID pointers, the function name describes what context those Ids should represent, the type name should be generic.
Based on my experience, by creating a delimited expression from the employeeIDs, there is a tricky and nice solution for this problem. You should only create an string expression like ';123;434;365;' in-which 123, 434 and 365 are some employeeIDs. By calling the below procedure and passing this expression to it, you can fetch your desired records. Easily you can join the "another table" into this query. This solution is suitable in all versions of SQL server. Also, in comparison with using table variable or temp table, it is very faster and optimized solution.
CREATE PROCEDURE dbo.DoSomethingOnSomeEmployees #List AS varchar(max)
AS
BEGIN
SELECT EmployeeID
FROM EmployeesTable
-- inner join AnotherTable on ...
where #List like '%;'+cast(employeeID as varchar(20))+';%'
END
GO
Use a table-valued parameter for your stored procedure.
When you pass it in from C# you'll add the parameter with the data type of SqlDb.Structured.
See here: http://msdn.microsoft.com/en-us/library/bb675163.aspx
Example:
// Assumes connection is an open SqlConnection object.
using (connection)
{
// Create a DataTable with the modified rows.
DataTable addedCategories =
CategoriesDataTable.GetChanges(DataRowState.Added);
// Configure the SqlCommand and SqlParameter.
SqlCommand insertCommand = new SqlCommand(
"usp_InsertCategories", connection);
insertCommand.CommandType = CommandType.StoredProcedure;
SqlParameter tvpParam = insertCommand.Parameters.AddWithValue(
"#tvpNewCategories", addedCategories);
tvpParam.SqlDbType = SqlDbType.Structured;
// Execute the command.
insertCommand.ExecuteNonQuery();
}
You need to pass it as an XML parameter.
Edit: quick code from my project to give you an idea:
CREATE PROCEDURE [dbo].[GetArrivalsReport]
#DateTimeFrom AS DATETIME,
#DateTimeTo AS DATETIME,
#HostIds AS XML(xsdArrayOfULong)
AS
BEGIN
DECLARE #hosts TABLE (HostId BIGINT)
INSERT INTO #hosts
SELECT arrayOfUlong.HostId.value('.','bigint') data
FROM #HostIds.nodes('/arrayOfUlong/u') as arrayOfUlong(HostId)
Then you can use the temp table to join with your tables.
We defined arrayOfUlong as a built in XML schema to maintain data integrity, but you don't have to do that. I'd recommend using it so here's a quick code for to make sure you always get an XML with longs.
IF NOT EXISTS (SELECT * FROM sys.xml_schema_collections WHERE name = 'xsdArrayOfULong')
BEGIN
CREATE XML SCHEMA COLLECTION [dbo].[xsdArrayOfULong]
AS N'<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="arrayOfUlong">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded"
name="u"
type="xs:unsignedLong" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>';
END
GO
Context is always important, such as the size and complexity of the array. For small to mid-size lists, several of the answers posted here are just fine, though some clarifications should be made:
For splitting a delimited list, a SQLCLR-based splitter is the fastest. There are numerous examples around if you want to write your own, or you can just download the free SQL# library of CLR functions (which I wrote, but the String_Split function, and many others, are completely free).
Splitting XML-based arrays can be fast, but you need to use attribute-based XML, not element-based XML (which is the only type shown in the answers here, though #AaronBertrand's XML example is the best as his code is using the text() XML function. For more info (i.e. performance analysis) on using XML to split lists, check out "Using XML to pass lists as parameters in SQL Server" by Phil Factor.
Using TVPs is great (assuming you are using at least SQL Server 2008, or newer) as the data is streamed to the proc and shows up pre-parsed and strongly-typed as a table variable. HOWEVER, in most cases, storing all of the data in DataTable means duplicating the data in memory as it is copied from the original collection. Hence using the DataTable method of passing in TVPs does not work well for larger sets of data (i.e. does not scale well).
XML, unlike simple delimited lists of Ints or Strings, can handle more than one-dimensional arrays, just like TVPs. But also just like the DataTable TVP method, XML does not scale well as it more than doubles the datasize in memory as it needs to additionally account for the overhead of the XML document.
With all of that said, IF the data you are using is large or is not very large yet but consistently growing, then the IEnumerable TVP method is the best choice as it streams the data to SQL Server (like the DataTable method), BUT doesn't require any duplication of the collection in memory (unlike any of the other methods). I posted an example of the SQL and C# code in this answer:
Pass Dictionary to Stored Procedure T-SQL
As others have noted above, one way to do this is to convert your array to a string and then split the string inside SQL Server.
As of SQL Server 2016, there's a built-in way to split strings called
STRING_SPLIT()
It returns a set of rows that you can insert into your temp table (or real table).
DECLARE #str varchar(200)
SET #str = "123;456;789;246;22;33;44;55;66"
SELECT value FROM STRING_SPLIT(#str, ';')
would yield:
value
-----
123
456
789
246
22
33
44
55
66
If you want to get fancier:
DECLARE #tt TABLE (
thenumber int
)
DECLARE #str varchar(200)
SET #str = "123;456;789;246;22;33;44;55;66"
INSERT INTO #tt
SELECT value FROM STRING_SPLIT(#str, ';')
SELECT * FROM #tt
ORDER BY thenumber
would give you the same results as above (except the column name is "thenumber"), but sorted. You can use the table variable like any other table, so you can easily join it with other tables in the DB if you want.
Note that your SQL Server install has to be at compatibility level 130 or higher in order for the STRING_SPLIT() function to be recognized. You can check your compatibility level with the following query:
SELECT compatibility_level
FROM sys.databases WHERE name = 'yourdatabasename';
Most languages (including C#) have a "join" function you can use to create a string from an array.
int[] myarray = {22, 33, 44};
string sqlparam = string.Join(";", myarray);
Then you pass sqlparam as your parameter to the stored procedure above.
This will help you. :) Follow the next steps,
Open the Query Editor
Copy Paste the following code as it is, it will create the Function which converts the String to Int
CREATE FUNCTION dbo.SplitInts
(
#List VARCHAR(MAX),
#Delimiter VARCHAR(255)
)
RETURNS TABLE
AS
RETURN ( SELECT Item = CONVERT(INT, Item) FROM
( SELECT Item = x.i.value('(./text())[1]', 'varchar(max)')
FROM ( SELECT [XML] = CONVERT(XML, '<i>'
+ REPLACE(#List, #Delimiter, '</i><i>') + '</i>').query('.')
) AS a CROSS APPLY [XML].nodes('i') AS x(i) ) AS y
WHERE Item IS NOT NULL
);
GO
Create the Following stored procedure
CREATE PROCEDURE dbo.sp_DeleteMultipleId
#List VARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
DELETE FROM TableName WHERE Id IN( SELECT Id = Item FROM dbo.SplitInts(#List, ','));
END
GO
Execute this SP Using exec sp_DeleteId '1,2,3,12' this is a string of Id's which you want to delete,
You can convert your array to string in C# and pass it as a Stored Procedure parameter as below,
int[] intarray = { 1, 2, 3, 4, 5 };
string[] result = intarray.Select(x=>x.ToString()).ToArray();
 
SqlCommand command = new SqlCommand();
command.Connection = connection;
command.CommandText = "sp_DeleteMultipleId";
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("#Id",SqlDbType.VARCHAR).Value=result ;
This will delete multiple rows in a single stored proc call. All the best.
There is no support for array in sql server but there are several ways by which you can pass collection to a stored proc .
By using datatable
By using XML.Try converting your collection in an xml format and then pass it as an input to a stored procedure
The below link may help you
passing collection to a stored procedure
Starting in SQL Server 2016 you can bring the list in as an NVARCHAR() and use OPENJSON
DECLARE #EmployeeList nvarchar(500) = '[1,2,15]'
SELECT *
FROM Employees
WHERE ID IN (SELECT VALUE FROM OPENJSON(#EmployeeList ))
I've been searching through all the examples and answers of how to pass any array to sql server without the hassle of creating new Table type,till i found this linK, below is how I applied it to my project:
--The following code is going to get an Array as Parameter and insert the values of that
--array into another table
Create Procedure Proc1
#UserId int, //just an Id param
#s nvarchar(max) //this is the array your going to pass from C# code to your Sproc
AS
declare #xml xml
set #xml = N'<root><r>' + replace(#s,',','</r><r>') + '</r></root>'
Insert into UserRole (UserID,RoleID)
select
#UserId [UserId], t.value('.','varchar(max)') as [RoleId]
from #xml.nodes('//root/r') as a(t)
END
Hope you enjoy it
Starting in SQL Server 2016 you can simply use split string
Example:
WHERE (#LocationId IS NULL OR Id IN (SELECT items from Split_String(#LocationId, ',')))
CREATE TYPE dumyTable
AS TABLE
(
RateCodeId int,
RateLowerRange int,
RateHigherRange int,
RateRangeValue int
);
GO
CREATE PROCEDURE spInsertRateRanges
#dt AS dumyTable READONLY
AS
BEGIN
SET NOCOUNT ON;
INSERT tblRateCodeRange(RateCodeId,RateLowerRange,RateHigherRange,RateRangeValue)
SELECT *
FROM #dt
END
It took me a long time to figure this out, so in case anyone needs it...
This is based on the SQL 2005 method in Aaron's answer, and using his SplitInts function (I just removed the delim param since I'll always use commas). I'm using SQL 2008 but I wanted something that works with typed datasets (XSD, TableAdapters) and I know string params work with those.
I was trying to get his function to work in a "where in (1,2,3)" type clause, and having no luck the straight-forward way. So I created a temp table first, and then did an inner join instead of the "where in". Here is my example usage, in my case I wanted to get a list of recipes that don't contain certain ingredients:
CREATE PROCEDURE dbo.SOExample1
(
#excludeIngredientsString varchar(MAX) = ''
)
AS
/* Convert string to table of ints */
DECLARE #excludeIngredients TABLE (ID int)
insert into #excludeIngredients
select ID = Item from dbo.SplitInts(#excludeIngredientsString)
/* Select recipies that don't contain any ingredients in our excluded table */
SELECT r.Name, r.Slug
FROM Recipes AS r LEFT OUTER JOIN
RecipeIngredients as ri inner join
#excludeIngredients as ei on ri.IngredientID = ei.ID
ON r.ID = ri.RecipeID
WHERE (ri.RecipeID IS NULL)

Stored Procedure return -1 for all cases in entity framework

CREATE PROC spIsValidUser
#UserName varchar(50),
#Password varchar(50)
AS
IF Exists(SELECT * FROM Users where UserName=#UserName and Password=#Password)
BEGIN
return 0
END
ELSE
BEGIN
return 1
END
GO
I have created this Stored Procedure and tring to call this Stored Procedure using entity framework. Below is code in written in C#.
MyBusEntities db = new MyBusEntities();
int empQuery = db.spIsValidUser("abc", "abc#123");
spIsValidUser Stored Procedure return -1 in all case. Please let me know error.
EDIT - According to given answer, Store procedure is not used return statement because Entity Framework cannot support Stored Procedure Return scalar values out of the box..Let me know how can I send scalar data from Stored Procedure?
Your stored procedure is currently returns a scalar value. Use the following steps to solve this issue:
Change your stored procedure like this (Don't use the keyword return in the stored procedure to return the value, Entity Framework cannot support Stored Procedure Return scalar values out of the box. BUT there is a work around):
ALTER PROC spIsValidUser
#UserName varchar(50),
#Password varchar(50)
AS
SELECT Count(*) FROM Users where UserName= #UserName and Password= #Password
return
You need to Import the stored procedure as a Function. Right-click on the workspace area of your Entity model and choose Add -> Function Import.
In the Add Function Import dialog, enter the name you want your stored procedure to be referred to in your model, choose your procedure from the drop down list, and choose the return value of the procedure to be Scalar.
Finally write you code like this:
MyBusEntities db = new MyBusEntities();
System.Nullable<int> empQuery = db.spIsValidUser("abc", "abc#123").SingleOrDefault().Value;
MessageBox.Show(empQuery.ToString());// show 1 if Exist and 0 if not Exist
Edit: I think support of stored procedure return values depends on version of Entity framework. Also Entity Framework doesn't have rich stored procedure support because its an ORM, not a SQL replacement.
Have you tried:
CREATE PROC spIsValidUser
#UserName varchar(50),
#Password varchar(50)
AS
IF Exists(SELECT * FROM Users where UserName=#UserName and Password=#Password)
BEGIN
SELECT 0
END
ELSE
BEGIN
SELECT 1
END
GO
Have you imported your stored procedures in the EF model correctly? and are you setting correct return type to stored procedures??
There are 4 possible return type that you can set to your procedures
The possible return types are:
none
Scalars
Complex
Entities
you need to set scalars return type.
if you dont know how to set the return type, then here is the full tutorial http://www.binaryintellect.net/articles/30738a7c-5176-4333-aa83-98eab8548da5.aspx
quick example.
CREATE PROCEDURE CustOrderCount
#CustomerID nchar(5)
AS
BEGIN
SELECT COUNT(*) FROM ORDERS
WHERE CUSTOMERID=#CustomerID;
END
NorthwindEntities db = new NorthwindEntities();
var count = db.CustOrderCount("ALFKI");
int ordercount = count.SingleOrDefault().Value;
this will return int order count.

Creating a dynamic Stored Procedure on MSSQL SERVER 2008 R2

I have a System that fetches its data from different DBs on the same server.This DBs are newly attached to the server annually.e.g. at the at the beginning of 2013, a db called 2012 is attached.
So I want to create a stored procedure(SP) that fetches the user's input which can be anything from 2005(year). so based on the year the user enters, the SP should go to that db(whose name will be the year the user entered) and search for the data (with its parameter being the year the user entered) inside the db which will also has a table with the same name as the db(i.e the table will have the same name as the year name).
Hope this makes sense
It would be a good idea to paramatarize the query.
e.g.
CREATE PROC usp_bar
(
#ID INT
)
AS
BEGIN
DECLARE #SQL NVARCHAR(100)
DECLARE #Params NVARCHAR(100)
SET #SQL = N'SELECT * FROM [Table] WHERE ID = #ID'
SET #Params = N'#ID INT'
EXEC sp_executesql #SQL, #Params, #ID = 5
END
Check out this
I am no DBA so take this with a grain of salt and understand there may be a better way to do this but what you will probably have to do is something like this:
CREATE PROCEDURE usp_foo
#Year varchar(4)
AS
DECLARE #sql varchar(255)
#sql = 'SELECT * from [' + #Year + '].[owner].[table]'
sp_executesql #sql
Of course the user calling this sproc will have to A) have permissions to call system sprocs B) have permission to access the yearly database
Additionally, instead of going the SQL route, you could just make a dynamic connection string that you could populate with the correct catalog then issue your SQL queries directly to the database. Personally I would prefer that over using dynamic SQL.
One thing you could do, is take a look at synonyms, you could create one for each year:
http://sommarskog.se/dynamic_sql.html#Dyn_DB
CREATE SYNONYM otherdbtbl FOR otherdb.dbo.tbl
I'd recommend his site, it's full of good stuff, it's a great read :)
As to whether this works well for you, I'd expect it depends on how many tables you have in each DB. If it's a few this may work, if it's hundreds maybe another approach may work better - like abszero's suggestion of doing the switching in the application tier?

Build up list first, or query for every record? (Have to check for duplicates)

I'm doing some web scraping to build up a personal SQL database. As I'm looping through the web requests, I'm adding records. The only thing is, duplicates sometimes appear in the web requests and I want to make sure to only add a record if it doesn't already exist in my database. I gather this can be done by performing an SQL query before every insert to make sure that record hasn't already been added, but is this the best way to do it? Would it make more sense to build up a Generic.List first, and then do all my database inserts at the end?
You can create a stored procedure that will attempt to update a record and then insert if the update query did not update any rows. This will minimize the number of queries that need to be run and prevent checking for the row's existence. A little bit of Googling found this. The second option looks like it might be what you are looking for.
/*
Same SP is used to INSERT as well as UPDATE a table.
Here we are avoid unnecessary checking of whether the record exists or not.
Instead try to Update directly. If there is no record then ##RowCount would be 0.
Based on that Insert it as a new record.
*/
CREATE PROCEDURE uspUPSert_Ver2
(
#empID INT,
#fname VARCHAR(25),
#lname VARCHAR(25),
#emailid VARCHAR(50)
)
AS
BEGIN
SET NOCOUNT ON
BEGIN TRAN
UPDATE tblUpsert WITH (SERIALIZABLE)
SET emailid = #emailid ,
firstname = #fname ,
lastname = #lname
WHERE EmpID = #empID
IF ##ROWCOUNT = 0
BEGIN
INSERT INTO tblUpsert VALUES (#empID, #fname, #lname, #emailid)
END
COMMIT TRAN
END
GO
seems like you would need either a primary key or a unique constraint on the columns that identify the rows as duplicate. Then if there is an error in the insert that violates the unique constraint the row won't insert. Catch the exception, log it to a different table for future validation and move to the next row.
http://www.w3schools.com/sql/sql_unique.asp

Categories

Resources