I have a problem with a procedure that I'm developing in MySQL, this is my first time. A few months ago I made a small CRUD (select, insert, update) in MSSQL, and only sends the required data.
create procedure sp_Bodegas (#Opcion varchar(10), #CodBodega int = null, #NomBodega varchar(75) = null, #DirBodega varchar(150) = null, #EstBodega bit = null)
as
begin
set nocount on
if (#Opcion='SELECT')
begin
select cod_Bodega as CodBodega, nom_Bodega as NomBodega, dir_Bodega as DirBodega, est_Bodega as EstBodega from inv_Bodegas
end
if (#Opcion='INSERT')
begin
insert into inv_Bodegas (cod_Bodega, nom_Bodega, dir_Bodega, est_Bodega) values (#CodBodega, #NomBodega, #DirBodega, #EstBodega)
end
if (#Opcion='UPDATE')
begin
update inv_Bodegas set nom_Bodega = #NomBodega, dir_Bodega = #DirBodega where cod_Bodega = #CodBodega
end
set nocount off
end;
But a few days ago I started to work with MySQL and try to do the same procedure but this can not use variables such as '#NomBodega = Null' for not sending any data required option. then create input variables to receive the data, but now there are many parameters that have to send every time you run the procedure.
create procedure sp_Bodegas (in Opcion varchar(10), in CodBodega int, in NomBodega varchar(75), in DirBodega varchar(150), in EstBodega bit)
begin
if Opcion = 'SELECT' then
select cod_Bodega as CodBodega, nom_Bodega as NomBodega, dir_Bodega as DirBodega, est_Bodega as EstBodega from inv_Bodegas;
end if;
if Opcion = 'INSERT' then
insert into inv_Bodegas (cod_Bodega, nom_Bodega, dir_Bodega, est_Bodega) values (#CodBodega, #NomBodega, #DirBodega, #EstBodega);
end if;
if Opcion = 'UPDATE' then
update inv_Bodegas set nom_Bodega = #NomBodega, dir_Bodega = #DirBodega where cod_Bodega = #CodBodega;
end if;
end;
Wanted to know how I can make it work so very similar in my application, I am using aspx and EF for my database.
Thanks.
You have declared the variable as NomBodega but when you are using it in your procedure you use #NomBodega.
The #NomBodega would only be required if you passed in an out parameter to select the value after the procedure has run.
Thanks for your help, but i was very busy.
After read a lot of SP MYSQL i find is not possible so. i gona send every value.
Is it possible to have a default parameter for a mysql stored procedure?
Related
I am developing my very first stored procedure in SQL Server 2008 and need advice concerning the errors message.
Procedure or function xxx too many arguments specified
which I get after executing the stored procedure [dbo].[M_UPDATES] that calls another stored procedure called etl_M_Update_Promo.
When calling [dbo].[M_UPDATES] (code see below) via right-mouse-click and ‘Execute stored procedure’ the query that appears in the query-window is:
USE [Database_Test]
GO
DECLARE #return_value int
EXEC #return_value = [dbo].[M_UPDATES]
SELECT 'Return Value' = #return_value
GO
The output is
Msg 8144, Level 16, State 2, Procedure etl_M_Update_Promo, Line 0
Procedure or function etl_M_Update_Promo has too many arguments specified.
QUESTION: What does this error message exactly mean, i.e. where are too many arguments? How to identify them?
I found several threads asking about this error message, but the codes provided were all different to mine (if not in another language like C# anyway). So none of the answers solved the problem of my SQL query (i.e. SPs).
Note: below I provide the code used for the two SPs, but I changed the database names, table names and column names. So, please, don’t be concerned about naming conventions, these are only example names!
(1) Code for SP1 [dbo].[M_UPDATES]
USE [Database_Test]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[ M_UPDATES] AS
declare #GenID bigint
declare #Description nvarchar(50)
Set #GenID = SCOPE_IDENTITY()
Set #Description = 'M Update'
BEGIN
EXEC etl.etl_M_Update_Promo #GenID, #Description
END
GO
(2) Code for SP2 [etl_M_Update_Promo]
USE [Database_Test]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [etl].[etl_M_Update_Promo]
#GenId bigint = 0
as
declare #start datetime = getdate ()
declare #Process varchar (100) = 'Update_Promo'
declare #SummeryOfTable TABLE (Change varchar (20))
declare #Description nvarchar(50)
declare #ErrorNo int
, #ErrorMsg varchar (max)
declare #Inserts int = 0
, #Updates int = 0
, #Deleted int = 0
, #OwnGenId bit = 0
begin try
if #GenId = 0 begin
INSERT INTO Logging.dbo.ETL_Gen (Starttime)
VALUES (#start)
SET #GenId = SCOPE_IDENTITY()
SET #OwnGenId = 1
end
MERGE [Database_Test].[dbo].[Promo] AS TARGET
USING OPENQUERY( M ,'select * from m.PROMO' ) AS SOURCE
ON (TARGET.[E] = SOURCE.[E])
WHEN MATCHED AND TARGET.[A] <> SOURCE.[A]
OR TARGET.[B] <> SOURCE.[B]
OR TARGET.[C] <> SOURCE.[C]
THEN
UPDATE SET TARGET.[A] = SOURCE.[A]
,TARGET.[B] = SOURCE.[B]
, TARGET.[C] = SOURCE.[c]
WHEN NOT MATCHED BY TARGET THEN
INSERT ([E]
,[A]
,[B]
,[C]
,[D]
,[F]
,[G]
,[H]
,[I]
,[J]
,[K]
,[L]
)
VALUES (SOURCE.[E]
,SOURCE.[A]
,SOURCE.[B]
,SOURCE.[C]
,SOURCE.[D]
,SOURCE.[F]
,SOURCE.[G]
,SOURCE.[H]
,SOURCE.[I]
,SOURCE.[J]
,SOURCE.[K]
,SOURCE.[L]
)
OUTPUT $ACTION INTO #SummeryOfTable;
with cte as (
SELECT
Change,
COUNT(*) AS CountPerChange
FROM #SummeryOfTable
GROUP BY Change
)
SELECT
#Inserts =
CASE Change
WHEN 'INSERT' THEN CountPerChange ELSE #Inserts
END,
#Updates =
CASE Change
WHEN 'UPDATE' THEN CountPerChange ELSE #Updates
END,
#Deleted =
CASE Change
WHEN 'DELETE' THEN CountPerChange ELSE #Deleted
END
FROM cte
INSERT INTO Logging.dbo.ETL_log (GenID, Startdate, Enddate, Process, Message, Inserts, Updates, Deleted,Description)
VALUES (#GenId, #start, GETDATE(), #Process, 'ETL succeded', #Inserts, #Updates, #Deleted,#Description)
if #OwnGenId = 1
UPDATE Logging.dbo.ETL_Gen
SET Endtime = GETDATE()
WHERE ID = #GenId
end try
begin catch
SET #ErrorNo = ERROR_NUMBER()
SET #ErrorMsg = ERROR_MESSAGE()
INSERT INTO Logging.dbo.ETL_Log (GenId, Startdate, Enddate, Process, Message, ErrorNo, Description)
VALUES (#GenId, #start, GETDATE(), #Process, #ErrorMsg, #ErrorNo,#Description)
end catch
GO
You invoke the function with 2 parameters (#GenId and #Description):
EXEC etl.etl_M_Update_Promo #GenID, #Description
However you have declared the function to take 1 argument:
ALTER PROCEDURE [etl].[etl_M_Update_Promo]
#GenId bigint = 0
SQL Server is telling you that [etl_M_Update_Promo] only takes 1 parameter (#GenId)
You can alter the procedure to take two parameters by specifying #Description.
ALTER PROCEDURE [etl].[etl_M_Update_Promo]
#GenId bigint = 0,
#Description NVARCHAR(50)
AS
.... Rest of your code.
Use the following command before defining them:
cmd.Parameters.Clear()
This answer is based on the title and not the specific case in the original post.
I had an insert procedure that kept throwing this annoying error, and even though the error says, "procedure....has too many arguments specified," the fact is that the procedure did NOT have enough arguments.
The table had an incremental id column, and since it is incremental, I did not bother to add it as a variable/argument to the proc, but it turned out that it is needed, so I added it as #Id and viola like they say...it works.
For those who might have the same problem as me, I got this error when the DB I was using was actually master, and not the DB I should have been using.
Just put use [DBName] on the top of your script, or manually change the DB in use in the SQL Server Management Studio GUI.
Yet another cause of this error is when you are calling the stored procedure from code, and the parameter type in code does not match the type on the stored procedure.
I feel ashamed for even having to post this, but it might help someone in the future. Make sure you don't have a typo in your function call!
I kept getting this error trying to call a function and couldn't figure out why. My function and call had the same number of arguments (or so I thought).
Here's my function call:
SELECT FORMAT_NAME(A.LASTNAME, A.FIRSTNAME, A,MIDDLENAME)
It's easier to see in Stack Overflow, but it wasn't so obvious in SSMS that I had a comma in place of a period for A.MIDDLENAME.
SELECT FORMAT_NAME(A.LASTNAME, A.FIRSTNAME, A.MIDDLENAME)
Simple user error.
In addition to all the answers provided so far, another reason for causing this exception can happen when you are saving data from list to database using ADO.Net.
Many developers will mistakenly use for loop or foreach and leave the SqlCommand to execute outside the loop, to avoid that make sure that you have like this code sample for example:
public static void Save(List<myClass> listMyClass)
{
using (var Scope = new System.Transactions.TransactionScope())
{
if (listMyClass.Count > 0)
{
for (int i = 0; i < listMyClass.Count; i++)
{
SqlCommand cmd = new SqlCommand("dbo.SP_SaveChanges", myConnection);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("#ID", listMyClass[i].ID);
cmd.Parameters.AddWithValue("#FirstName", listMyClass[i].FirstName);
cmd.Parameters.AddWithValue("#LastName", listMyClass[i].LastName);
try
{
myConnection.Open();
cmd.ExecuteNonQuery();
}
catch (SqlException sqe)
{
throw new Exception(sqe.Message);
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
finally
{
myConnection.Close();
}
}
}
else
{
throw new Exception("List is empty");
}
Scope.Complete();
}
}
You either have to double check the Parameters on both side (StoredProcedure And Code):
Make Sure they are the same on both ends regarding to the number of them.
Make Sure you have NOT changed your StoredProcedure code and forgot to Execute it, nothing bad happens if you hit F5 to make sure have all the changes committed and saved.
Make Sure you you have the same naming convention on both sides (Not Likely to be the cause but it worth a shot).
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 an app that runs a stored procedure in SQL Server, checking the difference of times between one row in a table and getdate()
I call this stored procedure from c#, and use a #returnValue to do some things
This is the method
public static bool Check(string CheckStored)
{
using (DbCommand command = DatabaseDA.DefaultDb.GetStoredProcCommand(CheckStored))
{
DatabaseDA.DefaultDb.AddParameter(command, "ReturnValue", DbType.Boolean, ParameterDirection.ReturnValue, "", DataRowVersion.Current, 0);
DatabaseDA.DefaultDb.ExecuteNonQuery(command);
return Convert.ToBoolean(command.Parameters["#ReturnValue"].Value);
}
}
and this is the call
bool notifNeeded = NotificationsDA.Check("CheckLastEnvioListadoComprobanteEjercicio");
then in SQL Server I have:
ALTER Procedure [dbo].[CheckLastEnvioListadoComprobanteEjercicio]
as
Begin
declare #UltimoEnvio datetime
declare #ReturnValue bit
select #UltimoEnvio = LastDate from EnvioListadoEjercicioComprobantes
Select #returnValue = CASE
WHEN DATEDIFF(hour, #UltimoEnvio, getdate()) >= 1 THEN 1
ELSE 0
END
from rep_inboxRequest
if (#ReturnValue = 1)
update EnvioListadoEjercicioComprobantes set LastDate = getdate()
return #ReturnValue
END
in EnvioListadoEjercicioComprobantes I have a row with the lastDate of one action (ej sending mail).
Right now, I have only one row, with 2012-06-18 06:40:02.210 value. I compare this date with the actual date, and return a bit if the difference is more than an hour.
Right now, in Argentina, its about 2012-06-18 11:26
If I execute getdate() in SQL Server, I get 2012-06-18 11:30:44.027
If I run my entire stored procedure in SQL Server and print #ReturnValue, I get 1 and the row is updated-
But when I call my stored from C#, I always get 0, and of course, the row didn't update.
What am I doing wrong ?
Why are you doing all that work (declare, select, update conditionally) when you can just perform a conditional update?
ALTER PROCEDURE [dbo].[CheckLastEnvioListadoComprobanteEjercicio]
AS
BEGIN
SET NOCOUNT ON;
UPDATE dbo.EnvioListadoEjercicioComprobantes
SET LastDate = GETDATE()
WHERE LastDate <= DATEADD(HOUR, -1, GETDATE());
IF ##ROWCOUNT > 0
RETURN 1;
ELSE
RETURN 0;
END
GO
Anyway I don't think that's the way you deal with a return value. Try something like this (this is pseudo-code):
DatabaseDA.DefaultDb.ExecuteNonQuery(command);
var returnVal = command.Parameters.Add("#ReturnValue", SqlDbType.Int);
returnVal.Direction = ParameterDirection.ReturnValue; // this is important
DatabaseDA.DefaultDb.ExecuteNonQuery(command);
return Convert.ToBoolean(returnVal.Value);
Otherwise I suggest you stop using a return value for this, if you want the return parameter to be bit coming out of SQL Server, you can use an output parameter.
ALTER PROCEDURE [dbo].[CheckLastEnvioListadoComprobanteEjercicio]
#ReturnVal BIT = 0 OUTPUT
AS
BEGIN
SET NOCOUNT ON;
UPDATE dbo.EnvioListadoEjercicioComprobantes
SET LastDate = GETDATE()
WHERE LastDate <= DATEADD(HOUR, -1, GETDATE());
SELECT #ReturnVal = ##ROWCOUNT;
END
GO
Now in your C# code (again, this is pseudo-code, I don't know that it will magically compile in your app if you copy and paste, but it should give you the idea):
SqlParameter rv = new SqlParameter("#ReturnVal", SqlDbType.Boolean);
rv.Direction=ParameterDirection.Output;
command.Parameters.Add(rv);
command.ExecuteNonQuery();
return Convert.ToBoolean(rv.Value);
Check your database's collation settings: In your Select statement, you are setting #returnValue but later you're checking and returning #ReturnValue. If case sensitivity is on, those are two different variables.
Try adding SET NOCOUNT ON at the top of your stored procedure , traditionally the return value is used to report the number of rows affected using the "SET NOCOUNT ON" option disables this feature which may be causing trouble with your return value.
Also check the SQL Server Logins Language option as this too can affect the way DateTime is calculated (amongst other things like collation). It might be that in Management Studio you are connecting using a windows account using argentinian local time but the C# application is connecting using a US/English login setting which will cause SQL Server to think you're in a different timezone.
I have a mysql script in a file that I need to be able to execute from my c# application. Here is a sample of what the script contains:
USE osae;
-- Set DB version
CALL osae_sp_object_property_set('SYSTEM', 'DB Version', '0.3.5', '', '');
CALL osae_sp_object_property_set('SYSTEM', 'Debug', 'FALSE', '', '');
CALL osae_sp_object_type_property_add ('Prune Logs','Boolean','TRUE','SYSTEM',0);
CALL osae_sp_object_property_set ('SYSTEM','Prune Logs','TRUE','','');
DELIMITER $$
DROP PROCEDURE IF EXISTS osae_sp_object_event_script_update$$
CREATE DEFINER = 'root'#'localhost'
PROCEDURE osae_sp_object_event_script_update(IN pobject varchar(200), IN pevent varchar(200), IN ptext text)
BEGIN
DECLARE vObjectCount INT;
DECLARE vObjectID INT;
DECLARE vObjectTypeID INT;
DECLARE vEventCount INT;
DECLARE vEventID INT;
SELECT COUNT(object_id) INTO vObjectCount FROM osae_object WHERE UPPER(object_name)=UPPER(pobject);
IF vObjectCount > 0 THEN
SELECT object_id,object_type_id INTO vObjectID,vObjectTypeID FROM osae_object WHERE UPPER(object_name)=UPPER(pobject);
SELECT COUNT(event_id) INTO vEventCount FROM osae_object_type_event WHERE object_type_id=vObjectTypeID AND (UPPER(event_name)=UPPER(pevent) OR UPPER(event_label)=UPPER(pevent));
IF vEventCount = 1 THEN
SELECT event_id INTO vEventID FROM osae_object_type_event WHERE object_type_id=vObjectTypeID AND (UPPER(event_name)=UPPER(pevent) OR UPPER(event_label)=UPPER(pevent));
UPDATE osae_object_event_script SET event_script=ptext WHERE object_id=vObjectID AND event_id=vEventID;
-- CALL osae_sp_debug_log_add(CONCAT('Updated ',vObjectID,' - ',vEventID,ptext),'');
END IF;
END IF;
END
$$
DELIMITER ;
As you can see it has a mixture of lines that call stored procedures and some drop and create statements to update other stored procedures.
I have tried two different methods to execute the script and both have failed:
MySqlScript script = new MySqlScript(connection, File.ReadAllText("script.sql"));
script.Execute();
This throws the exception: Index was outside the bounds of the array.
MySqlCommand upgCommand = new MySqlCommand();
upgCommand.Connection = connection;
upgCommand.CommandText = File.ReadAllText("script.sql");
upgCommand.ExecuteNonQuery();
This throws an exception that there is an error in my sql syntax.
When I run the entire script manually in dbForge Studio it executes perfectly. How can I get this script to execute correctly from my C# app
Take a look here. You should specify a delimiter for MySqlScript (since you have stored procedure in there). And your query should look like:
-- Set DB version
CALL osae_sp_object_property_set('SYSTEM', 'DB Version', '0.3.5', '', '')$$
CALL osae_sp_object_property_set('SYSTEM', 'Debug', 'FALSE', '', '')$$
CALL osae_sp_object_type_property_add ('Prune Logs','Boolean','TRUE','SYSTEM',0)$$
CALL osae_sp_object_property_set ('SYSTEM','Prune Logs','TRUE','','')$$
DROP PROCEDURE IF EXISTS osae_sp_object_event_script_update$$
CREATE DEFINER = 'root'#'localhost'
PROCEDURE osae_sp_object_event_script_update(IN pobject varchar(200), IN pevent varchar(200), IN ptext text)
BEGIN
DECLARE vObjectCount INT;
DECLARE vObjectID INT;
DECLARE vObjectTypeID INT;
DECLARE vEventCount INT;
DECLARE vEventID INT;
SELECT COUNT(object_id) INTO vObjectCount FROM osae_object WHERE UPPER(object_name)=UPPER(pobject);
IF vObjectCount > 0 THEN
SELECT object_id,object_type_id INTO vObjectID,vObjectTypeID FROM osae_object WHERE UPPER(object_name)=UPPER(pobject);
SELECT COUNT(event_id) INTO vEventCount FROM osae_object_type_event WHERE object_type_id=vObjectTypeID AND (UPPER(event_name)=UPPER(pevent) OR UPPER(event_label)=UPPER(pevent));
IF vEventCount = 1 THEN
SELECT event_id INTO vEventID FROM osae_object_type_event WHERE object_type_id=vObjectTypeID AND (UPPER(event_name)=UPPER(pevent) OR UPPER(event_label)=UPPER(pevent));
UPDATE osae_object_event_script SET event_script=ptext WHERE object_id=vObjectID AND event_id=vEventID;
-- CALL osae_sp_debug_log_add(CONCAT('Updated ',vObjectID,' - ',vEventID,ptext),'');
END IF;
END IF;
END
$$
And then your code:
MySqlScript script = new MySqlScript(connection, File.ReadAllText("script.sql"));
script.Delimiter = "$$";
script.Execute();
You could run a separate Process to execute the script. For example:
Process.Start("mysql < script.sql");
You are probably going to need to play around with it a little depending on your environment to include paths to the mysql executable or the sql script.
How if you put your sql script in a stored procedure? If you still want use this way attach the sql file to application as file to the application resources (files .resx) and execute it like that:
MySql.Data.MySqlClient.MySqlCommand cmdMySQL = newMySqlConnection.CreateCommand();
cmdMySQL.CommandText = (System.String)globalResource.your_file_name;
I am not 100% sure what native MySql syntax is, but when we perform similar functionality for Sql Server, we have to break the sql file into chunks based on the literal values (GO) that are only used by the query executor (Sql Server Management Console).
I suspect there may be similar information embedded in your request above, such as the DEFINE statement.
Knowing exactly what MySql complained about would help refine the solution.
Worked For Me:
connectOb.conn.Open();
MySqlScript script = new MySqlScript(connectOb.conn,
"SET #num := 0;
UPDATE serving_table SET Id = #num := (#num + 1);
ALTER TABLE serving_table AUTO_INCREMENT = 1;");
script.Execute();
connectOb.conn.Close();
This seems to be a simple question but nevertheless I haven't found an answer yet.
I have the following stored procedure
CREATE PROCEDURE [dbo].[AllocateId]
AS
BEGIN TRANSACTION
UPDATE TOP(1) IdReservation
SET IsAllocated = 1
OUTPUT DELETED.Id
WHERE IsAllocated = 0
COMMIT TRANSACTION
GO
It's been used in C# + EF code without a problem via ExecuteFunction of ObjectContext
ObjectResult<int> objectResult = ExecuteFunction<int>("AllocateId");
However when I try to call it directly from SQL script it doesn't seem to work
declare #Id int
EXEC #Id = [dbo].[AllocateId]
#Id is always 0. How do I get the value into #Id variable in sql script?
Procedure return value is different from result set(s) returned by that procedure. Your stored procedure returns a result set and does not return a return value (which ends up being null, which gets converted to 0 implicitly upon exiting the procedure).
To get the resultset your existing procedure retuns, you need insert ... exec:
declare #t table (id int);
insert into #t
exec [dbo].[AllocateId];
If you want to return a value as a return value as well, you should amend you stored procedure:
CREATE PROCEDURE [dbo].[AllocateId]
AS
BEGIN TRANSACTION
declare #id int;
UPDATE TOP(1) IdReservation
SET #id = Id, IsAllocated = 1
OUTPUT DELETED.Id
WHERE IsAllocated = 0
COMMIT TRANSACTION
return #id;
Then it will work in the way you describe in the question.