Related
ALTER PROCEDURE [dbo].[Proc_Erp_Branch_Update]
#Id int,
#Code varchar(20),
#Name nvarchar(50),
#IsActive bit=1,
#UpdateBy varchar(50),
#ImgId int
AS
BEGIN
IF EXISTS (SELECT* FROM Branch WHERE Id = #id AND IsDelete =0)
BEGIN
UPDATE Branch
SET Code = ISNULL(#Code,Code),
Name = ISNULL( #Name,Name),
IsActive = ISNULL( #IsActive,IsActive),
UpdatedBy = ISNULL( #UpdateBy,UpdatedBy),
ImageId = ISNULL( #ImgId,ImageId)
output deleted.Id
WHERE Id = #Id AND IsDelete = 0
END
ELSE
BEGIN
SELECT 0
END
END
Why does the procedure always return 0 even though the update statement appears to be successful in the [dbo].[Proc_Erp_Branch_Update]?
How do I resolve this?
var query = "Proc_Erp_Position_Update";
var res = await con.QueryFirstOrDefaultAsync<int>(query, new { Id = model.Id, Code = model.Code, Name = model.Name, IsAtive = model.IsActive, UpdatBy = username, ImageId = imgid.HasValue? imgid : 0 }, commandType: System.Data.CommandType.StoredProcedure);
return res;
res always returns 0
res will always be 0 since if your procedure does find the row and update it, it will not select any value - and the default for int in dot net is 0.
However, there is another problem in your procedure - there is a chance, though admittedly a small chance, that the relevant row will be changed or deleted between the select statement in the exists condition and the update statement that follows.
Luckily, there's an easy fix for that - simply remove the if.
Executing a stored procedure will return, by default, the number of rows effected, so you can simply use con.ExecuteAsync to get that number.
SQL:
ALTER PROCEDURE [dbo].[Proc_Erp_Branch_Update]
#Id int,
#Code varchar(20),
#Name nvarchar(50),
#IsActive bit=1,
#UpdateBy varchar(50),
#ImgId int
AS
BEGIN
UPDATE Branch
SET Code = ISNULL(#Code,Code),
Name = ISNULL( #Name,Name),
IsActive = ISNULL( #IsActive,IsActive),
UpdatedBy = ISNULL( #UpdateBy,UpdatedBy),
ImageId = ISNULL( #ImgId,ImageId)
WHERE Id = #Id AND IsDelete = 0
END
C#:
var query = "Proc_Erp_Position_Update";
var res = await con.ExecuteAsync(query, new { Id = model.Id, Code = model.Code, Name = model.Name, IsAtive = model.IsActive, UpdatBy = username, ImageId = imgid.HasValue? imgid : 0 }, commandType: System.Data.CommandType.StoredProcedure);
return res;
Note: I'm assuming you're using c# and Dapper based on the code you've shown in your question.
I am trying to execute a stored procedure in SQL Server from my java code. This stored procedure is used in some other language and it was working fine from long back. Now I need to integrate it in my java app. I have 15 columns in my table. When I tried this in my java code, its throwing
com.microsoft.sqlserver.jdbc.SQLServerException: The index 11 is out of range
I also see "Error: 0, SQLState: S1093"
My stored procedure
ALTER PROCEDURE [dbo].[user_input_sp]
#Username VARCHAR(10)=NULL,
#UserKey VARCHAR(50)=NULL,
#ReqTime DATETIME=null,
#ResTime DATETIME=null,
#Req TEXT=null,
#Res TEXT=null,
#condition TEXT=null,
#ID INT=null,
#Address VARCHAR(8000) = NULL,
#Task VARCHAR(50) = NULL,
#Direction INT=0,
#Seq INT=0,
#RR BIT=0,
#Correction VARCHAR(8) = NULL,
#PendingTrans VARCHAR(50) = NULL,
#ForwardID VARCHAR(50) = NULL,
#Command VARCHAR(50) = NULL
AS
DECLARE #TSqno int
#IF #Direction=0
BEGIN
EXECUTE Basp_NewKey 'web_log', #TSqno OUTPUT
Insert into cbscne dbo WebServiceLog( Order, US_Name, US_Key , US_ReqD, US_ResD, US_Req , US_Res, cond, ID ,Address, Task, Command)
values (#TSqno, #Username, #UserKey, #ReqTime, #ResTime, #Req ,#Res, #condition, #ID ,#Address, #Task ,#Command)
END
.......
My java code
public vold addWebServiceLogRequest(UserInput cd){
sessionFactory = sqlServerEMFactory.unwrap(SessionFactory.class);
Session sessionForSave = sessionFactory.openSession();
sessionForSave.beginTransaction();
sessionForSave.doReturningWork(connection-> {
try(CallableStatement cstmt = connection.prepareCall("{call user_input_sp(?,?,?,?,?,?,?,?,?)}")) {
cstmt.setInt("indicator", 0);
cstmt.setString("Username",cd.getInterfaceName());
cstmt.setInt("User_code",cd.getCaseId());
cstmt.setTimestamp("RetrieveDate",cd.getRequestDate());
cstmt.setTimestamp("ReturnDate",cd.getResponseDate());
cstmt.setString("Req",cd.getRequestxml());
cstmt.setString("Res",cd.getResponsexml());
cstmt.setString("Task",cd.getTask());
cstmt.setString("flow",null);
cstmt.execute();
cstmt.close();
connection.close();
return null;
}
});
}
Is there any SQL script to check the changes on SQL Server instance made by other DB admin and i get email alert of that changes. if yes, then please provide me the script and all the steps for applying it. I am using SQL Server 2012.
One solution is to use a DDL trigger to catch all schema changes (procedures, functions, table definition etc.). This can work for all non-encrypted objects and of course, other admins must not disable it.
More details about how to write such a trigger and persist changes can be found here.
[Later edit]
I remembered I have created such an audit on the development environment and I can provide a custom version based on the indicated article. Besides usual information, I have also included a "distance" between old object text and new object text to have a basic idea about change magnitude.
1) Table definition:
IF OBJECT_ID('dbo.DDLEvents', 'U') IS NULL
BEGIN
CREATE TABLE dbo.DDLEvents
(
EventId INT IDENTITY(1, 1) NOT NULL,
EventDate DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
EventType NVARCHAR(64),
EventXML XML,
DatabaseName NVARCHAR(255),
SchemaName NVARCHAR(255),
ObjectName NVARCHAR(255),
HostName VARCHAR(128),
IPAddress VARCHAR(32),
ProgramName NVARCHAR(255),
LoginName NVARCHAR(255),
ObjectDefinition NVARCHAR(MAX),
LastObjDefinition NVARCHAR(MAX),
Diff INT -- edit distance between last and current object version (gives an idea of how much was changed in the object)
);
create index IDX_DDLEvents_Object ON DDLEvents (SchemaName, ObjectName)
END
go
2) Initial text for existing objects:
IF NOT EXISTS(SELECT * FROM dbo.DDLEvents)
BEGIN
INSERT INTO dbo.DDLEvents
(EventType, DatabaseName, SchemaName, ObjectName, LoginName, ObjectDefinition)
SELECT 'CREATE_PROCEDURE', DB_NAME(), OBJECT_SCHEMA_NAME([object_id]), OBJECT_NAME([object_id]), 'SYSTEM', OBJECT_DEFINITION([object_id])
FROM sys.procedures;
INSERT INTO dbo.DDLEvents
(EventType, DatabaseName, SchemaName, ObjectName, LoginName, ObjectDefinition)
SELECT 'CREATE_VIEW', DB_NAME(), OBJECT_SCHEMA_NAME([object_id]), OBJECT_NAME([object_id]), 'SYSTEM', OBJECT_DEFINITION([object_id])
FROM sys.views;
INSERT INTO dbo.DDLEvents
(EventType, DatabaseName, SchemaName, ObjectName, LoginName, ObjectDefinition)
SELECT 'CREATE_FUNCTION', DB_NAME(), OBJECT_SCHEMA_NAME([object_id]), OBJECT_NAME([object_id]), 'SYSTEM', OBJECT_DEFINITION([object_id])
FROM sys.objects
-- scalar, inline table-valued, table-valued
WHERE type IN ('FN', 'IF', 'TF')
END
go
3) Distance function (CLR):
[Microsoft.SqlServer.Server.SqlFunction(IsDeterministic = true, IsPrecise = false)]
public static int Levenshtein(SqlString S1, SqlString S2)
{
if (S1.IsNull)
S1 = new SqlString("");
if (S2.IsNull)
S2 = new SqlString("");
int maxLen = 4096;
// keeping only the first part of the string (performance reasons)
String SC1 = S1.Value.ToUpper();
String SC2 = S2.Value.ToUpper();
if (SC1.Length > maxLen)
SC1 = SC1.Remove(maxLen);
if (SC2.Length > maxLen)
SC2 = SC2.Remove(maxLen);
int n = SC1.Length;
int m = SC2.Length;
short[,] d = new short[n + 1, m + 1];
int cost = 0;
if (n + m == 0)
{
return 0;
}
else if (n == 0)
{
return 0;
}
else if (m == 0)
{
return 0;
}
for (short i = 0; i <= n; i++)
d[i, 0] = i;
for (short j = 0; j <= m; j++)
d[0, j] = j;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
if (SC1[i - 1] == SC2[j - 1])
cost = 0;
else
cost = 1;
d[i, j] = (short) System.Math.Min(System.Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1), d[i - 1, j - 1] + cost);
}
}
// double percentage = System.Math.Round((1.0 - ((double)d[n, m] / (double)System.Math.Max(n, m))) * 100.0, 2);
// return percentage;
return d[n, m];
}
4) The DDL trigger definition
if not exists (select * from sys.triggers where name = 'DDL_Audit_Trigger')
exec ('create trigger DDL_Audit_Trigger ON DATABASE FOR CREATE_PROCEDURE AS BEGIN PRINT 1; END')
GO
ALTER TRIGGER [DDL_Audit_Trigger]
ON DATABASE
FOR
CREATE_ASSEMBLY, ALTER_ASSEMBLY, DROP_ASSEMBLY,
CREATE_PROCEDURE, ALTER_PROCEDURE, DROP_PROCEDURE,
CREATE_FUNCTION, ALTER_FUNCTION, DROP_FUNCTION,
CREATE_INDEX, ALTER_INDEX, DROP_INDEX,
CREATE_VIEW, ALTER_VIEW, DROP_VIEW,
CREATE_ROLE, ALTER_ROLE, DROP_ROLE,
CREATE_SCHEMA, ALTER_SCHEMA, DROP_SCHEMA,
CREATE_TABLE, ALTER_TABLE, DROP_TABLE,
CREATE_TYPE, DROP_TYPE,
CREATE_USER, ALTER_USER, DROP_USER,
CREATE_TRIGGER, ALTER_TRIGGER, DROP_TRIGGER,
RENAME
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
DECLARE #EventData XML = EVENTDATA();
DECLARE #ip VARCHAR(32) = ( SELECT client_net_address FROM sys.dm_exec_connections WHERE session_id = ##SPID);
DECLARE #ObjectSchema NVARCHAR(255) = #EventData.value('(/EVENT_INSTANCE/SchemaName)[1]', 'NVARCHAR(255)')
DECLARE #ObjectName NVARCHAR(255) = #EventData.value('(/EVENT_INSTANCE/ObjectName)[1]', 'NVARCHAR(255)')
-- DECLARE #ObjectFullName NVARCHAR(255) = #ObjectSchema + '.' + #ObjectName
DECLARE #CommandText NVARCHAR(MAX) = #EventData.value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]', 'NVARCHAR(MAX)')
DECLARE #LastObjectChange DATETIME = (SELECT TOP 1 EventDate FROM dbo.DDLEvents where SchemaName = #ObjectSchema and ObjectName = #ObjectName ORDER BY EventDate DESC)
DECLARE #LastObjectDefinition NVARCHAR(MAX) = (SELECT TOP 1 ObjectDefinition FROM dbo.DDLEvents where SchemaName = #ObjectSchema and ObjectName = #ObjectName and EventDate = #LastObjectChange ORDER BY EventDate DESC)
INSERT INTO dbo.DDLEvents
(EventType,
EventXML, DatabaseName,
SchemaName, ObjectName,
HostName, IPAddress, ProgramName, LoginName,
ObjectDefinition, LastObjDefinition, Diff
)
SELECT #EventData.value('(/EVENT_INSTANCE/EventType)[1]', 'NVARCHAR(100)'),
#EventData, DB_NAME(),
#ObjectSchema, #ObjectName,
HOST_NAME(), #ip, PROGRAM_NAME(), SUSER_SNAME(),
#CommandText, #LastObjectDefinition, dbo.Levenshtein(#CommandText, #LastObjectDefinition);
END TRY
BEGIN CATCH
INSERT INTO dbo.DDLEventsLog (Error)
SELECT ERROR_MESSAGE()
END CATCH
END
GO
I am developing an ADO.NET application. At some point in the DAL I call a stored-procedure named "CREATE_CUSTOMER". Although I set the SHORT_NAME field I still get the
"Msg 515, Level 16, State 2, Procedure CREATE_CUSTOMER, Line 29
Cannot insert the value NULL into column 'SHORT_NAME', table 'MYDB.app.CUSTOMER';
column does not allow nulls. INSERT fails." error.
When I inspect the query with the SQL profiler I get the following SQL runs on the server. As I Copy&Paste it to a new Query Window I still get the same error.
Do I miss something?
declare #p16 int
set #p16=NULL
exec sp_executesql N'[app].[CREATE_CUSTOMER]',
N'#SHORT_NAME nvarchar(11),
#MAIL_NAME nvarchar(18),
#MT_SALESPERSON_ID int,
#CREDIT_LIMIT decimal(1,0),
#CREDIT_LIMIT_CURRENCY_ID int,
#PAYMENT_TYPE_ID int,
#SALES_TERM_ID int,
#FREE_STORAGE_DAY_ID int,
#RISK_GROUP_ID int,
#SECTOR_ID int,
#OCCUPATION_ID int,
#STORAGE_FEE_ID int,
#STATUS smallint,
#IDENTITY int output',
#SHORT_NAME=N'NEW Corp',
#MAIL_NAME=N'NEW Corporation',
#MT_SALESPERSON_ID=3,
#CREDIT_LIMIT=0,
#CREDIT_LIMIT_CURRENCY_ID=1,
#PAYMENT_TYPE_ID=4,
#SALES_TERM_ID=7,
#FREE_STORAGE_DAY_ID=6,
#RISK_GROUP_ID=3,
#SECTOR_ID=13,
#OCCUPATION_ID=16,
#STORAGE_FEE_ID=6,
#STATUS=0,
#IDENTITY=#p16 output
select #p16
And my Stored Procedure is as follows :
CREATE PROCEDURE [app].[CREATE_CUSTOMER]
#SHORT_NAME varchar(250) = NULL,
#MAIL_NAME varchar(500) = NULL,
#MT_SALESPERSON_ID int = NULL,
#CREDIT_LIMIT decimal(18,2) = NULL,
#CREDIT_LIMIT_CURRENCY_ID int = NULL,
#PAYMENT_TYPE_ID int = NULL,
#SALES_TERM_ID int = NULL,
#FREE_STORAGE_DAY_ID int = NULL,
#RISK_GROUP_ID int = NULL,
#SECTOR_ID int = NULL,
#OCCUPATION_ID int = NULL,
#STORAGE_FEE_ID int = NULL,
#STATUS tinyint = NULL,
#IDENTITY INT = NULL OUTPUT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [app].[CUSTOMER]
([SHORT_NAME],
[MAIL_NAME],
[MT_SALESPERSON_ID],
[CREDIT_LIMIT],
[CREDIT_LIMIT_CURRENCY_ID],
[PAYMENT_TYPE_ID],
[SALES_TERM_ID],
[FREE_STORAGE_DAY_ID],
[RISK_GROUP_ID],
[SECTOR_ID],
[OCCUPATION_ID],
[STORAGE_FEE_ID],
[STATUS],
[CREATE_DATE],
[CREATE_USERID])
VALUES
(#SHORT_NAME,
#MAIL_NAME,
#MT_SALESPERSON_ID,
#CREDIT_LIMIT,
#CREDIT_LIMIT_CURRENCY_ID,
#PAYMENT_TYPE_ID,
#SALES_TERM_ID,
#FREE_STORAGE_DAY_ID,
#RISK_GROUP_ID,
#SECTOR_ID,
#OCCUPATION_ID,
#STORAGE_FEE_ID,
#STATUS,
GETDATE(),
CONTEXT_INFO())
SELECT #IDENTITY = SCOPE_IDENTITY()
END
This SQL code is being generated by the ADO.NET. Actual C# code is :
private static ICustomer CreateCustomer(ICustomer customer, int contextUserId)
{
try
{
string sql = "[app].[CREATE_CUSTOMER]";
SqlConnection conn = null;
using (conn = GetConnection())
{
SetContextInfomationToConnection(conn, contextUserId);
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.AddWithValue("#SHORT_NAME", customer.ShortName);
cmd.Parameters.AddWithValue("#MAIL_NAME", customer.MailName);
cmd.Parameters.AddWithValue("#MT_SALESPERSON_ID", customer.SalesPersonId);
cmd.Parameters.AddWithValue("#CREDIT_LIMIT", customer.CreditLimit);
cmd.Parameters.AddWithValue("#CREDIT_LIMIT_CURRENCY_ID", customer.CreditLimitCurrencyId);
cmd.Parameters.AddWithValue("#PAYMENT_TYPE_ID", customer.PaymentTypeId);
cmd.Parameters.AddWithValue("#SALES_TERM_ID", customer.SalesTermId);
cmd.Parameters.AddWithValue("#FREE_STORAGE_DAY_ID", customer.FreeStorageDayId);
cmd.Parameters.AddWithValue("#RISK_GROUP_ID", customer.RiskGroupId);
cmd.Parameters.AddWithValue("#SECTOR_ID", customer.SectorId);
cmd.Parameters.AddWithValue("#OCCUPATION_ID", customer.OccupationId);
cmd.Parameters.AddWithValue("#STORAGE_FEE_ID", customer.StorageFeeId);
cmd.Parameters.AddWithValue("#STATUS", customer.Status);
SqlParameter prmNewId = new SqlParameter("#IDENTITY", SqlDbType.Int, 4);
prmNewId.Direction = ParameterDirection.Output;
cmd.Parameters.Add(prmNewId);
cmd.ExecuteNonQuery();
int id = prmNewId.Value != DBNull.Value ? (int)prmNewId.Value : -1;
if (id > 0)
{
customer.Id = id;
return customer;
}
else
{
throw new Exception("Can not insert customer record with Id generation");
}
}
}
catch (Exception ex)
{
throw;
}
}
Your code is the equivalent of doing this:
DECLARE #SHORT_NAME nvarchar(11) = N'NEW Corp';
...
EXEC [app].[CREATE_CUSTOMER];
You are just declaring the parameters, never actually passing them to the procedure invocation. Your code should be like this:
exec sp_executesql N'[app].[CREATE_CUSTOMER] #SHORT_NAME, #MAIL_NAME, ...',
N'#SHORT_NAME nvarchar(11),
#MAIL_NAME nvarchar(18),
...',
#SHORT_NAME=N'NEW Corp',
#MAIL_NAME=N'NEW Corporation',
...
You must not only declare the parameters you pass to the batch, you must also use them when you invoke the procedure.
When I inspect the query with the SQL profiler I get the following SQL runs on the server. As I Copy&Paste it to a new Query Window I still get the same error
This sounds suspiciously like you are using a SqlCommand but forgot to set the CommandType to Procedure. the default is Text and will behave exactly as you observed.
Do not assign null values to ur variable, try only with DECLARING it as bellow
DECLARE #SHORT_NAME varchar(250) ,
instead of
#SHORT_NAME varchar(250) = NULL,
I have a stored procedure that I created and sometimes there are parameters that pass in a NULL value. I set up the stored procedure to take this into account, but every time I pass in a NULL value it doesn't return anything even if some of the other parameters are passed in. Can you please help? Here is my stored procedure. I'm not sure if it's the join that isn't correct or what.
Thanks.
#ProductID int = NULL,
#CollectionID int = NULL,
#ApplicationID int = NULL,
#StyleID int = NULL
AS
SELECT
dbo.CrossoverDesignTable.ColorNum, dbo.CrossoverDesignTable.CrossoverID,
dbo.ImagesWebsite.Description,
dbo.DesignNameTable.DesignDescription + ' ' + dbo.CrossoverDesignTable.ColorNum AS DesignColor,
dbo.CollectionTable.CollectionDescription
FROM
dbo.CrossoverDesignTable
INNER JOIN
dbo.DesignNameTable ON dbo.CrossoverDesignTable.DesignNameID = dbo.DesignNameTable.DesignNameID
INNER JOIN
dbo.ImagesWebsite ON dbo.CrossoverDesignTable.ProductImageID = dbo.ImagesWebsite.ProductImageID
INNER JOIN
dbo.CollectionTable ON dbo.CrossoverDesignTable.CollectionID = dbo.CollectionTable.CollectionID
WHERE
(dbo.CrossoverDesignTable.ProductID = #ProductID OR #ProductID IS NULL)
AND (dbo.CrossoverDesignTable.CollectionID = #CollectionID OR dbo.CrossoverDesignTable.CollectionID IS NULL)
AND (dbo.CrossoverDesignTable.ApplicationID = #ApplicationID OR #ApplicationID IS NULL)
AND (dbo.CrossoverDesignTable.ShowOnWeb = 'Yes')
AND (dbo.CrossoverDesignTable.StyleID = #StyleID OR #StyleID IS NULL)
RETURN
What I do in these scenarios is change the default for #ProductId to -1
DO NOT SEND ANY VALUE FOR THE PARAMETER, IF YOU SEND A NULL THEN IT WILL USE THAT VALUE. DEFAULT VALUES ARE ONLY USED WHEN THE PARAMETER IS NOT SENT.
#ProductID int = -1,
#CollectionID int = NULL,
#ApplicationID int = NULL,
#StyleID int = NULL
WHERE (#ProductID = -1 OR dbo.CrossoverDesignTable.ProductID = #ProductID)
AND .....
Assuming -1 is a value you don't have, I recommend you use this:
ISNULL(dbo.CrossoverDesignTable.ProductID, -1) = ISNULL(#ProductID, -1)
instead of:
dbo.CrossoverDesignTable.ProductID = #ProductID OR #ProductID IS NULL
and do the other comparisons in the same way.
If you want to keep your approach, you should do it this way, I think.
( (#ProductID is null) AND (dbo.CrossoverDesignTable.ProductID is null) )
OR (dbo.CrossoverDesignTable.ProductID = #ProductID)