SQL Server Stored Procedure Syntax Error - sql-server

I am trying to write a stored procedure that returns a deposit record for a specific person, the number of deposits for that person and the row number of that deposit for that person. The parameter #personID is always supplied the correct personID; however #SpecificRow is either 0 (meaning: return most recent deposit) or a row number (meaning:return record at this specific row).
Script:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [schema].[procedure]
#personID varchar(5),
#SpecificRow int,
#RowNumber INT OUTPUT,
#RowCount INT OUTPUT
AS
BEGIN
IF OBJECT_ID('#TempSortedDeposits') IS NOT NULL
DROP Table #TempSortedDeposits
-- get all deposits with record number into temp file for specific personID
SELECT
ROW_NUMBER() OVER (ORDER BY Date ASC) AS RecordNo, *
INTO
#TempSortedDeposits
FROM
persons.Deposits
WHERE
personID = #personID
-- get record count in file
SELECT #RowCount = COUNT(personID)
FROM persons.Deposits
WHERE personID = #personID
IF #SpecificRow = 0 --get most recent record
SET #RowNumber = #RowCount;
ELSE
--get record by rownumber
SET #RowNumber = #SpecificRow;
SELECT *
FROM #TempSortedDeposits
WHERE RecordNo = ­#RowNumber
END
When I try running the alter statement, I get the following error:
Msg 102, Level 15, State 1, Procedure procedure, Line 33 [Batch Start Line 9]
Incorrect syntax near '­'.
Any insight?
Thanks.

I deleted this line SELECT * FROM #TempSortedDeposits WHERE RecordNo = #RowNumber and manually re-type it then it worked.
This is because the error occurs due to copy and paste. That result to pasted code contains unprintable characters like d non-braking spaces.

Just a side note... your #TempSortedDeposits table dropping like you think it is.
Here's a quick example:
create table #TempSortedDeposits (i int)
insert into #TempSortedDeposits
values
(1)
IF OBJECT_ID('#TempSortedDeposits') IS NOT NULL DROP TABLE #TempSortedDeposits
select * from #TempSortedDeposits
If you run this the first time, it will return 1 when it shouldn't, because it should have been dropped. On the second run (same connection) you will get this error, showing you that the table still exists and wasn't dropped:
Msg 2714, Level 16, State 6, Line 2 There is already an object named
'#TempSortedDeposits' in the database.
To fix this, change the syntax to:
IF OBJECT_ID('tempdb..#TempSortedDeposits') IS NOT NULL DROP TABLE #TempSortedDeposits
Here is a test
create table #TempSortedDeposits (i int)
insert into #TempSortedDeposits
values
(1)
IF OBJECT_ID('tempdb..#TempSortedDeposits') IS NOT NULL DROP TABLE #TempSortedDeposits
select * from #TempSortedDeposits
If you first manually drop the table (since we created it with the last run) and then run this, you will get the error message:
Msg 208, Level 16, State 0, Line 7 Invalid object name
'#TempSortedDeposits'.
Which means the select failed, thus showing that the table was in fact dropped.

I have removed the extra character present in below line and re execute this proc. Line is
SELECT * FROM #TempSortedDeposits WHERE RecordNo = #RowNumber

Related

How to get the information that the update was used in the trigger?

I'm creating a trigger that gets the information when the user deletes or modifies the payment method insert the D for deleted and M for modified, the is being used in the trigger o for DELETE, update.
CREATE TRIGGER [dbo].[Trg_forpag_Drop]
on [dbo].[CUPONS2]
for DELETE, update
as
BEGIN
DECLARE #seqecf INT,
#seqecf2 INT,
#CODFORPAG INT,
#NOMOPERADORES INT,
#isDelivery char(1),
#Data datetime,
#status char(1)
SELECT #seqecf = deleted.SEQECF, #CODFORPAG = deleted.CODFORPAG FROM DELETED
SELECT #nomoperadores = codope, #isDelivery = cupdelivery FROM CUPONS WHERE SEQECF = #SEQECF
if #isDelivery = 'S' AND EXISTS (SELECT * FROM DELETED)
insert into forpagdel (seqecfforpagdel, codope, datforpagdel, codforpagdel, movstat) select deleted.seqecf, #nomoperadores, getDate(), deleted.codforpag, 'D' from DELETED
else IF exists (SELECT * FROM INSERTED)
insert into forpagdel (seqecfforpagdel, codope, datforpagdel, codforpagdel, movstat) select seqecf, #nomoperadores, getDate(), codforpag, 'M' from update
END
And the return of SQL is this:
Msg 156, Level 15, State 1, Procedure Trg_forpag_Drop, Line 24 [Batch 7 Start Line]
Incorrect syntax next to the 'update' keyword.
Is it possible to get the information when the update is used?
Note: I tested it with inserted, but it ends up NULL the codope field because its select comes from a deleted

SQL Server trigger does not recognize inserted row

I have simple SQL Server trigger and for some reason it does not recognize INSERTED row.
Here is code:
-- code
DROP TABLE a;
GO
CREATE TABLE a
(
id INT IDENTITY(1,1) PRIMARY KEY,
v INT
)
GO
DROP TABLE a_audit;
CREATE TABLE a_audit
(
id INT,
v INT,
[updated_at] [DATETIME] NOT NULL DEFAULT GETDATE()
)
GO
CREATE TRIGGER [dbo].[trg_a]
ON [dbo].[a]
AFTER INSERT, UPDATE, DELETE
NOT FOR REPLICATION
AS
BEGIN
SET NOCOUNT ON;
PRINT 'start';
DECLARE #xmltmp xml = (SELECT * FROM inserted FOR XML AUTO);
PRINT CONVERT(NVARCHAR(MAX), #xmltmp);
-- INSERT INTO a_audit (id, v) VALUES (inserted.id, inserted.v);
END;
GO
INSERT INTO a (v)
VALUES (1);
WAITFOR DELAY '00:00:01.11';
INSERT INTO a (v)
VALUES (2);
GO
SELECT * FROM a;
PRINT 'done'
It produces this output
start
<inserted id="1" v="1"/>
(1 row affected)
start
<inserted id="2" v="2"/>
(1 row affected)
(2 rows affected)
done
So I see that INSERTED row does exist.
However, if I remove comment on insert statements the output is this:
Msg 4104, Level 16, State 1, Procedure trg_a, Line 14 [Batch Start Line 16]
The multi-part identifier "inserted.id" could not be bound.
Msg 4104, Level 16, State 1, Procedure trg_a, Line 14 [Batch Start Line 16]
The multi-part identifier "inserted.v" could not be bound.
What is wrong?
inserted is a table, not a function. To INSERT from another table you need to use a INSERT INTO... SELECT ... FROM statement:
INSERT INTO a_audit (id,v)
SELECT id,
v
FROM inserted;
You can't reference a table's columns unless you use a FROM. For example just running the below would give the error below:
SELECT a_audit.id, a.audit.v;
The multi-part identifier "a_audit.id" could not be bound.
You would have to a SELECT...FROM:
SELECT id, v
FROM a_audit;

SQL Server Insert Null error in spite of providing not null values

I am trying to do an insert but it is giving an error stating that credits cannot be null but I am not providing null. Attached Screenshot
Code: Insert into [dbo].[Course] values (12,'Java',1,1,1);
Error: Msg 515, Level 16, State 2, Procedure trgAfterInsert, Line 31
Cannot insert the value NULL into column 'Credits', table 'DemoCollege.dbo.Course'; column does not allow nulls. INSERT fails.
The statement has been terminated.
Trigger:
Create trigger trgAfterInsert2 ON [dbo].[Course]
After Insert
AS
Declare #cid int;
Declare #cname nvarchar(50);
Select #cid = i.CourseID from inserted i;
Select #cname = i.Title from inserted i;
Insert into dbo.CourseTemp values (#cid, #cname);
Print 'After insert trigger fired';
GO
There's an insert trigger on the table & that's where the error is being generated from.
There must be some logic in that is converting the provided credit value to a null value somehow.
Just provide the columns where you want to insert the values.
Insert into [dbo].[Course](ColName1, ColName2, ColName3, ColName4, etc..) values (12,'Java',1,1,1);
Most probably you're missing a col in the middle

Trigger for three operation(Update,Delete,Insert) conversion error

I'm trying to create one trigger for insert,delete and update on customers table.
Trigger was created successfully ,however, I'm sure it contains many errors.
Here is my code of trigger
go
create trigger Onetrig
on customers
after update,insert,delete
as
declare #log varchar(100),#name varchar(20),#activity varchar(20)
begin
if exists(select * from deleted) and exists(select * from deleted)
set #activity = 'Update'
set #name = (select c_name from inserted)
set #log = 'Record Updated in database '+#name
insert into logs
values(#activity,#log,GETDATE())
if exists(select * from inserted) and not exists(select * from deleted)
set #activity = 'Insert'
set #name = (select c_name from inserted)
set #log = 'Record Inserted in database '+#name
insert into logs
values(#activity,#log,GETDATE())
if exists(select * from deleted) and not exists(select * from inserted)
set #activity = 'Insert'
set #name = (select c_name from deleted)
set #log = 'Record Deleted from database '+#name
insert into logs
values(#activity,#log,GETDATE())
end
My task is to populate the log table with the activities of these three operations. when I perform any of the three operations it throws error of some kind of conversion.
Msg 8152, Level 16, State 14, Procedure Onetrig, Line 11
String or binary data would be truncated.
The statement has been terminated.
customers table has some records.
Here is the code of my customers & log table:
create table logs
(activity varchar(20),report varchar(20),Time datetime)
create table customers
(c_id int primary key identity(1,1) NOT NULL,c_name varchar(20),c_lastname varchar(20))
What conversion am I missing?
You have declared report to be 20 characters in logs. But, you are inserting the string 'Record Updated in database '+#name into it. This has at least 27 characters.
Suggestions:
Fix the length of the varchar fields. You might as well make them much longer, even up to 8000 characters.
When doing insert, always include the list of columns explicitly.
Fix the first if statement to refer to inserted and deleted, so the logic makes sense.
Put semicolons at the end of each statement.
Gordon Linoff's answer is very good.
I would like to add that in case of trigger, following lines
set #name = (select c_name from inserted)
set #name = (select c_name from deleted)
assume that there is always only one row inserted / deleted / updated. Which is wrong because DML triggers are at statement level not at row level.
I would change (for I/U/D) thus:
if exists ...
begin
set #activity = 'U/I/D'
insert into dbo.logs (... columns ...) -- <-- You should use the schema (default schema is dbo)
select #activity, 'Record Updated in database ' + x.c_name, GETDATE()
-- ^
-- |
-- ----------------------------------------------------------
-- The maximum length of dbo.logs.c_name (!?) column should be
-- LEN('Record Updated in database') + 1 + MaxLength of dbo.customers.c_name column
from inserted as x -- or deleted
end

Display the number of rows inserted into a table from an existing table

Please how can display the number of rows inserted into an archive table using Microsoft SQL server 2012 with Stored Procedure. I have my code display below. I ran the code successful, but calling the stored procedure, I got error message says
Msg 8114, Level 16, State 5
Procedure p_moveTransHisttoArchive3a, Line 0 Error converting data type varchar to datetime.
Here is my code:
IF OBJECT_ID(N'Production.p_moveTransHisttoArchive3a', N'P') IS NOT NULL
DROP PROCEDURE Production.p_moveTransHisttoArchive3a;
GO
CREATE PROCEDURE Production.p_moveTransHisttoArchive3a
#FiveDaysAgo DATETIME
AS
SET NOCOUNT ON;
BEGIN
DECLARE #counter INT;
SET #counter = ##ROWCOUNT
INSERT INTO Production.TransactionHistoryArchive
SELECT*
FROM Production.TransactionHistory
WHERE TransactionDate <= #FiveDaysAgo
RETURN #counter --No of rows moved
END;
GO
Here is something close to what you want I think. Why is your inbound parameter named FiveDaysAgo? If you want to always get rows that are older than five days ago that belongs INSIDE the proc, not as a parameter.
CREATE PROCEDURE Production.p_moveTransHisttoArchive3a
#FiveDaysAgo DATETIME
, #RowCount int OUTPUT
AS
set nocount on;
INSERT INTO Production.TransactionHistoryArchive
(
Col1
, Col2
)
SELECT Col1
, Col2
FROM Production.TransactionHistory
WHERE TransactionDate <= #FiveDaysAgo
select #RowCount = ##ROWCOUNT

Resources