I have a database which stores information about a library (books, authors & categories).
But I can't get my stored procedure to work for inserting data. The stored procedure itself executes fine, but when I perform a test, it simply doesn't add anything to the database. Can anyone see what I'm missing?
This is my stored procedure (for category):
USE MyLibrary
GO
IF EXISTS (SELECT 1 FROM sysobjects WHERE name = 'CategoryInsert' AND TYPE = 'P')
BEGIN
DROP PROC CategoryInsert
END
GO
CREATE PROCEDURE CategoryInsert
(
#Id int out,
#Name nvarchar(255),
#InsertedBy nvarchar(120),
#InsertedOn datetime
)
AS
DECLARE #CurrentId int
SELECT #CurrentId = Id FROM Category WHERE lower(#Name) = lower(#Name)
IF #CurrentId IS NOT NULL
BEGIN
SET #Id = -100
RETURN
END
INSERT INTO Category
(
Name,
InsertedBy,
InsertedOn
)
VALUES
(
#Name,
#InsertedBy,
#InsertedOn
)
SET #Id = SCOPE_IDENTITY()
GO
This is my test:
USE MyLibrary
GO
DECLARE #NewId int
DECLARE #date datetime
SET #date = getdate()
EXEC CategoryInsert #NewId, 'Testing', 'AL', #date
SELECT #NewId
GO
This line:
SELECT #CurrentId = Id FROM Category WHERE lower(#Name) = lower(#Name)
IF #CurrentId IS NOT NULL
The equality check will always return true because you're essentially comparing WHERE 1 = 1, which means that #CurrentID will always have a value and thus your stored procedure will always return before the INSERT happens.
Related
All I want to do is check if a name exists in a given table in my database or not but I am getting multiple returns from the stored procedure causing an exception.
This is the stored procedure I am using in SQL Server:
CREATE OR ALTER PROCEDURE ContactExists
#Name varchar(50)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #result bit = 0
DECLARE #name varchar(50) = '';
SET #name = (SELECT Name FROM Table)
IF (#name = #Name)
BEGIN
SET #result = 1
RETURN #result
END
RETURN #result
END
GO
And this is the method I am using in C#:
SPstr = "dbo.ContactExists";
SqlCommand cmd = new SqlCommand(SPstr, connection);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#Name", Name);
var returnValue = cmd.Parameters.Add("#result", SqlDbType.Int);
returnValue.Direction = ParameterDirection.ReturnValue;
cmd.ExecuteNonQuery();
return (int)returnValue.Value;
I am getting multiple returns from the stored procedure causing an exception.
I suspect you mean you're getting this:
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
which is going to arise from this:
set #name = (SELECT Name from Table)
if Table has more than one row. Ensure the subquery (SELECT Name from Table) returns at most one row (use a WHERE on the pk, use MAX etc..)
Don't use the return value from stored procedures to return data. It's an old and mostly obsolete way to signal success or failure of the proc. So either use an output parameter:
CREATE OR ALTER PROCEDURE ContactExists
#Name varchar(50), #result bit output
AS
BEGIN
SET NOCOUNT ON;
set #result = 0;
if exists (SELECT * FROM SomeTable where name = #Name)
begin
set #result = 1;
end
END
or a resultset
CREATE OR ALTER PROCEDURE ContactExists
#Name varchar(50)
AS
BEGIN
SET NOCOUNT ON;
declare #result bit = 0;
if exists (SELECT * FROM SomeTable where name = #Name)
begin
set #result = 1;
end
select #result result;
END
I have created this stored procedure:
CREATE PROCEDURE [dbo].[zsp_MoveItemsToFolder]
(#IdListToMove IdListToMove READONLY,
#FolderId INT,
#UserId INT)
AS
BEGIN
DECLARE #Rowcount INT = 1;
WHILE (#Rowcount > 0)
UPDATE TOP (5000) dbo.SingleScannedItems --<-- define Batch Size in TOP Clause
SET MyListId = #FolderId
WHERE SingleScannedItemId IN (SELECT l.SingleScannedItemIds
FROM #IdListToMove l)
AND UserId = #UserId
SET #Rowcount = ##ROWCOUNT;
CHECKPOINT; --<-- to commit the changes with each batch
END
Prior to that I have created a user defined type in SQL like this:
CREATE TYPE [dbo].[IdListToMove] AS TABLE(
[SingleScannedItemIds] int NULL
);
And once I have imported the procedure into the C# LINQ the only parameters that I can see are FolderId and UserId.
However the #IdListToMove user defined type is not visible in the imported stored procedure :/...
So my question is: why is the user defined type not visible in the imported stored procedure (that is imported through the Entity Framework 6)
How do I fix this so that I can pass the list through C# into the stored procedure?
Can someone help me out?
Edit: here's the modified procedure with #Marc Gravel's suggestions:
ALTER PROCEDURE [dbo].[zsp_MoveItemsToFolder]
(#IdListToMove NVARCHAR(MAX),
#FolderId INT,
#UserId INT)
AS
BEGIN
DECLARE #Rowcount INT = 1;
WHILE (#Rowcount > 0)
UPDATE TOP (5000) dbo.SingleScannedItems --<-- define Batch Size in TOP Clause
SET MyListId = #FolderId
WHERE (EXISTS (SELECT 1
FROM dbo.SplitStringProduction(#IdListToMove,',') S1
WHERE SingleScannedItemId = S1.val))
AND UserId = #UserId
AND MyListId <> #FolderId
SET #Rowcount = ##ROWCOUNT;
CHECKPOINT; --<-- to commit the changes with each batch
END
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 have a stored procedure with takes 2 parameters (StudentID and CurrentSmester) as input and return me table with fields :
Course Code
Update Type
Update Id
This stored procedure is created by another team in my office. I can not modify it but at the same point I want to use it in my Webservice (which I am building for android) to make sure data remains consistent.
My requirement is to get :
Course Code
Update Type
Update Id
Course Title
Can I create another store procedure which will call that store procedure with parameters as I mentioned, make a join with course table to get course title too.
Is this possible ? If yes can you please guide me through its implementation.
Thanking You and Happy New Year !!
Create a new stored procedure , insert the results coming back from your existing stored procedure into a temp table, join your Course table with that temp table and you are good to go ,
something like this.....
CREATE PROCEDURE usp_NewProc
#StudentID INT ,
#CurrentSmester INT
AS
BEGIN
SET NOCOUNT ON;
IF OBJECT_ID('tempdb..#temp', 'U') IS NOT NULL
DROP TABLE #temp
CREATE TABLE #temp
(
CourseCode [DataType],
UpdateType [DataType],
Update Id [DataType]
)
INSERT INTO #temp
EXEC existsting_proc #StudentID , #CurrentSmester
SELECT t.* , C.CourseTitle
FROM #temp t INNER JOIN CourseTable C on <join Condition>
IF OBJECT_ID('tempdb..#temp', 'U') IS NOT NULL
DROP TABLE #temp
END
You can insert the results from the STORED PROCEDURE into a temp table (table variable or temp table) and them select from that table and join onto the Courses table to retrieve the title.
SQL Fiddle DEMO
Example code
CREATE TABLE Courses(
CourseCode VARCHAR(50),
CourseName VARCHAR(250)
);
INSERT INTO Courses VALUES ('A','AA'), ('B','BB');
CREATE PROCEDURE OtherTeamsSP(
#StudentID INT,
#CurrentSmester INT
)
AS
SELECT 'A' CourseCode,
'FOO' UpdateType,
1 UpdateId;
CREATE PROCEDURE MyProcedure(
#StudentID INT,
#CurrentSmester INT
)
AS
CREATE TABLE #SPOutput(
CourseCode VARCHAR(50),
UpdateType VARCHAR(50),
UpdateId INT
)
INSERT INTO #SPOutput
EXEC OtherTeamsSP #StudentID, #CurrentSmester
SELECT *
FROM #SPOutput s INNER JOIN
Courses c ON s.CourseCode = c.CourseCode
DROP TABLE #SPOutput
Calling the new SP
EXEC MyProcedure 1,2
-- First Stored Procedure
CREATE PROCEDURE FirstSP
#MyFirstParam INT
AS
DECLARE #MyFirstParamValue INT
SELECT #MyFirstParamValue = #MyFirstParam * #MyFirstParam
RETURN (#MyFirstParamValue)
GO
-- Second Stored Procedure
CREATE PROCEDURE SecondSP
#SecondParam INT
AS
DECLARE #SecondParamValue INT
SELECT #SecondParamValue = #SecondParam * #SecondParam
RETURN (#SecondParamValue)
GO
-- Pass One Stored Procedure's Result as Another Stored Procedure's Parameter
DECLARE #FirstValue INT, #SeondValue INT
-- First SP
EXEC #FirstValue = FirstSP 5
-- Second SP
EXEC #SeondValue = SecondSP #FirstValue
SELECT #SeondValue SecondSP
GO
-- Clean up
DROP PROCEDURE FirstSP
DROP PROCEDURE SecondSP
GO
I'm trying to add the following sproc to Entity Framework. After adding this via "Update from Model" the Model Browser shows this sproc in the "Function Imports" and "Stored Procedures/Functions" of the model. Using the "Edit" from Function Imports dialog I can not "Get Column Information" and unsuccessfully determine a Return type for the collection.
The output from the sproc is a temporary table but I do define the columns being returned. Is this sproc the problem? Am I missing a step in setting up the EF?
ALTER PROCEDURE [dbo].[addrApproxSP]
-- Add the parameters for the stored procedure here
#frontage bigint = 0,
#housedir varchar(1) = 0,
#streetnum bigint = 0,
#streetdir varchar(1) = 0,
#distance bigint = 0
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Set Variables
DECLARE #lowfront bigint,
#highfront bigint,
#lowstreet bigint,
#highstreet bigint,
#currname varchar(25),
#streetcur varchar(25),
#whereclause varchar(40),
#fixstreet varchar(25),
#pos int,
#piece varchar(500)
--Set variables to proper values in range
Set #lowfront = #frontage - #distance
set #highfront = #frontage + #distance
set #lowstreet = #streetnum - #distance
set #highstreet = #streetnum + #distance
-- Process for Street Names that are Numeric Values
-- Create Temp Table
CREATE TABLE #StreetNames
(streetname varchar(25))
-- SELECT StreetName and put in Temp table
INSERT #Streetnames(streetname)
select distinct streetname
from ADDR_STREETCOORD
where begincoord between #lowstreet and #highstreet
and STREETDIR = #streetdir
and lowhouse > #lowfront and HIGHHOUSE < #highfront
and HOUSEDIR = #housedir
union
select distinct streetname
from ADDR_STREETCOORD
where lowhouse > #lowstreet and HIGHHOUSE < #highstreet
and HOUSEDIR = #housedir
and begincoord between #lowfront and #highfront
and STREETDIR = #streetdir
-- Check each Streetname and those that are a coordinate (ex: "1000 S") change to "1000"
CREATE TABLE #FixStreets(streetname varchar(25))
DECLARE curStreet CURSOR FOR SELECT streetname FROM #StreetNames
OPEN curStreet
FETCH NEXT FROM curStreet INTO #fixstreet
WHILE ##FETCH_STATUS = 0
BEGIN
--insert code here
INSERT #FixStreets(streetname)
--Call Function to: parse the street name
--if the first part isnumeric then insert that
--if not numeric then keep as is
select [dbo].fnParseCoordinate(#fixstreet)
FETCH NEXT FROM curStreet INTO #fixstreet
END
CLOSE curStreet
DEALLOCATE curStreet
--select * from #FixStreets
--create a temp table to store the results of each street name in a single table
-- in order to return the results as a single table
--For Each street name search its frontage range values
--loop through each streetname to get the parcels matching those streets
CREATE TABLE #AllResults(Parcel varchar(14),Prop_locat varchar(50))
DECLARE curName CURSOR FOR SELECT streetname FROM #FixStreets
OPEN curName
FETCH NEXT FROM curName INTO #streetcur
WHILE ##FETCH_STATUS = 0
BEGIN
--insert code here
INSERT #AllResults(Parcel, Prop_locat)
select parcel_id,prop_locat
from ADDR_ParcelsWWW
where StreetName = #streetcur
and predir = #housedir
and housefrom between #lowfront and #highfront
union
select parcel_id,LOCATOR_ADDRESS
from ADDR_MASTERADDRESS
where StreetName = #streetcur
and predir = #housedir
and housefrom between #lowfront and #highfront
FETCH NEXT FROM curName INTO #streetcur
END
CLOSE curName
DEALLOCATE curName
--Select the results of all the tables
select Parcel, prop_locat from #AllResults
END
When EF polls your SP, it does this first: SET FMTONLY ON
This can screw things up if you use temp tables in your SP, which it looks like you're doing.
Try explicitly setting this at the beginning of your SP: SET FMTONLY OFF
That should allow EF to detect your columns.