I've created a trigger on a table called Project, the query successfully compiled however when I go to insert data into the table I get an error stating:
Msg 14636, Level 16, State 1, Procedure sp_send_dbmail, Line 112 [Batch Start Line 139]
No global profile is configured. Specify a profile name in the #profile_name parameter.
As well as:
Msg 3930, Level 16, State 1, Procedure sp_send_dbmail, Line 64 [Batch Start Line 139]
The current transaction cannot be committed and cannot support operations that write to the log file. Roll back the transaction.
I'm not completely familiar with the sp_send_dbmail procedure but I tried to have it so when a trigger is triggered it send an email out to xxxxx#gmail.com.
--Create a Table to hold the project audit
CREATE TABLE [dbo].[ProjectAudit](
projectId char(4) not null,
projectName varchar(50) null,
fundedbudget decimal(16,2) null,
firmFedID char(9) null,
statusID varchar(25) null,
projectTypeID char(4) null,
startDate date null,
projectedEndDate date null,
projectManager char(8) null,
dateTimeCreated smalldatetime null,
operation varchar(50),
userName varchar(50)
)
go
-- Project trigger
create TRIGGER trg_ProjectAudit
ON Project
After Insert,Delete,Update
AS
Begin
declare #name varchar(50)
declare #body varchar(100)
if exists(select projectId from inserted)
BEGIN
select #name = projectName
from inserted
set #name = #name + ' has been inputted into the project table.'
INSERT INTO ProjectAudit
(projectId, projectName, fundedbudget, firmFedID, statusID, projectTypeID,
startDate, projectedEndDate, projectManager, operation, dateTimeCreated, userName)
SELECT projectId, projectName, fundedbudget, firmFedID, statusID, projectTypeID,
startDate, projectedEndDate, projectManager, 'INSERT', getdate(), System_user
FROM Inserted
exec msdb.dbo.sp_send_dbmail #recipients = 'xxxxx#gmail.com',
#body = #name
END
if exists(select projectId from deleted)
begin
select #name = projectName
from deleted
set #name = #name + ' has been deleted from the project table.'
INSERT INTO ProjectAudit
(projectId, projectName, fundedbudget, firmFedID, statusID, projectTypeID,
startDate, projectedEndDate, projectManager, operation, dateTimeCreated, userName)
SELECT projectId, projectName, fundedbudget, firmFedID, statusID, projectTypeID,
startDate, projectedEndDate, projectManager, 'DELETE', getdate(), System_user
FROM deleted
exec msdb.dbo.sp_send_dbmail #recipients = 'xxxxx#gmail.com',
#body = #name
end
--check if a column update
if (update(projectid) or update(projectTypeID))
begin
print 'ProjectID or ProjectTypeID column was updated'
exec msdb.dbo.sp_send_dbmail #recipients = 'xxx#gmail.com',
#body = 'Data has been updated in the project table.'
end
End
GO
Related
Some background info: i have a table named defects which has column named status_id and another column named date_closed ,i want to set date_closed after status_id has been updated
i already try to do this using after update trigger with the following code:
after update on eba_bt_sw_defects
for each row
declare
l_status number(20) := null;
begin
select status_id into l_status from eba_bt_sw_defects D,eba_bt_status S where D.status_id = S.id;
if l_status in ( select id from eba_bt_status where is_open = 'N' and NVL(is_enhancement,'N')='N') then
:NEW.DATE_CLOSED := LOCALTIMESTAMP ;
end if;
end;
but an error occured ( subquery not allowed in this contextCompilation failed)
i want a help
A couple of things that need fixing in your code:
In a trigger do not select from the table the trigger you're on. This will probably raise a ORA-04091: table name is mutating, trigger/function may not see it error.
IF l_variable IN (SELECT ...) is not a valid oracle syntax. It raises PLS-00405: subquery not allowed in this context
I don't have your data so here is a similar example:
drop table todos;
drop table statuses;
-- create tables
create table statuses (
id number generated by default on null as identity
constraint statuses_id_pk primary key,
status varchar2(60 char),
is_open varchar2(1 char) constraint statuses_is_open_ck
check (is_open in ('Y','N'))
)
;
create table todos (
id number generated by default on null as identity
constraint todos_id_pk primary key,
name varchar2(255 char) not null,
close_date timestamp with local time zone,
status_id number
constraint todos_status_id_fk
references statuses on delete cascade
)
;
-- load data
insert into statuses (id, status, is_open ) values (1, 'OPEN', 'Y' );
insert into statuses (id, status, is_open ) values (2, 'COMPLETE', 'N' );
insert into statuses (id, status, is_open ) values (3, 'ON HOLD', 'Y' );
insert into statuses (id, status, is_open ) values (4, 'CANCELLED', 'N' );
commit;
insert into todos (name, close_date, status_id ) values ( 'Y2 Security Review', NULL, 1 );
-- triggers
CREATE OR REPLACE TRIGGER todos_biu BEFORE
INSERT OR UPDATE ON todos
FOR EACH ROW
DECLARE
l_dummy NUMBER;
BEGIN
SELECT
1
INTO l_dummy
FROM
statuses
WHERE
is_open = 'N' AND
id = :new.status_id;
:new.close_date := localtimestamp;
EXCEPTION
WHEN no_data_found THEN
-- I'm assuming you want close_date to NULL if todo is re-opened.
:new.close_date := NULL;
END todos_biu;
/
update todos set status_id = 2;
select * from todos;
id name close_date status_id
1 Y2 Security Review 11-MAY-22 05.27.04.987117000 PM 2
So I'm setting up a schema in which I can input transactions of a journal entry independent of each other but also that rely on each other (mainly to ensure that debits = credits). I set up the tables, function, and trigger. Then, when I try to input values into the transactions table, I get the error below. I'm doing all of this in pgAdmin4.
CREATE TABLE transactions (
transactions_id UUID PRIMARY KEY DEFAULT uuid_generate_v1(),
entry_id INTEGER NOT NULL,
post_date DATE NOT NULL,
account_id INTEGER NOT NULL,
contact_id INTEGER NULL,
description TEXT NOT NULL,
reference_id UUID NULL,
document_id UUID NULL,
amount NUMERIC(12,2) NOT NULL
);
CREATE TABLE entries (
id UUID PRIMARY KEY,
test_date DATE NOT NULL,
balance NUMERIC(12,2)
CHECK (balance = 0.00)
);
CREATE OR REPLACE FUNCTION transactions_biut()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
EXECUTE 'INSERT INTO entries (id,test_date,balance)
SELECT
entry_id,
post_date,
SUM(amount) AS ''balance''
FROM
transactions
GROUP BY
entry_id;';
END;
$$;
CREATE TRIGGER transactions_biut
BEFORE INSERT OR UPDATE ON transactions
FOR EACH ROW EXECUTE PROCEDURE transactions_biut();
INSERT INTO transactions (
entry_id,
post_date,
account_id,
description,
amount
)
VALUES
(
'1',
'2019-10-01',
'101',
'MISC DEBIT: PAID FOR FACEBOOK ADS',
-200.00
),
(
'1',
'2019-10-01',
'505',
'MISC DEBIT: PAID FOR FACEBOOK ADS',
200.00
);
After I execute this input, I get the following error:
ERROR: column "id" of relation "entries" does not exist
LINE 1: INSERT INTO entries (id,test_date,balance)
^
QUERY: INSERT INTO entries (id,test_date,balance)
SELECT
entry_id,
post_date,
SUM(amount) AS "balance"
FROM
transactions
GROUP BY
entry_id;
CONTEXT: PL/pgSQL function transactions_biut() line 2 at EXECUTE
SQL state: 42703
There are a few problems here:
You're not returning anything from the trigger function => should probably be return NEW or return OLD since you're not modifying anything
Since you're executing the trigger before each row, it's bound to fail for any transaction that isn't 0 => maybe you want a deferred constraint trigger?
You're not grouping by post_date, so your select should fail
You've defined entry_id as INTEGER, but entries.id is of type UUID
Also note that this isn't really going to scale (you're summing up all transactions of all days, so this will get slower and slower...)
#chirs I was able to figure out how to create a functioning solution using statement-level triggers:
CREATE TABLE transactions (
transactions_id UUID PRIMARY KEY DEFAULT uuid_generate_v1(),
entry_id INTEGER NOT NULL,
post_date DATE NOT NULL,
account_id INTEGER NOT NULL,
contact_id INTEGER NULL,
description TEXT NOT NULL,
reference_id UUID NULL,
document_id UUID NULL,
amount NUMERIC(12,2) NOT NULL
);
CREATE TABLE entries (
entry_id INTEGER PRIMARY KEY,
post_date DATE NOT NULL,
balance NUMERIC(12,2),
CHECK (balance = 0.00)
);
CREATE OR REPLACE FUNCTION transactions_entries() RETURNS TRIGGER AS $$
BEGIN
IF (TG_OP = 'DELETE') THEN
INSERT INTO entries
SELECT o.entry_id, o.post_date, SUM(o.amount) FROM old_table o GROUP BY o.entry_id, o.post_date;
ELSIF (TG_OP = 'UPDATE') THEN
INSERT INTO entries
SELECT o.entry_id, n.post_date, SUM(n.amount) FROM new_table n, old_table o GROUP BY o.entry_id, n.post_date;
ELSIF (TG_OP = 'INSERT') THEN
INSERT INTO entries
SELECT n.entry_id,n.post_date, SUM(n.amount) FROM new_table n GROUP BY n.entry_id, n.post_date;
END IF;
RETURN NULL; -- result is ignored since this is an AFTER trigger
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER transactions_ins
AFTER INSERT ON transactions
REFERENCING NEW TABLE AS new_table
FOR EACH STATEMENT EXECUTE PROCEDURE transactions_entries();
CREATE TRIGGER transactions_upd
AFTER UPDATE ON transactions
REFERENCING OLD TABLE AS old_table NEW TABLE AS new_table
FOR EACH STATEMENT EXECUTE PROCEDURE transactions_entries();
CREATE TRIGGER transactions_del
AFTER DELETE ON transactions
REFERENCING OLD TABLE AS old_table
FOR EACH STATEMENT EXECUTE PROCEDURE transactions_entries();
Any thoughts on optimization?
I am using EF 5 and this is my SP
USE [MYDatabase] GO
SET ANSI_NULLS ON GO
SET QUOTED_IDENTIFIER ON GO
ALTER PROCEDURE [dbo].[SP_FirstAttend] #serviceStart date, #serviceEnd date AS
BEGIN
SET NOCOUNT OFF
SET FMTONLY OFF
--IF (1=0)
--BEGIN
--SET FMTONLY ON
BEGIN
DROP TABLE #temp1
CREATE TABLE #temp1 (id int, sid int, npi int, fiscal int, serviceStart date, serviceEnd date, fcode varchar(10), tid int, StudName varchar(200), TherName varchar (200))
INSERT INTO #temp1
SELECT ID,
mand.SID,
mand.NPI,
FiscalYear,
ServiceStart,
ServiceEnd,
FundingCode,
ther.TID,
RTRIM(stud.StudentLastName) + ' ' + RTRIM(stud.StudentFirstName),
RTRIM(ther.LastName) + ' ' + RTRIM(ther.FirstName)
FROM MandateMaster AS mand
JOIN TherapistMaster AS ther ON ther.NPI = mand.NPI
JOIN StudentMaster AS stud ON stud.SID = mand.SID
SELECT *,
(SELECT top(1) sid
FROM SessionDetail
WHERE SID = tb1.sid
AND TID = tb1.tid) AS val1
FROM #temp1 AS tb1
WHERE ServiceStart >= #serviceStart
AND ServiceStart <= #serviceEnd;
END
-- END
END
and its still giving me "Stored procedure returns no columns".
I read somewhere to set the
integrated security=True; in the connection string on web.config but still nothing worked.
I been trying to find the solutions for this but keep getting the same message. Please let me know what to do .
Thanks.
You got nothing as result because this condition IF (1=0) always returns false then your select statement is never hit.
Just remove this IF (1=0) and your stored procedure will return some data.
I am working on HW assignment learning about triggers and am having problems with syntax on both insert and delete DML ForTriggers as follows:
CREATE TRIGGER tr_PERSON_ForInsert
ON PERSON
FOR INSERT
AS
BEGIN
DECLARE #SSN CHAR(9)
SELECT #SSN = SSN FROM inserted
DECLARE #NAME VARCHAR(50)
SELECT #NAME = NAME FROM inserted
DECLARE #USERNAME VARCHAR(50)
SELECT #USERNAME USERNAME FROM INSERTED
declare #time time(7)
select #time = time from inserted
insert into PERSON_DEL_LOG
VALUES ('New person with SSN = ' +
Cast(#SSN as NVARchar(9)) +
CAST(#NAME AS NVARCHAR(50)) +
cast(#username as nvarchar(50)) +
cast(#time as nvarchar(20))
)
END
INSERT INTO PERSON('012675543', 'MIKE', '5467896543', 'MUSEUM', 'INTEL',
'BLUECROSS', '987654321')
CREATE TRIGGER tr_PERSON_ForDELETE
ON PERSON
FOR DELETE
AS
BEGIN
DECLARE #SSN CHAR(9)
SELECT #SSN = SSN FROM DELETED
DECLARE #NAME VARCHAR(50)
SELECT #NAME = NAME FROM DELETED
insert into PERSON_DEL_LOG
VALUES ('New person with SSN = ' +
Cast(#SSN as nvarchar(9)) +
Cast(#NAME as VARCHAR(50)) + 'is added at ' +
cast(Getdate() as nvarchar(20))
)
END
DELETE FROM PERSON WHERE NAME = 987654321
SELECT * FROM PERSON_DEL_LOG
My PERSON_DEL_LOG table structure:
SSN, NAME, USERNAME, TIME
I need to know where exactly is my problem/s
IF NOT EXISTS(SELECT * FROM SYS.COLUMNS WHERE Name=N'isHidden' AND Object_ID=Object_ID(N'Templates'))
BEGIN
BEGIN TRANSACTION
GO
CREATE TABLE dbo.Tmp_Templates
(
ID int NOT NULL IDENTITY (1, 1),
isHidden bit NULL,
FileName nvarchar(255) NOT NULL,
Name nvarchar(255) NOT NULL,
Description nvarchar(1024) NULL,
UploadedByTVDBUsersID int NOT NULL,
Created datetime NOT NULL
)
GO
SET IDENTITY_INSERT dbo.Tmp_Templates ON
GO
IF EXISTS(SELECT * FROM dbo.Templates)
EXEC('INSERT INTO dbo.Tmp_Templates (ID, FileName, Name, Description, UploadedByTVDBUsersID, Created)
SELECT ID, FileName, Name, Description, UploadedByTVDBUsersID, Created FROM dbo.Templates WITH (HOLDLOCK TABLOCKX)')
GO
SET IDENTITY_INSERT dbo.Tmp_Templates OFF
GO
DROP TABLE dbo.Templates
GO
EXECUTE sp_rename N'dbo.Tmp_Templates', N'Templates', 'OBJECT'
GO
ALTER TABLE dbo.Templates ADD CONSTRAINT
PK__Templates__499219E9 PRIMARY KEY CLUSTERED
(
ID
)
GO
PRINT N' Templates ADD isHidden'
COMMIT
END
Results in error:
Msg 102, Level 15, State 1, Line 7 Incorrect syntax near
'TRANSACTION'. Caution: Changing any part of an object name could
break scripts and stored procedures.
Update:
Excluding the IF statement wrapping the transaction this SQL is generated by Microsoft SQL Server Management Studio.
If I remove the wrapping IF statement then everything works, but I only need the change to happen if the field isn't already there. How can I make the IF statement work properly?
Um... why the -1 and the vote to close?
I had to wrap each part of the transaction in an IF statement so the GOs were not embedded in an IF statement. The following TSQL works just fine. The transaction updates the schema as expected.
BEGIN TRANSACTION
GO
IF NOT EXISTS(SELECT * FROM SYS.COLUMNS WHERE Name=N'isHidden' AND Object_ID=Object_ID(N'Templates'))
BEGIN
CREATE TABLE dbo.Tmp_Templates
(
ID int NOT NULL IDENTITY (1, 1),
isHidden bit NULL,
FileName nvarchar(255) NOT NULL,
Name nvarchar(255) NOT NULL,
Description nvarchar(1024) NULL,
UploadedByTVDBUsersID int NOT NULL,
Created datetime NOT NULL
)
ALTER TABLE dbo.Tmp_Templates ADD PRIMARY KEY (ID)
END
GO
IF NOT EXISTS(SELECT * FROM SYS.COLUMNS WHERE Name=N'isHidden' AND Object_ID=Object_ID(N'Templates'))
BEGIN
SET IDENTITY_INSERT dbo.Tmp_Templates ON
END
GO
IF NOT EXISTS(SELECT * FROM SYS.COLUMNS WHERE Name=N'isHidden' AND Object_ID=Object_ID(N'Templates'))
BEGIN
IF EXISTS(SELECT * FROM dbo.Templates)
EXEC('INSERT INTO dbo.Tmp_Templates (ID, FileName, Name, Description, UploadedByTVDBUsersID, Created)
SELECT ID, FileName, Name, Description, UploadedByTVDBUsersID, Created FROM dbo.Templates WITH (HOLDLOCK TABLOCKX)')
END
GO
IF NOT EXISTS(SELECT * FROM SYS.COLUMNS WHERE Name=N'isHidden' AND Object_ID=Object_ID(N'Templates'))
BEGIN
SET IDENTITY_INSERT dbo.Tmp_Templates OFF
END
GO
IF NOT EXISTS(SELECT * FROM SYS.COLUMNS WHERE Name=N'isHidden' AND Object_ID=Object_ID(N'Templates'))
BEGIN
DROP TABLE dbo.Templates
END
GO
IF NOT EXISTS(SELECT * FROM SYS.COLUMNS WHERE Name=N'isHidden' AND Object_ID=Object_ID(N'Templates'))
BEGIN
EXECUTE sp_rename N'dbo.Tmp_Templates', N'Templates', 'OBJECT'
PRINT N' Templates ADD isHidden'
END
GO
COMMIT
first GO statement split your query to
IF NOT EXISTS(SELECT * FROM SYS.COLUMNS WHERE Name=N'isHidden' AND Object_ID=Object_ID(N'Templates'))
BEGIN
BEGIN TRANSACTION
//error - END missing
And there is BEGIN keyword without END.
You need to remove GO statement.
UPDATE:
IF 1 = 1
BEGIN
SELECT * FROM someTable
GO
END
also generate Msg 102, Level 15, State 1, Line 3
Incorrect syntax near 'someTable'.
SqlServer won't allow you to use sp_rename inside the transaction since it could break things badly.
You can drop and add the table again, on in your case, you can also use a temporale table to do the query work, truncate the old table, and move rows from temp into Templates.
Sample temp table
CREATE TABLE #myTempTable
(
DummyField1 INT,
DummyField2 VARCHAR(20)
)
Reference
http://msdn.microsoft.com/en-us/library/ms188351.aspx