Upsert with "on conflict do update" with partial index in jOOQ - postgresql

I have a partial index on table MY_TABLE that is defined like:
CREATE UNIQUE INDEX my_index
ON MY_TABLE(CUSTOMER_ID, OWNER_ID)
WHERE CLOSED_ON IS NULL;
Then, I'm attempting an upsert using jOOQ
final var insert = using(configuration)
.insertInto(MY_TABLE,
MY_TABLE.CUSTOMER_ID,
MY_TABLE.OWNER_ID,
MY_TABLE.UPDATED_ON);
customers.forEach(custId -> insert.values(custId, reprId, today));
insert.onConflict(MY_TABLE.CUSTOMER_ID, MY_TABLE.OWNER_ID)
.where(MY_TABLE.CLOSED_ON.isNull())
.doUpdate()
.set(MY_TABLE.UPDATED_ON, today)
.execute();
But the above code is throwing this error:
org.jooq.exception.DataAccessException: SQL [...];
ERROR: invalid reference to FROM-clause entry for table "my_table"
Hint: There is an entry for table "my_table", but it cannot be referenced from this part of the query.
Looking at the generated SQL I see jOOQ is adding the schema and table name to the where part of the on conflict, which Postgres doesn't like:
... on conflict ("customer_id", "owner_id") where "my_schema"."my_table"."closed_on" is null do update set ...
Is there a way to tell jOOQ not to add the schema and table name?
This is a workaround I'm using, but I wonder if there is a better way:
.where(condition("closed_on IS NULL"))

We found a bug report in jOOQ's issues page that asks exactly this question:
https://github.com/jOOQ/jOOQ/issues/11732
Which mentions this workaround:
.where(field(COURSE_ENROLL.DELETED_TS.getUnqualifiedName()).isNull())
So I can do that instead of what I did with the literal string in my case.
This is also mentioned to be a bug that was fixed 3 weeks ago :)
Thanks.
EDIT:
There is already a fix for this in jOOQ 3.14.9

Related

DB2 : SQL Error [42997]: Function not supported (Reason code = "21").. SQLCODE=-270, SQLSTATE=42997

I have to write a sql script to modify a lot of types of columns in my db2 database.
Everything goes well excpet for one specific table (script used is the same as others tables) and db2 returns always an error I don't understand.
Here is my script :
ALTER TABLE "TEST"."CLIENT"
ALTER COLUMN C_CODE
SET DATA TYPE CHAR(16 OCTETS);
and the error :
SQL Error [42997]: Function not supported (Reason code = "21")..
SQLCODE=-270, SQLSTATE=42997, DRIVER=4.26.14
I try to modify some others columns on the same table, but I always receive the same error.
Do you, by any chance, have an idea?
Thanks in advance
The error SQL0270N (sqlcode = -270) has many possible causes, and the specific cause is indicated by the "reason code".
In this case the "reason code 21" means:
A column cannot be dropped or have its length, data type, security,
nullability, or hidden attribute altered on a table that is a base
table for a materialized query table.
The documentation for this sqlcode on Db2-LUW is at:
https://www.ibm.com/docs/en/db2/11.5?topic=messages-sql0250-sql0499#sql0270n
Search for SQL0270N on that page, and notice the suggested user response:
To drop or alter a column in a table that is a base table for a materialized query table, perform the following steps:
1. Drop the dependent materialized query table.
2. Drop the column of the base table, or alter the length, data type, nullability, or hidden attribute of this column.
3. Re-create the materialized query table.

Ambiguous column reference "ctid" in SELECT with more than one table

I'm using CRecordset to query one table, but I use a second table to filter data. If in my GetDefaultSQL override method I return a table list with more than one table then I get this ERROR: column reference "ctid" is ambiguous. I know what a "ctid" column is, but I don't use it in my code. It's inserted into the original SQL statement by ODBC driver. How to fix this? How to tell the ODBC driver not to insert the "ctid" column?
I tried to call CRecordset::Open with readOnly parameter, as I assume that ODBC needs ctid to update the row, and I don't need to update them. But the error remains.
Also tried to add a primary key to the second table that was missing it, thinking if a table has a primary key then ODBC can use that instead of 'ctid', but again no luck. Makes sense though, because I don't fetch any column of that second table, and the second table is used just for filtering.
If I make a DB view to work around the issue, I get ERROR: column "ctid" does not exist.
You have to call CRecordset::Open with two parameters changed:
m_pSet->Open(CRecordset::snapshot, NULL, CRecordset::readOnly);
Then you can fetch both the joined tables and the view without errors. No "ctid" then.

How to set Ignore Duplicate Key in Postgresql while table creation itself

I am creating a table in Postgresql 9.5 where id is the primary key. While inserting rows in the table if anyone tries to insert duplicate id, i want it to get ignored instead of raising exception. Is there any way such that i can set this while table creation itself that duplicate entries get ignored.
There are many techniques to resolve duplicate insertion issue while writing insertion query i.e. using ON CONFLICT DO NOTHING, or using WHERE EXISTS clause etc. But i want to handle this at table creation end so that the person writing insertion query doesn't need to bother any.
Creating RULE is one of the possible solution. Are there other possible solutions? Maybe something like this:
`CREATE TABLE dbo.foo (bar int PRIMARY KEY WITH (FILLFACTOR=90, IGNORE_DUP_KEY = ON))`
Although exact this statement doesn't work on Postgresql 9.5 on my machine.
add a trigger before insert or rule on insert do instead - otherwise has to be handled by inserting query. both solutions will require more resources on each insert.
Alternative way to use function with arguments for insert, that will check for duplicates, so end users will use function instead of INSERT statement.
WHERE EXISTS sub-query is not atomic btw - so you can still have exception after check...
9.5 ON CONFLICT DO NOTHING is the best solution still

slick insert query with forceInsertQuery

I need to copy table to another same schema table.
I would like to do something like
insert into table1 select * from table2
In slick, it seems possible to insert with queries.
There is a function with signature .insert(:Query)
In my table I defined a "id" column with auto-increment option.
However slick automatically omit auto-increment column except using forceInsert method.
In this case, column number doesn't match if I print the sql out:
val table = TableQuery[Table_X]
println(TableQuery[Table_Y].insertStatementFor( table.take(1000) ))
insert statement is lack of an "id" column, but table.take(1000) include it.
How can I solve this problem?
I see some functions called forceInsertQuery in the source code of slick on github. I am not sure whether this can help me or not

PostgreSQL syntax error related to INSERT and/or WITH. Occurs in 8.4 but not 9.1. Ideas?

Here is some SQL for PostgreSQL (I know it's a silly query; I've boiled the original query down to the simplest broken code):
CREATE TABLE entity (
id SERIAL PRIMARY KEY
);
WITH new_entity
AS (INSERT INTO entity DEFAULT VALUES
RETURNING id
)
SELECT id FROM new_entity;
Here it is running on PostgreSQL 9.1:
psql:../sandbox/test.sql:3: NOTICE: CREATE TABLE will create implicit sequence "entity_id_seq" for serial column "entity.id"
psql:../sandbox/test.sql:3: NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "entity_pkey" for table "entity"
CREATE TABLE
id
----
1
(1 row)
Here it is not running on PostgreSQL 8.4:
psql:../sandbox/test.sql:3: NOTICE: CREATE TABLE will create implicit sequence "entity_id_seq" for serial column "entity.id"
psql:../sandbox/test.sql:3: NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "entity_pkey" for table "entity"
CREATE TABLE
psql:../sandbox/test.sql:9: ERROR: syntax error at or near "INSERT"
LINE 2: AS (INSERT INTO entity DEFAULT VALUES
Obviously, the table creation goes fine in both cases, but it wipes out on the second query in PostgreSQL 8.4. From this error message I am unable to gather exactly what the problem is. I don't know what it is that 9.1 has and 8.4 doesn't have that could result in this syntax error. It's hilariously hard to google it. I am approaching the level of desperation required to trawl through the pages of PostgreSQL release notes between 8.4 and 9.1 and finding out if anything related to WITH … AS or INSERT … RETURNING was changed or added, but before I go there I am hoping one of you has the experience and/or godly google-fu to help me out here.
Data-modifying statements in WITH were introduced in Postgres 9.1