Has anyone got a clue on how to address the following issue?
When attempting to update a database via migration I get the following error:
An explicit value for the identity column in table 'HistoryUsers' can only be specified when a column list is used and IDENTITY_INSERT is ON.
Running the trigger in Management studio works!
The code giving the error:
migrationBuilder.Sql(#"
CREATE TRIGGER [Users_TRIGGER]
ON [Users]
AFTER UPDATE, INSERT, DELETE
AS
DECLARE #EmpID int, #user nvarchar(max), #activity nvarchar(200);
IF EXISTS(SELECT * FROM inserted) AND EXISTS (SELECT * FROM deleted)
BEGIN
SET #activity = 'UPDATE';
SET #user = SYSTEM_USER;
INSERT INTO [HistoryUsers]
SELECT *, #activity, CURRENT_TIMESTAMP, #user
FROM inserted
END
IF EXISTS (SELECT * FROM inserted) AND NOT EXISTS(SELECT * FROM deleted)
BEGIN
SET #activity = 'INSERT';
SET #user = SYSTEM_USER;
INSERT INTO [HistoryUsers]
SELECT *, #activity, CURRENT_TIMESTAMP, #user
FROM inserted
END
IF EXISTS(SELECT * FROM deleted) AND NOT EXISTS(SELECT * FROM inserted)
BEGIN
SET #activity = 'DELETE';
SET #user = SYSTEM_USER;
INSERT INTO [HistoryUsers]
SELECT *, #activity, CURRENT_TIMESTAMP, #user
FROM deleted
END
GO
");
I have a table in DB:
<createTable tableName="api_consumer">
<column name="id"
type="INTEGER">
<constraints primaryKey="true"
primaryKeyName="PK_api_consumer_id"/>
</column>
<column name="business_id"
type="VARCHAR(50)"/>
<column name="type"
type="VARCHAR(32)"/>
<column name="status"
type="VARCHAR(32)"/>
<column name="description"
type="VARCHAR(256)"/>
<column name="created_by"
type="VARCHAR(64)"/>
<column name="created_date"
type="DATETIME"/>
<column name="modified_by"
type="VARCHAR(64)"/>
<column name="modified_date"
type="DATETIME"/>
<!--TTP below-->
<column name="name"
type="VARCHAR(64)">
</column>
<column name="origin_country"
type="VARCHAR(64)"/>
<column name="license_authority_name"
type="VARCHAR(64)"/>
<column name="registration_date"
type="DATETIME"/>
<column name="api_callback_url"
type="VARCHAR(256)"/>
<column name="application_base_url"
type="VARCHAR(256)"/>
<column name="authorization_callback_url"
type="VARCHAR(256)"/>
<column name="address"
type="INTEGER">
<constraints foreignKeyName="FK_api_consumer_address_id"
references="address(id)"/>
</column>
<column name="local_address"
type="INTEGER">
<constraints foreignKeyName="FK_api_consumer_local_address_id"
references="address(id)"/>
</column>
<column name="license"
type="INTEGER">
<constraints foreignKeyName="FK_api_consumer_license_id"
references="license(id)"/>
</column>
</createTable>
Generated in SQL dialect:
CREATE TABLE api_consumer
(
id INTEGER NOT NULL
CONSTRAINT "PK_api_consumer_id"
PRIMARY KEY,
business_id VARCHAR(50),
type VARCHAR(32),
status VARCHAR(32),
description VARCHAR(256),
created_by VARCHAR(64),
created_date TIMESTAMP,
modified_by VARCHAR(64),
modified_date TIMESTAMP,
name VARCHAR(64),
origin_country VARCHAR(64),
license_authority_name VARCHAR(64),
registration_date TIMESTAMP,
api_callback_url VARCHAR(256),
application_base_url VARCHAR(256),
authorization_callback_url VARCHAR(256),
address INTEGER
CONSTRAINT FK_api_consumer_address_id
REFERENCES address,
local_address INTEGER
CONSTRAINT FK_api_consumer_local_address_id
REFERENCES address,
license INTEGER
CONST
RAINT FK_api_consumer_license_id
REFERENCES license
);
and from the IntelliJ DB console I am trying to insert value to this table and test my triggers on it.
My insert is like:
INSERT INTO api_consumer VALUES ('11', '101', 'PSD2', 'NEW', 'TEST OF TRIGGER ON INSERT', 'kkwiatkowski', CURRENT_TIMESTAMP, null, null, 'SPRAWDZAM_COS', 'PL', null, null, null, null, null, 1, 1, 1);
And I am getting an error like:
sql> INSERT INTO api_consumer VALUES ('11', '101', 'PSD2', 'NEW', 'TEST OF TRIGGER ON INSERT', 'kkwiatkowski', CURRENT_TIMESTAMP, null, null, 'SPRAWDZAM_COS', 'PL', null, null, null, null, null, 1, 1, 1)
[2017-10-16 10:30:43] [42703] ERROR: column "insert" does not exist
[2017-10-16 10:30:43] Gdzie: PL/pgSQL function proc_subscription_audit_insert() line 3 at SQL statement
Word: "Gdzie" means Where in eng.
If I delete this id value: '11', then the insert query is invalid, cause the argument scope is moving on the right. Understandable.
[2017-10-16 10:39:08] [22007] ERROR: invalid input syntax for type timestamp: "SPRAWDZAM_COS"
[2017-10-16 10:39:08] Pozycja: 133
Word: "Pozycja" means Position in eng.
1) So how can I fix that?
2) How can I implement auto-increment value in here?
I have tried adding an autoIncrement="true" in the xml structure and then invoke this insert query without id argument. Neither this nor adding nextval(id) to the insert query works.
Edit:
procedures.xml
<changeSet id="1.0-procedures" author="blab">
<sql>
DROP FUNCTION IF EXISTS proc_api_consumer_audit_insert();
DROP FUNCTION IF EXISTS proc_api_consumer_audit_update();
DROP FUNCTION IF EXISTS proc_subscription_audit_insert();
DROP FUNCTION IF EXISTS proc_subscription_audit_update();
</sql>
<createProcedure>
CREATE FUNCTION proc_api_consumer_audit_insert()
RETURNS TRIGGER AS $api_consumer$
BEGIN
INSERT INTO api_consumer_audit(api_consumer_id, change_type, changed_by, changed_date, business_id_old, business_id_new, name_old, name_new, api_callback_url_old, api_callback_url_new, application_base_url_old, application_base_url_new, authorization_callback_url_old, authorization_callback_url_new, status_old, status_new) VALUES(NEW.id, 'INSERT', CURRENT_USER, CURRENT_TIMESTAMP, null, NEW.business_id, null, NEW.name, null, NEW.api_callback_url, null, NEW.application_base_url, null, NEW.authorization_callback_url, null, NEW.status);
RETURN NEW;
END;
$api_consumer$ LANGUAGE plpgsql;
</createProcedure>
<createProcedure>
CREATE FUNCTION proc_api_consumer_audit_update()
RETURNS TRIGGER AS $api_consumer$
BEGIN
INSERT INTO api_consumer_audit(api_consumer_id, change_type, changed_by, changed_date, business_id_old, business_id_new, name_old, name_new, api_callback_url_old, api_callback_url_new, application_base_url_old, application_base_url_new, authorization_callback_url_old, authorization_callback_url_new, status_old, status_new) VALUES(NEW.id, 'UPDATE', CURRENT_USER, CURRENT_TIMESTAMP, OLD.business_id, NEW.business_id, OLD.name, NEW.name, OLD.api_callback_url, NEW.api_callback_url, OLD.application_base_url, NEW.application_base_url, OLD.authorization_callback_url, NEW.authorization_callback_url, OLD.status, NEW.status);
RETURN NEW;
END;
$api_consumer$ LANGUAGE plpgsql;
</createProcedure>
<createProcedure>
CREATE FUNCTION proc_subscription_audit_insert()
RETURNS TRIGGER AS $subscription_audit$
BEGIN
INSERT INTO subscription_audit(subscription_id, change_type, status_old, status_new, valid_from_old, valid_from_new, valid_through_old, valid_through_new, changed_by, changed_date) VALUES (NEW.id, INSERT, null, NEW.status, null, NEW.valid_from, null, NEW.valid_through, CURRENT_USER, CURRENT_TIMESTAMP);
RETURN NEW;
END;
$subscription_audit$ LANGUAGE plpgsql;
</createProcedure>
<createProcedure>
CREATE FUNCTION proc_subscription_audit_update()
RETURNS TRIGGER AS $subscription_audit$
BEGIN
INSERT INTO subscription_audit(subscription_id, change_type, status_old, status_new, valid_from_old, valid_from_new, valid_through_old, valid_through_new, changed_by, changed_date) VALUES (NEW.id, 'UPDATE', OLD.status, NEW.status, OLD.valid_from, NEW.valid_from, OLD.valid_through, NEW.valid_through, CURRENT_USER, CURRENT_TIMESTAMP);
RETURN NEW;
END;
$subscription_audit$ LANGUAGE plpgsql;
</createProcedure>
<rollback>
DROP FUNCTION IF EXISTS proc_api_consumer_audit_insert();
DROP FUNCTION IF EXISTS proc_api_consumer_audit_update();
DROP FUNCTION IF EXISTS proc_subscription_audit_insert();
DROP FUNCTION IF EXISTS proc_subscription_audit_update();
</rollback>
</changeSet>
triggers.xml
<changeSet id="1.0-triggers" author="blab">
<sql>
DROP TRIGGER IF EXISTS trg_api_consumer_audit_insert ON api_consumer;
DROP TRIGGER IF EXISTS trg_api_consumer_audit_update ON api_consumer;
<!-- DROP TRIGGER IF EXISTS trg_api_consumer_audit_delete ON api_consumer-->
DROP TRIGGER IF EXISTS trg_subscription_audit_insert ON subscription;
DROP TRIGGER IF EXISTS trg_subscription_audit_update ON subscription;
<!-- DROP TRIGGER IF EXISTS trg_subscription_audit_delete ON subscription-->
</sql>
<createProcedure>
CREATE TRIGGER trg_api_consumer_audit_insert
AFTER INSERT ON api_consumer
FOR EACH ROW EXECUTE PROCEDURE proc_api_consumer_audit_insert();
</createProcedure>
<createProcedure>
CREATE TRIGGER trg_api_consumer_audit_update
AFTER UPDATE ON api_consumer
FOR EACH ROW EXECUTE PROCEDURE proc_api_consumer_audit_update();
</createProcedure>
<createProcedure>
CREATE TRIGGER trg_subscription_audit_insert
AFTER INSERT ON api_consumer
FOR EACH ROW EXECUTE PROCEDURE proc_subscription_audit_insert();
</createProcedure>
<createProcedure>
CREATE TRIGGER trg_subscription_audit_update
AFTER UPDATE ON api_consumer
FOR EACH ROW EXECUTE PROCEDURE proc_subscription_audit_update();
</createProcedure>
<rollback>
DROP TRIGGER IF EXISTS trg_api_consumer_audit_insert;
DROP TRIGGER IF EXISTS trg_api_consumer_audit_update;
DROP TRIGGER IF EXISTS trg_subscription_audit_insert;
DROP TRIGGER IF EXISTS trg_subscription_audit_update;
</rollback>
</changeSet>
Version: SQL Server 2008 R2
This trigger checks primary key violations, if any moves the row to the history table; and then deletes the row; and then inserts the row that caused the violation.
But it is not doing its job.
CREATE TRIGGER [dbo].[ONINSERT]
ON [dbo].[TICKETS]
Instead of INSERT
AS
BEGIN
DECLARE #ID VARCHAR(200)
SET NOCOUNT ON;
SET #ID = (SELECT TICKET_ID FROM inserted)
INSERT TICKET_HISTORY
SELECT * FROM TICKETS
WHERE
TICKET_ID = #ID ;
print 'Inserting ' + #id
DELETE FROM TICKETS
WHERE TICKET_ID = #ID;
print 'Deleting' + #id
INSERT TICKETS
SELECT * FROM inserted;
print 'Inserting back' + #id
Triggers fire only once even if you have multiple inserts,so in your case I don't see that happening...You don't need to delete the row again since instead of insert generally means "instead of insert do some custom action"
if exists
(
select 1 from inserted i
join
mytable t
on t.id=i.id
)
begin
--insert into tickets history
insert into ticketshistory
select i.* from inserted i
join
mytable t where t.id=i.id
---you can add custom logic to alert or simply ignore
return
end
--this is needed since if there is no violation you have to insert rows
insert into tickets
select * from inserted
I want bulk insert into a PostgreSQL database: backend code would create XML like
<items>
<i dt="2014-08-01" name="vvv" count="12" />
<i dt="2014-08-02" name="zzz" count="6" />
</items>
which I want to pass to a function and save all the values in one go.
But I'm stuck at xpath: each "column" seems to be an array of values, and I'm not sure how to insert them into a table then. Here's a test example:
CREATE TEMP TABLE temp_values (dt date, name varchar, count int);
WITH x AS (SELECT '
<items>
<i dt="2014-08-01" name="vvv" count="12" />
<i dt="2014-08-02" name="zzz" count="6" />
<i dt="2014-08-03" name="bbd" count="10" />
</items>'::xml AS t
)
INSERT INTO temp_values
SELECT
xpath('/items/i/#dt', t),
xpath('/items/i/#name', t),
xpath('/items/i/#count', t)
FROM x;
Now, in the end I want temp_values to have 3 records, as in the XML, but the table is empty.
If you comment out the "insert into" line, you'd see that the values are parsed correctly. It's just that it returns a single record where each column is an array, instead of returning multiple records.
What am I missing?
Ok, apparently unnest and array indexing is the solution:
unnest(array) | expand an array to a set of rows
So the code would be
CREATE TEMP TABLE temp_values (dt date, name varchar, count int) ON COMMIT DROP;
WITH x AS (SELECT '
<items>
<i dt="2014-08-01" name="vvv" count="12" />
<i dt="2014-08-02" name="zzz" count="6" />
<i dt="2014-08-03" name="bbd" count="10" />
</items>'::xml AS t
)
INSERT INTO temp_values
SELECT
CAST(CAST((xpath('//#dt', node))[1] as varchar) as date),
CAST((xpath('//#name', node))[1] as varchar),
CAST(CAST((xpath('//#count', node))[1] as varchar) as int)
FROM (SELECT unnest(xpath('/items/i', t)) AS node FROM x) sub;
SELECT * FROM temp_values
I'd prefer to delete some extra slashes before #:
CREATE TEMP TABLE temp_values (dt date, name varchar, count int) ON COMMIT DROP;
WITH x AS (SELECT '
<items>
<i dt="2014-08-01" name="vvv" count="12" />
<i dt="2014-08-02" name="zzz" count="6" />
<i dt="2014-08-03" name="bbd" count="10" />
</items>'::xml AS t
)
INSERT INTO temp_values
SELECT
CAST(CAST((xpath('#dt', node))[1] as varchar) as date),
CAST((xpath('#name', node))[1] as varchar),
CAST(CAST((xpath('#count', node))[1] as varchar) as int)
FROM (SELECT unnest(xpath('/items/i', t)) AS node FROM x) sub;
SELECT * FROM temp_values
How can you do a select in on more than 2100 values?
<cfquery name="result.qryData">
SELECT sub_acct_no, ...
FROM dbo.Closed_ORDER
WHERE ord_no IN <cfqueryparam cfsqltype="CF_SQL_varchar" value="#ValueList(qryOrd.ord_no)#" list="yes">
</cfquery>
Because of the ways that the tables are setup, linked Servers and JOINS are not an option.
When this is ran an error this thrown because there are new many fields being passed in.
First load the values into XML
<cfset var strResult = '<ul class="xoxo">'>
<cfloop query="qryOrd">
<cfset strResult &= '<li>#xmlformat(ord_no)#</li>'>
</cfloop>
<cfset strResult &= '</ul>'>
Then use the xml in the sql query
<cfquery name="result.qryData">
DECLARE #xmlOrd_no xml = <cfqueryparam cfsqltype="CF_SQL_varchar" value="#strResult#">
DECLARE #tblOrd_no TABLE (ID varchar(20))
INSERT INTO #tblOrd_no
SELECT tbl.Col.value('.', 'varchar(20)')
FROM #xmlOrd_no.nodes('/ul/li') tbl(Col)
SELECT sub_acct_no, ...
FROM dbo.Closed_ORDER
WHERE ord_no IN (SELECT ID FROM #tblOrd_no)
</cfquery>
You can also do a dump of the XML and it is properly formatted in HTML
<cfoutput>#strResult#</cfoutput>