This has been bugging me for a while, so finally decided to understand why it happened. Any version of SQL server 2005 on
I have a query I'm developing like this:
IF OBJECT_ID('tempdb..#ProdOrders') IS NOT NULL
DROP TABLE [#ProdOrders];
CREATE TABLE [#ProdOrders]
(
[Document No_] NVARCHAR(20)
,[Item No_] NVARCHAR(20)
,[PlannedQty] INT
);
INSERT INTO [#ProdOrders]
(
[Document No_]
,[Item No_]
,[PlannedQty]
)
Select ...
Now I Decide to add a column, so I change it to this (in same session)
IF OBJECT_ID('tempdb..#ProdOrders') IS NOT NULL
DROP TABLE [#ProdOrders];
CREATE TABLE [#ProdOrders]
(
[Document No_] NVARCHAR(20)
,[Item No_] NVARCHAR(20)
,[PlannedQty] INT
,[Facility] NVARCHAR(2)
);
INSERT INTO [#ProdOrders]
(
[Document No_]
,[Item No_]
,[PlannedQty]
,[Facility]
)
Select...
When I execute it, I get an error saying the new column (Facility) is unknown
Anyone got any idea why?
Thanks
Mark
Related
Given the following audit table:
CREATE TABLE Auditing.[Record Deletion Times]
(
ID BIGINT IDENTITY NOT NULL,
[Schema] NVARCHAR(128) NOT NULL,
[Table] NVARCHAR(256) NOT NULL,
[Record ID] INT NOT NULL,
[Date-Time] DATETIME2 NOT NULL,
[Record Information] NVARCHAR(1024) NULL,
CONSTRAINT [Record Deleted Times Primary Key] PRIMARY KEY CLUSTERED
(
ID ASC
),
CONSTRAINT [Record Deleted Modified Times Unique Key] UNIQUE NONCLUSTERED
(
[Schema] ASC,
[Table] ASC,
[Record ID] ASC,
[Date-Time] ASC
)
)
and the following data table:
CREATE TABLE [dbo].[Items]
(
[ID] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[Key] [varchar](50) NOT NULL,
[Value] [varchar](255) NOT NULL
)
I want a trigger that will record information to Record Deletion Times when it is deleted from Items. I have found that I am able to do this with an INSTEAD OF trigger (whereby I record the data then manually delete the record in the trigger) but was wondering why a FOR or AFTER trigger does not do the same thing without the need for me performing the deletion myself. My guess is that deleted doesn't contain any data about the record that was deleted once it was deleted (what's the best way to debug a trigger?).
This is the trigger I hoped to use which failed to record anything in Record Deletion Times:
CREATE TRIGGER [Items Deleted]
ON Items
FOR DELETE
AS
INSERT INTO Auditing.[Record Deletion Times]
SELECT
'dbo',
'Items',
deleted.ID,
GETUTCDATE(),
CONCAT
(
'Key: ''',
Items.Key,
''' Value: ''',
Items.Value,
''''
)
FROM Items
JOIN deleted ON deleted.ID = Items.ID
This is the trigger I ended-up using instead:
CREATE TRIGGER [Items Deleted]
ON Items
INSTEAD OF DELETE
AS
BEGIN
INSERT INTO Auditing.[Record Deletion Times]
SELECT
'dbo',
'Items',
deleted.ID,
GETUTCDATE(),
CONCAT
(
'Key: ''',
Items.Key,
''' Value: ''',
Items.Value,
''''
)
FROM Items
JOIN deleted ON deleted.ID = Items.ID
DELETE Items
FROM Items
JOIN deleted ON deleted.ID = Items.ID
END
You should not be selecting from your Items table since the row(s) you want are now deleted.
Just select from Deleted
Ie
INSERT INTO RecordDeletionTimes
SELECT
'dbo',
'Items',
ID,
GETUTCDATE(),
CONCAT
(
'Key: ''',
[Key],
''' Value: ''',
Value,
''''
)
FROM deleted ;
See Demo Fiddle
The best way to debug your trigger is to just select * from deleted and test in SSMS using a begin tran/rollback.
I'm using the below SQL query to create a table and copy the values from an excel:
CREATE TABLE teacher (
DAILY_ALLOWANCE INTEGER
,DATE_OF_BIRTH DATE
,EMAIL VARCHAR(35)
,FIRST_NAME VARCHAR(35)
,FULL_NAME VARCHAR(35)
,ID VARCHAR(35)
,NAME VARCHAR(35)
,NUMBER_OF_STUDENTS INTEGER
,OWNERID VARCHAR(35)
,SALARY INTEGER
,TEACHER_UNIQUE_ID VARCHAR(15)
,YEARS_OF_EXPERIENCE INTEGER
) copy teacher (
DAILY_ALLOWANCE
,DATE_OF_BIRTH
,EMAIL
,FIRST_NAME
,FULL_NAME
,ID
,NAME
,NUMBER_OF_STUDENTS
,OWNERID
,SALARY
,TEACHER_UNIQUE_ID
,YEARS_OF_EXPERIENCE
)
FROM 'C:\Users\Surendra Anand R\Desktop\Note!\Files\Teacher.csv' csv header;
But I'm getting an error:
ERROR: syntax error at or near "copy"
LINE 14: ) copy teacher (
Could anyone please explain what I'm missing?.
As #a_horse_with_no_name clarified,
The query needs to be run one by one.
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?
CREATE TABLE s_etpta.sfphierg (
hierar VARCHAR(10) NOT NULL,
libelle VARCHAR(40),
typfct VARCHAR(1),
utilcre VARCHAR(10),
datcre DATE,
utilmod VARCHAR(10),
datmod DATE,
CONSTRAINT i_sfphierg PRIMARY KEY(hierar)
)
CREATE TABLE s_etpta.hopsech (
horsect VARCHAR(40) NOT NULL,
libelle VARCHAR(40),
libcourt VARCHAR(20),
horcode VARCHAR(10),
CONSTRAINT i_hopsech PRIMARY KEY(horsect)
)
BEGIN
delete from SFPHIERG;
INSERT INTO SFPHIERG ("hierar", "libelle", "typfct", "utilcre", "datcre",
"utilmod", "datmod")
select '01'||horcode, E'Hircuit standard'||horcode, E'1', E'HQS', E'2007-01-
29', E' ', E'1900-01-01'
FROM HOPSECH where HOPSECH.IJIGHSUPPM like '1'
and not exists (select hierar from SFPHIERG where hierar like '01'||horcode);
INSERT INTO SFPHIERG ("hierar", "libelle", "typfct", "utilcre", "datcre",
"utilmod", "datmod")
select '00'||horcode, E'Circuit cascade'||horcode, E'1', E'HQS', E'2007-01-
29', E' ', E'1900-01-01'
FROM HOPSECH where HOPSECH.IJIGHSUPPR like '1'
and not exists (select hierar from SFPHIERG where hierar like '00'||horcode);
END;
In my functions's body I have two insert queries executed after a delete query.
The rows are correctly inserted when my first column doesn't exist, when it does I have the failed unique constraint error, when this error occur nothing is added into my table.
Is there a way I can stop this error from blocking all the inserts and only the inserts where my first column exists?
I have a table in which datas are given as follows
SkillId SkillName Experience KnowledgeLevelXId
6 c++ NULL NULL
7 Asp.net NULL NULL
9 Flex NULL NULL
10 Flash builder NULL NULL
I wrote a Sp for insertion
ALTER PROCEDURE [dbo].[SkillSettingSave]
(
#SkillName varchar(100)
)
AS
BEGIN
INSERT INTO [HRM_SkillSetting]
(
[SkillName]
)
VALUES
(
#SkillName
)
I need to add update query in above sp, where skillname should not be repeated.
You might check for existance of a record using exists. To avoid race condition you would do it in a single statement:
ALTER PROCEDURE [dbo].[SkillSettingSave]
(
#SkillName varchar(100)
)
AS
BEGIN
INSERT INTO [HRM_SkillSetting]
(
[SkillName]
)
-- Instead of using values you might use select
SELECT #SkillName
-- And insert row only if it does not exists
WHERE NOT EXISTS (SELECT NULL
FROM [HRM_SkillSetting]
WHERE SkillName = #SkillName
)
END