-
Notifications
You must be signed in to change notification settings - Fork 378
Description
Hi,
Like with #968, I have a case where I want to delegate the SELECT query generation to Spring to leverage Spring's support for different dialects (giving me support for different databases "out of the box"). Unfortunately, I am faced with a non-trivial join where I need to go beyond Spring's current assumptions for how JOIN works.
My two key issues:
- When initiating a join (
selectBuilder.join(...)), the parameter is assumed to be aTable(possible via String which is immediately passed toTable.create). However, SQL supports joining on a "subselect" (LEFT OUTER JOIN (SELECT ... ) AS alias ON alias.X = other_table.Y). This is now tracked in Add support for join with subselect #1003 - The condition part on a join assumes
x.A = y.B [AND z.C = Y.D ...]formatted conditions. However, other formats can be used - such asOR'ing conditions. This is tracked as this issue.
The concrete example
The example I am working on is a bit complex, but I have attempted to reduce it to these model classes:
@Data
public class TransportLocation {
@Id
private UUID id;
}
@Data
public class Transport {
@Id
private UUID id;
private UUID pickupLocationId;
private UUID deliveryLocationId;
private UUID vehicleId;
}
@Data
public class TransportLocationTO extends TransportLocation {
private Vehicle vehicle;
}
@Data
public class Vehicle {
@Id
private UUID id;
}
What I want to do is to generate an SQL query that maps up a TransportLocationTO from a single SELECT statement. The Vehicle entity comes via the Transport entity on either pickupLocationId or deliveryLocationId. Some additional context:
-
The
TransportLocationcan be on "either side" of theTransport. Often it will appear in thepickupLocationIdof one Transport anddeliveryLocationIdof another. This happens if theTransportLocationis a "middle stops" in the route.- The
idof theTransportLocationdepends implicit on theVehicledue to business rules (that are not reflected in this example) - but SQL-wise the link between the two goes viaTransport. This is why it is "fine" in this case for the JOIN to use anOR(with a DISTINCT). But on the flip side, if I only use one of them then the join will fail for either very first or the very lastTransportLocation.
- The
-
The API has
TransportLocationTOhas a "primary entity" - as in "GET /transport-locations" + "GET /transport-locations/{ID}" are defined endpoints and they want to include theVehicleentity. -
I will be passing the generated SQL to Spring R2DBC's
DatabaseClientin case that bit will matter (I do not think it will, but mentioning it for completeness).
Version used
In case it matters, I am currently using:
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
I am not entirely sure which version of spring-data-jdbc + spring-r2dbc that implies.
Solutions / work arounds
As far as I have gathered, the "optimal" solution is to use JOIN + sub-select as this avoids the need for DISTINCT, but this is not possible at all.
An alternative in my case is to use the JOIN ... ON A=B OR A=C + DISTINCT. I will test whether the code accepts the variant of JOIN ... ON (A=B OR A=C) = TRUE, which is at best a rewrite of questionable readability and at worst might neuter some database/query planner optimizations.
Sadly changing the datamodel is not an option for me (political decision that I cannot change).