I'm trying to retrieve the value of a SQL Sever temporal table's SYSSTARTTIME field with myBatis and can't figure it out. I had something like this:
<insert id="insertVersionedTableData" parameterType="com.me.dao.vo.DataVO">
<selectKey keyProperty="systemStartTm" resultType="java.util.Date" order="AFTER">
SELECT sysstarttm FROM #MyTableVar;
</selectKey>
DECLARE #MyTableVar TABLE (sysstarttm datetime);
INSERT INTO
dbo.versioned_table (id, first_name, last_name)
OUTPUT inserted.system_start_tm into #MyTableVar
VALUES (#{id}, #{firstName}, #{lastName});
</insert>
When I run this though I can see the insert in the console logging but it then throws an exception saying that #MyTableVar must be declared so it's like the table variable goes out of scope after the insert and the tag runs just like a regular SELECT
I've tried the generated keys functionality too but myBatis expects the key to be the first field in the table which my autogenerated SYSTEMSTARTTIME is not.
Related
I have a postgres database with a single table. The primary key of this table is a generated UUID. I am trying to add a logging table to this database such that whenever a row is added or deleted, the logging table gets an entry. My table has the following structure
CREATE TABLE configuration (
id uuid NOT NULL DEFAULT uuid_generate_v4(),
name text,
data json
);
My logging table has the following structure
CREATE TABLE configuration_log (
configuration_id uuid,
new_configuration_data json,
old_configuration_data json,
"user" text,
time timestamp
);
I have added the following rules:
CREATE OR REPLACE RULE log_configuration_insert AS ON INSERT TO "configuration"
DO INSERT INTO configuration_log VALUES (
NEW.id,
NEW.data,
'{}',
current_user,
current_timestamp
);
CREATE OR REPLACE RULE log_configuration_update AS ON UPDATE TO "configuration"
WHERE NEW.data::json::text != OLD.data::json::text
DO INSERT INTO configuration_log VALUES (
NEW.id,
NEW.data,
OLD.data,
current_user,
current_timestamp
);
Now, if I insert a value in the configuration table, the UUID in the configuration table and the configuration_log table are different. For example, the insert query
INSERT INTO configuration (name, data)
VALUES ('test', '{"property1":"value1"}')
The result is this... the UUID is c2b6ca9b-1771-404d-baae-ae2ec69785ac in the configuration table whereas in the configuration_log table the result is this... the UUID id 16109caa-dddc-4959-8054-0b9df6417406
However, the update rule works as expected. So if I write an update query as
UPDATE "configuration"
SET "data" = '{"property1":"abcd"}'
WHERE "id" = 'c2b6ca9b-1771-404d-baae-ae2ec69785ac';
The configuration_log table gets the correct UUID as seen here i.e. c2b6ca9b-1771-404d-baae-ae2ec69785ac
I am using NEW.id in both the rules so I was expecting the same behavior. Can anyone point out what I might be doing wrong here?
Thanks
This is another good example why rules should be avoided
Quote from the manual:
For any reference to NEW, the target list of the original query is searched for a corresponding entry. If found, that entry's expression replaces the reference.
So NEW.id is replaced with uuid_generate_v4() which explains why you are seeing a different value.
You should rewrite this to a trigger.
Btw: using jsonb is preferred over json, then you can also get rid of the (essentially incorrect) cast of the json column to text to compare the content.
I am working with postgres database and Java. I am using Jooq to query my database.
I need to make an insert in my table and get the primary_key/sequence generated by that insert. I know in simple postgres i can do it like this:
This is what my table looks like:
CREATE TABLE "myTable" (
"id" SERIAL NOT NULL,
"some_text" TEXT NOT NULL,
PRIMARY KEY ("id")
);
This is the insert query:
INSERT INTO public.myTable(some_text)
VALUES ('myValue');
and than to get the latest sequence,
SELECT currval('myTableName_myColumnName_seq')
FROM myTable;
1) How can I use currval in JOOQ?
Right now I am attempting something like this:
config.dsl().insertInto(Tables.myTable)
.set(Tables.myTable.myText, inputText)
.execute();
config.dsl().select.currval('myTableName_myColumnName_seq')
.from myTable;
but off-course the last statement gives error.
The problem with your solution is that while you inserting a record to your table, there might be another process that gets value from a sequence and you'll get wrong value with your second query (SELECT currval).
PostgreSQL allows you to get some data back in INSERT statement with RETURNING clause:
INSERT INTO public.myTable(some_text)
VALUES ('myValue')
RETURNING id;
As jOOQ manual states, you should use returning and fetch in this case. I'm not sure about proper usage (I'm not familiar with jOOQ), something like following:
config.dsl().insertInto(Tables.myTable)
.set(Tables.myTable.myText, inputText)
.returning(Tables.myTable.id)
.fetch();
You can get the current value of a sequence through Sequence.currval(), which returns an expression for that purpose. E.g.
dsl().select(MYTABLENAME_MYCOLUMNNAME_SEQ.currval()).from(...)
But since this sequence is auto-generated from a SERIAL which produces sequence values automatically on your insertions, I completely agree with icuken's answer, you should use INSERT .. RETURNING instead.
I have a simple test table
CREATE TABLE TEST (
KEY INTEGER PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
INTENTS VARCHAR(255),
NO_FOUND SMALLINT );
I am then trying to insert data into this table using the following command from within dashDB's sql dashboard.
Insert into table from (select item1,item2,item3 from TEST2 where some_condition );
However I cannot seem to get the command to not return an error.
Have tried the db2 'DEFAULT', and '0' (default for integer), and even NULL as values for item1.
Have also tried the insert using values, but then the column headings cause the system to report multiple values returned.
Have also tried 'OVERRIDING USER VALUE'
but this then complains about not finding a JOIN element.
Any ideas welcome.
I would try something like this:
Insert into test(intents,no_found)
(select item2,item3 from TEST2 where some_condition );
You specify that only two of the three columns receive values, the KEY column is generated. Hence you only select the two related columns.
We're in process of converting over from SQL Server to Postgres. I have a scenario that I am trying to accommodate. It involves inserting records from one table into another, WITHOUT listing out all of the columns. I realize this is not recommended practice, but let's set that aside for now.
drop table if exists pk_test_table;
create table public.pk_test_table
(
recordid SERIAL PRIMARY KEY NOT NULL,
name text
);
--example 1: works and will insert a record with an id of 1
insert into pk_test_table values(default,'puppies');
--example 2: fails
insert into pk_test_table
select first_name from person_test;
Error I receive in the second example:
column "recordid" is of type integer but expression is of type
character varying Hint: You will need to rewrite or cast the
expression.
The default keyword will tell the database to grab the next value.
Is there any way to utilize this keyword in the second example? Or some way to tell the database to ignore auto-incremented columns and just them be populated like normal?
I would prefer to not use a subquery to grab the next "id".
This functionality works in SQL Server and hence the question.
Thanks in advance for your help!
If you can't list column names, you should instead use the DEFAULT keyword, as you've done in the simple insert example. This won't work with a in insert into ... select ....
For that, you need to invoke nextval. A subquery is not required, just:
insert into pk_test_table
select nextval('pk_test_table_id_seq'), first_name from person_test;
You do need to know the sequence name. You could get that from information_schema based on the table name and inferring its primary key, using a function that takes just the table name as an argument. It'd be ugly, but it'd work. I don't think there's any way around needing to know the table name.
You're inserting value into the first column, but you need to add a value in the second position.
Therefore you can use INSERT INTO table(field) VALUES(value) syntax.
Since you need to fetch values from another table, you have to remove VALUES and put the subquery there.
insert into pk_test_table(name)
select first_name from person_test;
I hope it helps
I do it this way via a separate function- though I think I'm getting around the issue via the table level having the DEFAULT settings on a per field basis.
create table public.pk_test_table
(
recordid integer NOT NULL DEFAULT nextval('pk_test_table_id_seq'),
name text,
field3 integer NOT NULL DEFAULT 64,
null_field_if_not_set integer,
CONSTRAINT pk_test_table_pkey PRIMARY KEY ("recordid")
);
With function:
CREATE OR REPLACE FUNCTION func_pk_test_table() RETURNS void AS
$BODY$
INSERT INTO pk_test_table (name)
SELECT first_name FROM person_test;
$BODY$
LANGUAGE sql VOLATILE;
Then just execute the function via a SELECT FROM func_pk_test_table();
Notice it hasn't had to specify all the fields- as long as constraints allow it.
I'm trying to insert values into a database using prepared statements, but sometimes I need to insert for a certain value the literal 'DEFAULT', how do I do this?
CREATE TABLE test (id int, firstname text default 'john', lastname text default 'doe');
This is what I want to do, but then using a prepared statement:
insert into test (id, firstname, lastname) VALUES ('1', DEFAULT, DEFAULT);
But this is resulting in an error (for obvious reasons):
PREPARE testprep (integer, text, text) AS INSERT INTO test (id, firstname, lastname) VALUES ($1, $2, $3);
EXECUTE testprep('1',DEFAULT,DEFAULT);
The Error:
ERROR: syntax error at or near "DEFAULT"
Both examples I created using SQL-Fiddle:
http://sqlfiddle.com/#!15/243ae/1/0
http://sqlfiddle.com/#!15/243ae/3/0
There is no way to do that with a prepared statement.
The only escape would be a BEFORE INSERT trigger on the table that replaces certain data values (e.g. NULL) with the default value. But this is not a nice solution and will cost performance.
The other escape route is to use several prepared statements, one for each combination of values you want set to default.
You may try omitting the default columns from the insert statement:
PREPARE testprep (integer) AS
INSERT INTO test (id) VALUES ($1);
EXECUTE testprep('1');
Postgres should rely on the default values in the table definition for the firstname and lastname columns. From the Postgres documentation:
When a new row is created and no values are specified for some of the columns, those columns will be filled with their respective default values.