Conditional onDuplicateKeyUpdate in Jooq - postgresql

I tried to use the jooq dsl for an insert/update query.
We have a unique (MemberId, GroupId) combination in our table, and a group membership Enum.
On sending a subscription request with (MemberId, GroupId, RoleEnum)
The query should insert a new entry to the db, but if the MemberId, GroupId combination already exists - then only update the entry if the new RoleEnum is larger than the existing one.
I failed to do this using one query with the jooq Dsl, so instead I had to use two queries (get, then insert or update accordingly) but then I lose the atomicity of the operation...
Is there a way to do this with one query with the jooqDsl?

jOOQ emulates PostgreSQL 9.5's support for the ON CONFLICT clause via:
insertInto(...).values(...).onDuplicateKeyUpdate()... of the MySQL syntax. This is possible only if your table is generated with explicit primary key information on it. (https://github.com/jOOQ/jOOQ/issues/5093, since jOOQ 3.8)
mergeInto(...).key(...).values(...) of the H2 syntax. With this syntax, you can providean explicit key column list specification, so the code generator is not needed to provide constraint meta information. (https://github.com/jOOQ/jOOQ/issues/4464, since jOOQ 3.7).
Unfortunately, there is not yet any native ON CONFLICT support in jOOQ.

Related

InsertOrUpdate in Slick - when not using primary key

We are using Slick in a Scala Project. There's a module where we need to do Upsert operation ( Insert/Update) . One of the ways we know is to simply use SQL statements and do it, but for now we would like to stick to using Slick to do it instead.
Since Slick's version we use supports InsertOrUpdate() operation, we want to use that. Now here's an issue : -
Our table has one primary key, and that is the index which is set to auto-increment. And the upsert operation which we want to do is on a transaction id which though is expected to be unique but is not marked unique or primary key in the database.
How to handle this situation? I tried manually implementing Upsert by first checking the table, and then insert/update but that is failing in production environment when many requests are coming in every second and we are having 2 inserts for about 1% of the results.

Aggregation function is different in version 8.4 and 9.5?

I have a query like this.
SELECT companies.id, companies.code, MAX(disclosures.filed_at) disclosure_filed_at
FROM \"companies\" INNER JOIN \"disclosures\" ON \"disclosures\".\"company_id\" = \"companies\".\"id\"
GROUP BY companies.id
This query works in Postgresql 9.5.2, but it failed in version 8.4.20 with an error.
PG::GroupingError: ERROR: column "companies.code" must appear in the GROUP BY clause or be used in an aggregate function
If I add companies.code to GROUP BY clause, then it works. But when I select by companies.*, I can't group by companies.*.
Should I write all columns in version 8.4 to use *?
The Postgres behavior is supported by the ANSI standard. The reason is that the id not only defines each row in companies, but it is defined to do so (using a unique or primary key constraint, although I'm not sure if this works in Postgres for a unique constraint).
Hence, the database knows that it can safely refer to any other column from the same row. This is called "functional dependency".
This feature has also now been added to MySQL (documented here). You might find that documentation easier to follow than the Postgres description:
When GROUP BY is present, or any aggregate functions are present, it
is not valid for the SELECT list expressions to refer to ungrouped
columns except within aggregate functions or when the ungrouped column
is functionally dependent on the grouped columns, since there would
otherwise be more than one possible value to return for an ungrouped
column. A functional dependency exists if the grouped columns (or a
subset thereof) are the primary key of the table containing the
ungrouped column.

Crate DB exception, no viable alternative at input 'VARCHAR'

I'm using Elastic search to store large amount of data to make it searchable, but for configuration items I'm still using HSQL DB.
Is it possible to eliminate HSQL DB completely and use my existing Elastic search in combination with Crate DB?
Things I have tried:
tried connecting to my existing Elastic search using Crate driver and Crate client but I got an exception No handler found for action "crate_sql". Does that mean I cannot use my existing ES and have to use inbuilt ES in crateDB??
After connecting to crateDB elastic search (and not my existing ES). I was able to get connection using CrateDriver and run SQL queries. But in one of module I'm creating table using below command:
create table some_table_name
(
id VARCHAR(256),
userName VARCHAR(256),
fieldName VARCHAR(256),
primary key (id),
unique (userName, fieldName)
);
...but then I got an exception:
io.crate.action.sql.SQLActionException: line 1:28: no viable alternative at input 'VARCHAR'
Does that mean I cannot write create table query using SQL syntax and SQL data types?
I know it will work if I use string data type instead of varchar, but I don't want to change all those queries now.
1)
No you cannot use existing ES nodes together with Crate. The whole SQL analyzer/planner/execution layer is done server side, not client side. In fact the crate clients are rather dumb.
2)
You'll have to change the types and also remove / change anything that isn't supported by crate. For example defaults or unique constraints aren't supported (up to 0.39 - in the future support might be added)
In your case the varchar type isn't valid in Crate, instead you'll have to use "string".
See Data Types Documentation for a list of supported data types.

How to annotate unique constraint with WHERE clause in JPA

I need to use these unique constraints in PostgreSQL
CREATE UNIQUE INDEX favorites_3col_uni_idx
ON favorites (user_id, menu_id, recipe_id)
WHERE menu_id IS NOT NULL;
CREATE UNIQUE INDEX favorites_2col_uni_idx
ON favorites (user_id, recipe_id)
WHERE menu_id IS NULL;
The first one I annotate in JPA:
#Table(uniqueConstraints= {
#UniqueConstraint(name="favorites_3col_uni_idx", columnNames = {"user_id", "menu_id", "recipe_id"})
})
But, ¿it is possible to annotate in JPA the second unique index?
Thx.
You appear to want to create partial indexes (CREATE INDEX ... ON ... WHERE) using JPA constraint definitions.
These are fairly PostgreSQL specific, and aren't specified by JPA. You will need to use native syntax to create them. I don't believe JPA offers any features for index definition.
You cannot use a unique constraint for this purpose because unique partial indexes are not unique constraints. Partial unique indexes cannot be created with CONSTRAINT constraint_name UNIQUE(columns) in PostgreSQL. It's only an implementation detail that PostgreSQL creates a unique index for a unique constraint at all.
See:
Specifying an Index (Non-Unique Key) Using JPA
JPA: defining an index column
Some JPA providers offer extension annotations specific to that JPA provider that add features for running native DDL scripts, defining indexes with annoations, etc. Since you haven't mentioned which JPA provider you are using I can't tell you more. Here's the documentation for EclipseLink index DDL; this will not work if you are using Hibernate, OpenJPA, or something other than EclipseLink.
A JPA standard workaround is to check for the presence of those indexes during startup by querying pg_catalog.pg_index. If you don't find them, use an EntityManager native query to send the appropriate native SQL CREATE UNIQUE INDEX commands. A #Startup #Singleton bean is useful for this sort of task if you're using EJB3.1. See the PostgreSQL documentation for the structure of pg_catalog.pg_index. To just check if an index of a given name exists, run:
SELECT EXISTS(
SELECT 1
FROM pg_index
WHERE indexrelid = 'public.indexname'::regclass
);
Note that the above query does nothing to verify it's the index you expect, but you can do that with some additional checks. Just examine the contents of pg_index after creating the index so you know what to test for. I don't recommend trying to check for any particular value of indpred; just make sure it isn't null.

toplink prefixes table with TL_ while update operation

I have very simple named query on JPA (toplink ):
UPDATE Server s SET s.isECM = 0
I don't carry about cache or validity of already preloaded entities. But database connection is performed from restricted account (only INSERT/UPDATE/DELETE). It is appeared that toplink on this query executes (and failed since TL_Server is not exists) very strange SQL:
INSERT INTO TL_Server (elementId, IsECM)
SELECT t0.ElementId, ?
FROM Element t0, Server t1
WHERE ((t1.elementId = t0.ElementId) AND (t0.elementType = ?))
bind => [0, Server]
What is this? How the simple UPDATE appears an INSERT? Why toplink queries TL_?
The TL_Server is a temp table. Because the UpdateAll query is determined to be complex the temp table must be used. I assume it is determined to be complex because the class has multiple tables, so they must be joined, which cannot be done on a simple update.
If you class just had a single table, then just a simple update would be done.
If this is failing, then it is an issue with your database platform's temp table support. Ensure you are setting you "toplink.target-database" correctly. What database are you using?
You seem to be using a very old version of TopLink Essentials? The UpdateAll support has considerably improved in the latest EclipseLink versions, you may consider upgrading.
If you cannot get it to work using TopLink Essentials, you could always just use a native SQL query instead of JPQL.