Update issue with stored procedure - sql-server

I am working with a Old tool and the database that was connected to this tool in long gone. I am new at this and need some help understanding this. I need help with writing the code i tried and error-ed out every time.
public void UpdateUser(string NewUser, string OldUser)
{
using (SqlConnection con = HSDatabaseConnection())
{
using (SqlCommand cmd = new SqlCommand("UpdateNames", con))
{
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.Add("#LogonName", System.Data.SqlDbType.VarChar).Value = NewUser;
cmd.Parameters.Add("#OldLogonName", System.Data.SqlDbType.VarChar).Value = OldUser;
cmd.ExecuteNonQuery();
}
con.Close();
}
}
I have 4 tables the only thing each table has in common is the column name "AN". I need to update "AN" if a agent changes there name legally
so far I have come up with this procedure
USE [HSDB]
GO
/****** Object: StoredProcedure [dbo].[UpdateNames] Script Date: 9/16/2016 12:32:33 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[UpdateNames]
--Add the parameters for the stored procedure here
#AN varchar(MAX)
AS
BEGIN
--SET NOCOUNT ON added to prevent extra result sets from
--interfering with SELECT statements.
SET NOCOUNT ON;
--Insert statements for procedure here
UPDATE Att
SET AN = #AN
WHERE (AN = #AN)
UPDATE MS
SET AN = #AN
WHERE (AN = #AN)
UPDATE Lost
SET AN = #AN
WHERE (AN = #AN)
UPDATE WeeklyCharges
SET AN = #AN
WHERE (AN = #AN)
END
Can some one please tell me what i am doing wrong. Thank you

Issue 1:
your c# code is passing 2 paramaters #LogonName and #OldLogonName but your stored procedure is only accepting 1 parameter #AN. So that should error out.
Issue 2:
all of your update statements are setting AN = to itself because you are saying when AN = #AN then set AN = #AN....
Without having more detail about the error and your data structures, which you should include in the future, it is a little difficult to say. However, you probably could do something like this in SQL-Server 2012 +:
USE [HSDB]
GO
/****** Object: StoredProcedure [dbo].[UpdateNames] Script Date: 9/16/2016 12:32:33 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[UpdateNames]
--Add the parameters for the stored procedure here
#LogonName varchar(100)
,#OldLogonName varchar(100)
AS
BEGIN
--SET NOCOUNT ON added to prevent extra result sets from
--interfering with SELECT statements.
SET NOCOUNT ON;
--Insert statements for procedure here
BEGIN TRY
IF NOT EXISTS (SELECT * FROM LogOnOrUserTable WHERE LogonName = #OldLogonName)
BEGIN
;THROW 51000, 'Old Logon Name Does Not Exists', 1
END
BEGIN TRANSACTION
UPDATE Att
SET AN = #LogonName
WHERE (AN = #OldLogonName)
UPDATE MS
SET AN = #LogonName
WHERE (AN = #OldLogonName)
UPDATE Lost
SET AN = #LogonName
WHERE (AN = #OldLogonName)
UPDATE WeeklyCharges
SET AN = #LogonName
WHERE (AN = #OldLogonName)
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0 ROLLBACK TRANSACTION
;THROW
END CATCH
END
What it does:
first tests to see if the old user name exists and if it doesn't throws an error.
then updates all of the tables where AN = old logon name and sets it to the new logon name
if any one of those fails it rolls back the transaction and throws an error so that you don't have a change half made

Related

Fire SQL Trigger When Column Value Changes

I am adding the date to a column in SQL when the 'workstatus' is 'completed', but my problem is, when I open and save the same job again in the software, it runs the trigger and changes the date again to a new value which I don't want.
I want the trigger to run only if the 'workstatus' value is something else than 'completed'.
GO
/****** Object: Trigger [dbo].[TRJCD_JOBREQUEST] Script Date: 06/25/2021 15:49:04 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[TRJCD_JOBREQUEST] ON [dbo].[TBL_JOBREQUEST]
AFTER UPDATE,INSERT
AS
if (Update (workstatus))
begin
DECLARE #Jobcompletiondate datetime
DECLARE #workstatus VARCHAR(15)
DECLARE #jobid int
select #workstatus = workstatus from inserted
select #jobid = jobid from inserted
select #Jobcompletiondate = GETDATE()
begin
if #workstatus='Completed'
update TBL_JOBREQUEST set JobCompDate=#Jobcompletiondate where jobid = #jobid
end
end
The following is how you should construct your trigger.
There is no need to assign any values to variables, triggers fire once per batch and always operate on the set of updated rows.
If you update a status to Completed you need to check it's not currently Completed, also if you want to retain the first JobCompDate even if the status is amended afterwards simply use a case expression to only update the column where it's currently NULL.
create or alter trigger [dbo].[TRJCD_JOBREQUEST] on [dbo].[TBL_JOBREQUEST]
after update,insert
as
if ##RowCount=0 return
set nocount on
if Update (workstatus)
begin
update t set
t.JobCompDate=case when t.JobCompDate is null then GetDate() else t.JobCompDate end
from inserted i join TBL_JOBREQUEST t on t.jobid=i.jobid
where i.workstatus='Completed'
and not exists (
select * from deleted d
where d.jobid=i.jobid and d.workstatus=i.workstatus
)
end
Please note that I do not have your data set, so I'm unable to test the trigger, however, based on what you provided in your question, I believe this is the answer you are seeking:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[TRJCD_JOBREQUEST] ON [dbo].[TBL_JOBREQUEST]
AFTER UPDATE,INSERT
AS
if (Update (workstatus))
begin
DECLARE #Jobcompletiondate datetime
DECLARE #currentworkstatus VARCHAR(15)
DECLARE #oldworkstatus VARCHAR(15)
DECLARE #jobid int
select #oldworkstatus = workstatus from deleted
select #currentworkstatus = workstatus from inserted
select #jobid = jobid from inserted
select #Jobcompletiondate = GETDATE()
begin
if #currentworkstatus='Completed' and #oldworkstatus <> 'Completed'
update TBL_JOBREQUEST set JobCompDate=#Jobcompletiondate where jobid = #jobid
end
end
You needed to check if the deleted workstatus does not equal Completed and only then should the trigger fire.

SQLServerException when using StoredProcedureItemReader

I am getting an error when I am trying to use StoredProcedureItemReader.
I am having a stored procedure written in Microsoft SQL server which has the following input and output parameters:
Stored Procedure Name: person_details
Input: #From, #To
Output is a combination of various columns from various tables.
Here is my code:
StoredProcedureItemReader<ClaimExtractDTO> reader = new StoredProcedureItemReader<>();
SqlParameter[] parameter = {new SqlParameter("#From", java.sql.Types.BIGINT), new SqlParameter("#To", java.sql.Types.BIGINT)};
PreparedStatementSetter statementValues = new PreparedStatementSetter() {
#Override
public void setValues(PreparedStatement ps) throws SQLException {
ps.setLong(1, minValue); //minValue - Input 1
ps.setLong(2, maxValue); //maxValue - Input 2
}
};
reader.setDataSource(dataSource);
reader.setProcedureName("dbo.person_details");
reader.setParameters(parameter);
reader.setPreparedStatementSetter(statementValues);
reader.setRowMapper(new BeanPropertyRowMapper<>(ClaimExtractDTO.class));
return reader;
When running the above code I am getting
Caused by: org.springframework.dao.TransientDataAccessResourceException: Executing stored procedure; SQL [{call dbo.person_details(?, ?)}]; The index 0 of the output parameter is not valid.; nested exception is com.microsoft.sqlserver.jdbc.SQLServerException: The index 0 of the output parameter is not valid.
at org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:110) ~[spring-jdbc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72) ~[spring-jdbc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81) ~[spring-jdbc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81) ~[spring-jdbc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
at org.springframework.batch.item.database.StoredProcedureItemReader.openCursor(StoredProcedureItemReader.java:229) ~[spring-batch-infrastructure-4.2.3.BUILD-SNAPSHOT.jar:4.2.3.BUILD-SNAPSHOT]
at org.springframework.batch.item.database.AbstractCursorItemReader.doOpen(AbstractCursorItemReader.java:428) ~[spring-batch-infrastructure-4.2.3.BUILD-SNAPSHOT.jar:4.2.3.BUILD-SNAPSHOT]
at org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.open(AbstractItemCountingItemStreamItemReader.java:150) ~[spring-batch-infrastructure-4.2.3.BUILD-SNAPSHOT.jar:4.2.3.BUILD-SNAPSHOT]
... 18 common frames omitted
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: The index 0 of the output parameter is not valid.
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(SQLServerException.java:234) ~[mssql-jdbc-7.4.1.jre8.jar:na]
at com.microsoft.sqlserver.jdbc.SQLServerCallableStatement.getterGetParam(SQLServerCallableStatement.java:403) ~[mssql-jdbc-7.4.1.jre8.jar:na]
at com.microsoft.sqlserver.jdbc.SQLServerCallableStatement.getObject(SQLServerCallableStatement.java:705) ~[mssql-jdbc-7.4.1.jre8.jar:na]
at com.zaxxer.hikari.pool.HikariProxyCallableStatement.getObject(HikariProxyCallableStatement.java) ~[HikariCP-3.4.5.jar:na]
at org.springframework.batch.item.database.StoredProcedureItemReader.openCursor(StoredProcedureItemReader.java:222) ~[spring-batch-infrastructure-4.2.3.BUILD-SNAPSHOT.jar:4.2.3.BUILD-SNAPSHOT]
... 20 common frames omitted
when I am running the stored procedure on SQL server using exec dbo.person_details '1', '100'; it is running fine and getting me the output which consists of 20 columns from various tables.
I even set set nocount on on the Procedure.
I tried it with SqlParameter[] parameter = {new SqlOutParameter("personKey", java.sql.Types.INTEGER), new SqlParameter("#From", java.sql.Types.BIGINT), new SqlParameter("#To", java.sql.Types.BIGINT)}; thinking there should be outparameters defined. I still get the same error that's mentioned above.
Main contents of the procedure:
USE [employee]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
set nocount on
GO
ALTER PROCEDURE [dbo].[person_details]
#From BIGINT,
#To BIGINT
AS
....
Can anyone tell me how I can resolve this issue. Thanks in advance!
You need to ensure you set SET NOCOUNT ON WITHIN the stored procedure itself in order to avoid this error. No output parameters are expected but the rowcount is returned as one.
You are also running the store procedure directly again SQL Server as follows:
exec dbo.person_details '1', '100';
i.e. two input parameters and no output parameters.
Yet in your code you are setting up the parameters as follows:
SqlParameter[] parameter = {new SqlOutParameter("personKey", java.sql.Types.INTEGER), new SqlParameter("#From", java.sql.Types.BIGINT), new SqlParameter("#To", java.sql.Types.BIGINT)};
i.e. one output parameter and two input parameters.
It works after I put set nocount on inside my procedure
USE [employee]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[person_details]
#From BIGINT,
#To BIGINT
AS
set nocount on;
and my SQLParameters will look like
SqlParameter[] parameter = {new SqlParameter("#From", java.sql.Types.BIGINT), new SqlParameter("#To", java.sql.Types.BIGINT)};

SQL Server Trigger fires unexplainably

I've got a trigger on a table. It's a very simple trigger, set to after insert, send me an e-mail. Since I've put that trigger on, I've been sent e-mails by the system every 5 or 6 minutes or so. There is just one problem.
Whenever I receive an e-mail, the table is EMPTY
Here is my trigger
USE [didaprod]
GO
/****** Object: Trigger [dbo].[Caseplayer_CaseId_Restore_insert_mail] Script Date: 09-08-2016 11:59:41 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE trigger [dbo].[Caseplayer_CaseId_Restore_insert_mail] on [dbo].[Caseplayer_CaseId_Restore]
AFTER INSERT
as
SET NOCOUNT ON
declare #tekst nvarchar(500);
set #tekst = 'caseid sat til null på caseplayer! Tjek Caseplayer_CaseId_Restore tabel!' + convert(varchar,getdate(),105);
EXEC msdb.dbo.sp_send_dbmail #profile_name = 'Mail',
#recipients = 'kk#byggeevaluering.dk',
#subject = 'CASEID SAT TIL NULL!!!',
#body = #tekst
SET NOCOUNT OFF
GO
I've tried to manually insert a row, or a couple of rows in the table, just to check, and yes, the trigger fires as well, when there is a proper insert. But I cannot explain why I keep receiving the e-mails!. As for the table itself, it's got nothing fancy.
USE [didaprod]
GO
/****** Object: Table [dbo].[Caseplayer_CaseId_Restore] Script Date: 09-08-2016 12:04:46 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Caseplayer_CaseId_Restore](
[Id] [int] NOT NULL,
[CaseId] [int] NOT NULL,
[TimeOfChange] [datetime] NOT NULL
) ON [PRIMARY]
GO
I've disabled the trigger now, and confirmed that the e-mails have stopped. But this seems like an almost magic problem for me, and I would love to get an answer.
Suppose I do
delete from [Caseplayer_CaseId_Restore]
And just leave the table alone.
I'll still get e-mails from the system, telling me to check the table. When I then perform a
select * from [Caseplayer_CaseId_Restore]
The table is empty
SQL Server triggers fire once per statement rather than once per row. That's why it's important to write triggers that use inserted appropriately, to deal with the fact that it may contain 1, many, or zero rows.
I suspect that it's the latter case here. (I.e. a regularly executed INSERT statement that is in fact inserting zero rows)
So, you might want something like:
CREATE trigger [dbo].[Caseplayer_CaseId_Restore_insert_mail]
on [dbo].[Caseplayer_CaseId_Restore]
AFTER INSERT
as
SET NOCOUNT ON
IF EXISTS(select * from inserted)
BEGIN
declare #tekst nvarchar(500);
set #tekst = 'caseid sat til null på caseplayer! Tjek Caseplayer_CaseId_Restore tabel!' + convert(varchar,getdate(),105);
EXEC msdb.dbo.sp_send_dbmail #profile_name = 'Mail',
#recipients = 'kk#byggeevaluering.dk',
#subject = 'CASEID SAT TIL NULL!!!',
#body = #tekst
END

Inno Setup Executing a large sql script file during installation

I am trying to connect with SQL server and execute a script file while installing the setup. I managed to execute a simple script without GO statement in it.
Question: Is there a way to pass (skip) the GO word and execute the script?
ADOConnection.ConnectionString :=
'Provider=SQLOLEDB;' +
'Data Source=' + ServerEdit.Text + ';' +
'User Id=' + UsernameEdit.Text + ';' +
'Password=' + PasswordEdit.Text + ';' +
'Trusted_Connection=no;';
end;
ADOConnection.Open;
try
ADOCommand := CreateOleObject('ADODB.Command');
ADOCommand.ActiveConnection := ADOConnection;
ScriptPath := ExpandConstant('{tmp}\Script2.sql');
if LoadStringFromFile(ScriptPath, ssquery) then
begin
StringChangeEx(ssquery, 'GO', '', True);
SQLQuery := ssquery
ADOCommand.CommandText := SQLQuery;
ADOCommand.Execute(NULL, NULL, adCmdText or adExecuteNoRecords);
Result := True;
end;
finally
ADOConnection.Close;
end;
The Script2.sql
USE northwind3
GO
/****** Object: StoredProcedure [dbo].[Customers By City] Script Date: 5/25/2016 8:35:45 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[Customers By City]
-- Add the parameters for the stored procedure here
(#param1 NVARCHAR(20))
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
SELECT CustomerID, ContactName, CompanyName, City from Customers as c where c.City=#param1
END
GO
/****** Object: StoredProcedure [dbo].[Customers Count By Region] Script Date: 5/25/2016 8:35:45 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[Customers Count By Region]
-- Add the parameters for the stored procedure here
(#param1 NVARCHAR(15))
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #count int
SELECT #count = COUNT(*)FROM Customers WHERE Customers.Region = #Param1
RETURN #count
END
NOTE: I am using ADOB for the connection in similar way TLama's answer to How to connect to MS SQL Server using InnoSetup? Except in my case I have to include GO in my script.
Thank you.
You can split the SQL script to separate script files long the go statements and execute them individually in a sequence.
If that's not an option, you have to use API/tool that supports the go statement, i.e. the sqlcmd tool, instead of the ADO.
Or just load the script file and remove the go statements before you execute the script over ADO.
You can use StringChange function.

Must Declare Scalar variable on creating stored procedure

I am creating first time stored procedure but I don't know why this showing error. I also have many other post but didn't understand if someone can tell what I am doing wrong here.
Stored procedure:
SET ANSI_NULLS ON
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[DeleteOrganization]
#ORG_ID bigint
AS
BEGIN
SET NOCOUNT ON;
delete from Organizations where ORG_ID=#ORGID
delete from Institutes where INS_FK_ORGID=#ORGID
delete from Branches where BRN_ID=#ORGID
END
The variable is declared as #ORG_ID bigint with an underscore but you refer to it without the underscore: #ORGID. Pick one and use it consistently.
This should work:
ALTER PROCEDURE [dbo].[DeleteOrganization]
#ORGID bigint
AS
BEGIN
SET NOCOUNT ON;
DELETE FROM Organizations WHERE ORG_ID = #ORGID
DELETE FROM Institutes WHERE INS_FK_ORGID = #ORGID
DELETE FROM Branches WHERE BRN_ID = #ORGID
END

Resources