0

I'm trying to query by a field of a Interleaved table using Spring Data Spanner. The id comparison is automatically done by Spring Data Spanner when it does the ARRAY STRUCT inner join, but I'm not being able to add a WHERE clause to the Interleaved table query.

Considering the example below:

CREATE TABLE Singers (
  Id   INT64 NOT NULL,
  FirstName  STRING(1024),
  LastName   STRING(1024),
  SingerInfo BYTES(MAX),
) PRIMARY KEY (Id);

CREATE TABLE Albums (
  SingerId     INT64 NOT NULL,
  Id           INT64 NOT NULL,
  AlbumTitle   STRING(MAX),
) PRIMARY KEY (SingerId, Id),
  INTERLEAVE IN PARENT Singers ON DELETE CASCADE;

Let's suppose I want to query all Singers where the AlbumTitle is "Fear of the Dark", how can I write a repository method to achieve that using Spring Data Spanner?

Marcelo Wippel
  • 571
  • 4
  • 9

1 Answers1

1

You're example seems to either contain a couple of typos, or it is otherwise not completely correct:

  1. The Singers table has a column Id which is the primary key. That is in itself fine, but when creating a hierarchy of interleaved tables, it is recommended to prefix the primary key column with the table name. So it would be better to name it SingerId.
  2. The Albums table has a SingerId column and an Id column. These two columns form the primary key of the Albums table. This is technically incorrect (and confusing), and also the reason that I think that your example is not completely correct. Because Albums is interleaved in Singers, Albums must contain the same primary key columns as the Singers table, in addition to any additional columns that form the primary key of Albums. In this case Id references the Singers table, and the SingerId is an additional column in the Albums table that has nothing to do with the Singers table. The primary key columns of the parent table must also appear in the same order as in the parent table.

The example data model should therefore be changed to:

CREATE TABLE Singers (
  SingerId   INT64 NOT NULL,
  FirstName  STRING(1024),
  LastName   STRING(1024),
  SingerInfo BYTES(MAX),
) PRIMARY KEY (SingerId);

CREATE TABLE Albums (
  SingerId     INT64 NOT NULL,
  AlbumId      INT64 NOT NULL,
  AlbumTitle   STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId),
  INTERLEAVE IN PARENT Singers ON DELETE CASCADE;

From this point on you can consider the SingerId column in the Albums table as a foreign key relationship to a Singer and treat it as you would in any other database system. Note also that there can be multiple albums for each singer, so a query for ...I want to query all Singers where the AlbumTitle is "Fear of the Dark" is slightly ambiguous. I would rather say:

Give me all singers that have at least one album with the title "Fear of the Dark"

A valid query for that would be:

SELECT *
FROM Singers
WHERE SingerId IN (
  SELECT SingerId
  FROM Albums
  WHERE AlbumTitle='Fear of the Dark'
)
Knut Olav Løite
  • 2,964
  • 7
  • 19
  • I got your point, and you're right. But my problem is executing this query with Spring Data Spanner, because apparently, I can't add a WHERE clause to the Interleaved table query (All repository queries are auto-generated by Spring). – Marcelo Wippel Jul 01 '21 at 15:01
  • I'm not sure exactly what you mean with '__the__ interleaved table query'. To Spring Data Spanner, the relationship between a Singer and an Album should be very much the same as a normal foreign key relationship. Also, you should be able to just use a normal SQL query to achieve what you want. See https://docs.spring.io/spring-cloud-gcp/docs/1.1.0.M1/reference/html/_spring_data_cloud_spanner.html#_sql_query for an example on how to execute a query. If you were to insert the query from my answer into that, it should (in theory) return exactly what you are looking for. – Knut Olav Løite Jul 01 '21 at 17:50