Panoramica della query del grafico

Questo documento fornisce una panoramica del linguaggio di query dei grafi (GQL) e di come scrivere query sui grafi per BigQuery Graph. Puoi eseguire query grafiche per trovare pattern, attraversare relazioni e ottenere approfondimenti dal grafico della tua proprietà. Gli esempi in questo documento si riferiscono a un grafico chiamato FinGraph, che mostra le relazioni tra persone, account di loro proprietà e trasferimenti tra account. Per informazioni sulla definizione del grafico, vedi l'esempio di FinGraph.

Struttura della query

Una query del grafico è costituita dal nome del grafico, seguito da una o più istruzioni di query lineari. Ogni query lineare contiene una o più istruzioni, che ti consentono di lavorare con i dati del grafico per trovare corrispondenze di pattern, definire variabili, filtrare e trasformare i dati intermedi e restituire i risultati. Esegui una query del grafico nello stesso modo in cui esegui una query SQL in BigQuery.

Esempio di struttura di query del grafico.
Un esempio della struttura di una query del grafico.

Corrispondenza di pattern del grafico

La corrispondenza dei pattern del grafico trova pattern specifici all'interno del grafico. I pattern più semplici sono i pattern degli elementi, come i pattern dei nodi che corrispondono ai nodi e i pattern dei bordi che corrispondono ai bordi.

Pattern dei nodi

Un pattern di nodi corrisponde ai nodi del grafico. Questo pattern contiene parentesi corrispondenti, che possono includere facoltativamente una variabile di pattern del grafico, un'espressione di etichetta e filtri delle proprietà.

Trovare tutti i nodi

La seguente query restituisce tutti i nodi nel grafico. La variabile n, una variabile del pattern del grafico, si associa ai nodi corrispondenti. In questo caso, il pattern del nodo corrisponde a tutti i nodi del grafico.

GRAPH graph_db.FinGraph
MATCH (n)
RETURN LABELS(n) AS label, n.id;

Questa query restituisce label e id:

label id
Account 7
Account 16
Account 20
Person 1
Person 2
Person 3

Trovare tutti i nodi con un'etichetta specifica

La seguente query corrisponde a tutti i nodi del grafico che hanno l'Person etichetta. La query restituisce l'etichetta e alcune proprietà dei nodi corrispondenti.

GRAPH graph_db.FinGraph
MATCH (p:Person)
RETURN LABELS(p) AS label, p.id, p.name;

Questa query restituisce le seguenti proprietà dei nodi corrispondenti:

label id name
Person 1 Alex
Person 2 Dana
Person 3 Lee

Trova tutti i nodi che corrispondono a un'espressione di etichetta

Puoi creare un'espressione di etichetta con uno o più operatori logici. Ad esempio, la seguente query corrisponde a tutti i nodi del grafico che hanno l'etichetta Person o Account. La variabile pattern del grafico n espone tutte le proprietà dei nodi con l'etichetta Person o Account.

GRAPH graph_db.FinGraph
MATCH (n:Person|Account)
RETURN LABELS(n) AS label, n.id, n.birthday, n.create_time;

Nota quanto segue nei risultati di questa query:

  • Tutti i nodi hanno la proprietà id.
  • I nodi corrispondenti all'etichetta Account hanno la proprietà create_time, ma non hanno la proprietà birthday. La proprietà birthday è NULL per questi nodi.
  • I nodi corrispondenti all'etichetta Person hanno la proprietà birthday, ma non hanno la proprietà create_time. La proprietà create_time è NULL per questi nodi.
label id birthday create_time
Account 7 NULL 2020-01-10T14:22:20.222Z
Account 16 NULL 2020-01-28T01:55:09.206Z
Account 20 NULL 2020-02-18T13:44:20.655Z
Person 1 1991-12-21T08:00:00Z NULL
Person 2 1980-10-31T08:00:00Z NULL
Person 3 1986-12-07T08:00:00Z NULL

Trova tutti i nodi corrispondenti all'espressione dell'etichetta e al filtro delle proprietà

La seguente query corrisponde a tutti i nodi del grafico che hanno l'etichetta Person e la proprietà id uguale a 1:

GRAPH graph_db.FinGraph
MATCH (p:Person {id: 1})
RETURN LABELS(p) AS label, p.id, p.name, p.birthday;

Il risultato è simile al seguente:

label id name birthday
Person 1 Alex 1991-12-21T08:00:00Z

Puoi utilizzare la clausola WHERE per formare condizioni di filtro più complesse su etichette e proprietà.

La seguente query utilizza la clausola WHERE per filtrare i nodi per i quali la proprietà birthday è precedente a 1990-01-10:

GRAPH graph_db.FinGraph
MATCH (p:Person WHERE p.birthday < '1990-01-10')
RETURN LABELS(p) AS label, p.name, p.birthday;

Il risultato è simile al seguente:

label name birthday
Person Dana 1980-10-31T08:00:00Z
Person Lee 1986-12-07T08:00:00Z

Pattern perimetrali

Un pattern di archi corrisponde agli archi o alle relazioni tra i nodi. I pattern di bordo sono racchiusi tra parentesi quadre ([]) e includono simboli come -, -> o <- per indicare le direzioni. Un pattern di archi può includere facoltativamente una variabile di pattern del grafico a cui eseguire il binding degli archi corrispondenti.

Trova tutti gli archi con etichette corrispondenti

Questa query restituisce tutti gli archi nel grafico con l'etichetta Transfers. La query associa la variabile del pattern del grafico e agli archi corrispondenti.

GRAPH graph_db.FinGraph
MATCH -[e:Transfers]->
RETURN e.Id as src_account, e.order_number;

Il risultato è simile al seguente:

src_account order_number
7 304330008004315
7 304120005529714
16 103650009791820
20 304120005529714
20 302290001255747

Trova tutti gli archi corrispondenti all'espressione dell'etichetta e al filtro delle proprietà

Il pattern edge nella query seguente utilizza un'espressione di etichetta e un filtro delle proprietà per trovare tutti gli archi etichettati Transfers che corrispondono a un numero d'ordine specificato:

GRAPH graph_db.FinGraph
MATCH -[e:Transfers {order_number: "304120005529714"}]->
RETURN e.Id AS src_account, e.order_number;

Il risultato è simile al seguente:

src_account order_number
7 304120005529714
20 304120005529714

Trova tutti i bordi utilizzando qualsiasi pattern di bordi

Puoi utilizzare il pattern di arco any direction (-[]-) in una query per trovare gli archi in entrambe le direzioni. La seguente query trova tutti i trasferimenti con un account bloccato:

GRAPH graph_db.FinGraph
MATCH (account:Account)-[transfer:Transfers]-(:Account {is_blocked:true})
RETURN transfer.order_number, transfer.amount;

Il risultato è simile al seguente:

order_number amount
304330008004315 300
304120005529714 100
103650009791820 300
302290001255747 200

Pattern del percorso

Un pattern di percorso è costituito da pattern di nodi e archi alternati.

Trovare tutti i percorsi da un nodo specifico utilizzando un pattern di percorso

La seguente query trova tutti i trasferimenti a un account avviati da un account di proprietà di Person con id uguale a 2.

Ogni risultato corrispondente rappresenta un percorso da un nodo Person quando id è uguale a 2 a un nodo Account connesso utilizzando un arco Owns, a un altro nodo Account utilizzando un arco Transfers.

GRAPH graph_db.FinGraph
MATCH
  (p:Person {id: 2})-[:Owns]->(account:Account)-[t:Transfers]->
  (to_account:Account)
RETURN
  p.id AS sender_id, account.id AS from_id, to_account.id AS to_id;

Il risultato è simile al seguente:

sender_id from_id to_id
2 20 7
2 20 16

Pattern del percorso quantificati

Un pattern quantificato ripete un pattern all'interno di un intervallo specificato.

Trovare un pattern di bordo quantificato

Per trovare percorsi di lunghezza variabile, puoi applicare un quantificatore a un pattern di arco. La seguente query lo dimostra trovando gli account di destinazione che si trovano a una distanza di 1-3 trasferimenti da un'origine Account con un valore id di 7.

La query applica il quantificatore {1, 3} al pattern del bordo -[e:Transfers]->. Questa istruzione indica alla query di trovare corrispondenze con i percorsi che ripetono il pattern di arco Transfers una, due o tre volte. La clausola WHERE viene utilizzata per escludere l'account di origine dai risultati. La funzione ARRAY_LENGTH viene utilizzata per accedere a group variable e.

GRAPH graph_db.FinGraph
MATCH (src:Account {id: 7})-[e:Transfers]->{1, 3}(dst:Account)
WHERE src != dst
RETURN src.id AS src_account_id, ARRAY_LENGTH(e) AS path_length, dst.id AS dst_account_id;

Il risultato è simile al seguente:

src_account_id path_length dst_account_id
7 1 16
7 1 16
7 3 16
7 3 16
7 2 20
7 2 20

Alcune righe nei risultati sono ripetute. Questo perché possono esistere più percorsi che corrispondono al pattern tra gli stessi nodi di origine e destinazione e la query li restituisce tutti.

Trovare un pattern di percorso quantificato

La seguente query trova i percorsi tra i nodi Account con uno o due Transfers archi tramite account intermedi bloccati.

Il pattern di percorso tra parentesi è quantificato e la relativa clausola WHERE specifica le condizioni per il pattern ripetuto.

GRAPH graph_db.FinGraph
MATCH
  (src:Account)
  ((a:Account)-[:Transfers]->(b:Account {is_blocked:true}) WHERE a != b){1,2}
    -[:Transfers]->(dst:Account)
RETURN src.id AS src_account_id, dst.id AS dst_account_id;

Il risultato è simile al seguente:

src_account_id dst_account_id
7 20
7 20
20 20

Variabili di gruppo

Una variabile di pattern del grafico dichiarata in un pattern quantificato diventa una variabile di gruppo quando viene accessibile al di fuori di questo pattern. Si lega quindi a un array di elementi del grafico corrispondenti.

Puoi accedere a una variabile di gruppo come array. Gli elementi del grafico vengono conservati nell'ordine in cui compaiono lungo i percorsi corrispondenti. Puoi aggregare una variabile di gruppo utilizzando l'aggregazione orizzontale.

Variabile del gruppo di accesso

Nell'esempio seguente, si accede alla variabile e nel seguente modo:

  • Come variabile di pattern del grafico associata a un singolo arco nella clausola WHERE e.amount > 100 quando si trova all'interno del pattern quantificato.
  • Come variabile di gruppo associata a un array di elementi perimetrali in ARRAY_LENGTH(e) nell'istruzione RETURN quando si trova al di fuori del pattern quantificato.
  • Come variabile di gruppo associata a un array di elementi perimetrali, aggregata da SUM(e.amount) al di fuori del pattern quantificato. Questo è un esempio di aggregazione orizzontale.
GRAPH graph_db.FinGraph
MATCH
  (src:Account {id: 7})-[e:Transfers WHERE e.amount > 100]->{0,2}
  (dst:Account)
WHERE src.id != dst.id
LET total_amount = SUM(e.amount)
RETURN
  src.id AS src_account_id, ARRAY_LENGTH(e) AS path_length,
  total_amount, dst.id AS dst_account_id;

Il risultato è simile al seguente:

src_account_id path_length total_amount dst_account_id
7 1 300 16
7 2 600 20

Prefissi di ricerca del percorso

Per limitare i percorsi corrispondenti all'interno di gruppi che condividono nodi di origine e destinazione, puoi utilizzare il prefisso di ricerca per i percorsi ANY, ANY SHORTEST o ANY CHEAPEST. Puoi applicare questi prefissi solo prima di un intero pattern di percorso e non puoi applicarli all'interno delle parentesi.

Corrispondenza tramite ANY

La seguente query trova tutti gli account unici raggiungibili che si trovano a uno o due Transfers di distanza da un determinato nodo Account.

Il prefisso di ricerca del percorso ANY garantisce che la query restituisca un solo percorso tra una coppia unica di nodi src e dst Account. Nell'esempio seguente, anche se puoi raggiungere il nodo Account con {id: 16} in due percorsi diversi dal nodo di origine Account, la query restituisce un solo percorso.

GRAPH graph_db.FinGraph
MATCH ANY (src:Account {id: 7})-[e:Transfers]->{1,2}(dst:Account)
LET ids_in_path = ARRAY_CONCAT(ARRAY_AGG(e.Id), [dst.Id])
RETURN src.id AS src_account_id, dst.id AS dst_account_id, ids_in_path;

Il risultato è simile al seguente:

src_account_id dst_account_id ids_in_path
7 16 7,16
7 20 7,16,20

Corrispondenza tramite ANY SHORTEST

Il prefisso di ricerca del percorso ANY SHORTEST restituisce un singolo percorso per ogni coppia di nodi di origine e destinazione, selezionati tra quelli con il numero minimo di archi.

Ad esempio, la seguente query trova uno dei percorsi più brevi tra un nodo Account con valore id pari a 7 e un nodo Account con valore id pari a 20. La query considera i percorsi con bordi Transfers da 1 a 3.

GRAPH graph_db.FinGraph
MATCH ANY SHORTEST (src:Account {id: 7})-[e:Transfers]->{1, 3}(dst:Account {id: 20})
RETURN src.id AS src_account_id, dst.id AS dst_account_id, ARRAY_LENGTH(e) AS path_length;

Il risultato è simile al seguente:

src_account_id dst_account_id path_length
7 20 2

Corrispondenza tramite ANY CHEAPEST

Il prefisso di ricerca del percorso ANY CHEAPEST garantisce che per ogni coppia di account di origine e di destinazione, la query restituisca un solo percorso con il costo di calcolo totale minimo.

La seguente query trova un percorso con il costo di calcolo totale minimo tra i nodi Account. Questo costo si basa sulla somma della proprietà amount dei bordi Transfers. La ricerca prende in considerazione i percorsi con uno o tre lati Transfers.

GRAPH graph_db.FinGraph
MATCH ANY CHEAPEST (src:Account)-[e:Transfers COST e.amount]->{1,3}(dst:Account)
LET total_cost = sum(e.amount)
RETURN src.id AS src_account_id, dst.id AS dst_account_id, total_cost;

Il risultato è simile al seguente:

src_account_id dst_account_id total_cost
7 7 900
7 16 100
7 20 400
16 7 800
16 16 500
16 20 300
20 7 500
20 16 200
20 20 500

Pattern del grafico

Un pattern del grafico è costituito da uno o più pattern di percorso, separati da una virgola (,). I pattern del grafico possono contenere una clausola WHERE, che consente di accedere a tutte le variabili del pattern del grafico nei pattern di percorso per formare condizioni di filtro. Ogni pattern di percorso produce una raccolta di percorsi.

Corrispondenza utilizzando un pattern del grafico

La seguente query identifica gli account intermediari e i relativi proprietari coinvolti in transazioni di importo superiore a 200, tramite le quali i fondi vengono trasferiti da un account di origine a un account bloccato.

I seguenti pattern del percorso formano il pattern del grafico:

  • Il primo pattern trova i percorsi in cui il trasferimento avviene da un account a un account bloccato utilizzando un account intermedio.
  • Il secondo pattern trova i percorsi da un account al suo proprietario.

La variabile interm funge da collegamento comune tra i due pattern di percorso, il che richiede che interm faccia riferimento allo stesso nodo dell'elemento in entrambi i pattern di percorso. In questo modo viene creata un'operazione di equi-join basata sulla variabile interm.

GRAPH graph_db.FinGraph
MATCH
  (src:Account)-[t1:Transfers]->(interm:Account)-[t2:Transfers]->(dst:Account),
  (interm)<-[:Owns]-(p:Person)
WHERE dst.is_blocked = TRUE AND t1.amount > 200 AND t2.amount > 200
RETURN
  src.id AS src_account_id, dst.id AS dst_account_id,
  interm.id AS interm_account_id, p.id AS owner_id;

Il risultato è simile al seguente:

src_account_id dst_account_id interm_account_id owner_id
20 16 7 1

Istruzioni di query lineari

Puoi concatenare più istruzioni del grafico per formare un'istruzione di query lineare. Le istruzioni vengono eseguite nello stesso ordine in cui appaiono nella query.

  • Ogni istruzione prende come input l'output dell'istruzione precedente. L'input è vuoto per la prima istruzione.

  • L'output dell'ultima istruzione è il risultato finale.

Ad esempio, puoi utilizzare istruzioni di query lineari per trovare il trasferimento massimo a un account bloccato. La seguente query trova l'account e il relativo proprietario con il trasferimento in uscita più grande a un account bloccato.

GRAPH graph_db.FinGraph
MATCH (src_account:Account)-[transfer:Transfers]->(dst_account:Account {is_blocked:true})
ORDER BY transfer.amount DESC
LIMIT 1
MATCH (src_account:Account)<-[owns:Owns]-(owner:Person)
RETURN src_account.id AS account_id, owner.name AS owner_name;

La tabella seguente illustra questo processo mostrando i risultati intermedi passati tra ogni istruzione. Per brevità, vengono mostrate solo alcune proprietà.

Affermazione Risultato intermedio (abbreviato)
MATCH
  (src_account:Account)
    -[transfer:Transfers]->
  (dst_account:Account {is_blocked:true})
src_account transfer dst_account
{id: 7} {amount: 300.0} {id: 16, is_blocked: true}
{id: 7} {amount: 100.0} {id: 16, is_blocked: true}
{id: 20} {amount: 200.0} {id: 16, is_blocked: true}

ORDER BY transfer.amount DESC
src_account transfer dst_account
{id: 7} {amount: 300.0} {id: 16, is_blocked: true}
{id: 20} {amount: 200.0} {id: 16, is_blocked: true}
{id: 7} {amount: 100.0} {id: 16, is_blocked: true}

LIMIT 1
src_account transfer dst_account
{id: 7} {amount: 300.0} {id: 16, is_blocked: true}

MATCH
  (src_account:Account)
    <-[owns:Owns]-
  (owner:Person)
src_account transfer dst_account è proprietario di proprietario
{id: 7} {amount: 300.0} {id: 16, is_blocked: true} {person_id: 1, account_id: 7} {id: 1, name: Alex}
RETURN
  src_account.id AS account_id,
  owner.name AS owner_name
        
account_id owner_name
7 Alex

Il risultato è simile al seguente:

account_id owner_name
7 Alex

Dichiarazione return

L'istruzione RETURN specifica cosa restituire dai pattern corrispondenti. Può accedere alle variabili del pattern del grafico e includere espressioni e altre clausole, come ORDER BY e GROUP BY.

BigQuery Graph non supporta la restituzione di elementi del grafico come risultati della query. Per restituire l'intero elemento del grafico, utilizza la funzione TO_JSON.

Restituisci gli elementi del grafico come JSON

GRAPH graph_db.FinGraph
MATCH (n:Account {id: 7})
-- Returning a graph element in the final results is NOT allowed. Instead, use
-- the TO_JSON function or explicitly return the graph element's properties.
RETURN TO_JSON(n) AS n;

Il risultato è simile al seguente:

n
{"identifier":"mUZpbkdyYXBoLkFjY291bnQAeJEO","kind":"node","labels":["Account"],"properties":{"create_time":"2020-01-10T14:22:20.222Z","id":7,"is_blocked":false,"nick_name":"Vacation Fund"}}

Comporre query più grandi con la parola chiave NEXT

Puoi concatenare più istruzioni di query lineari del grafico utilizzando la parola chiave NEXT. La prima istruzione riceve un input vuoto e l'output di ogni istruzione successiva diventa l'input per la successiva.

L'esempio seguente trova il proprietario dell'account con il maggior numero di trasferimenti in entrata concatenando più istruzioni lineari del grafico. Puoi utilizzare la stessa variabile, ad esempio account, per fare riferimento allo stesso elemento del grafico in più istruzioni lineari.

GRAPH graph_db.FinGraph
MATCH (:Account)-[:Transfers]->(account:Account)
RETURN account, COUNT(*) AS num_incoming_transfers
GROUP BY account
ORDER BY num_incoming_transfers DESC
LIMIT 1

NEXT

MATCH (account:Account)<-[:Owns]-(owner:Person)
RETURN account.id AS account_id, owner.name AS owner_name, num_incoming_transfers;

Il risultato è simile al seguente:

account_id owner_name num_incoming_transfers
16 Lee 3

Puoi anche combinare le istruzioni di query lineari con gli operatori di insieme.

Funzioni ed espressioni

Puoi utilizzare tutte le funzioni (aggregate e scalari), gli operatori e le espressioni condizionali di GoogleSQL nelle query sui grafi. BigQuery Graph supporta anche funzioni GQL e operatori GQL che possono essere utilizzati solo nelle query grafiche.

La seguente query include un mix di funzioni e operatori GQL e SQL all'interno di una query del grafico:

GRAPH graph_db.FinGraph
MATCH (person:Person)-[o:Owns]->(account:Account)
WHERE person IS SOURCE OF o
RETURN person, ARRAY_AGG(account.nick_name) AS accounts
GROUP BY person

NEXT

RETURN
  LABELS(person) AS labels,
  accounts,
  CONCAT(person.city, ", ", person.country) AS location,
  TO_JSON(person) AS person
LIMIT 1;

Il risultato è simile al seguente:

etichette account località persona
Person ["Vacation Fund"] Adelaide, Australia {"identifier":"mUZpbkdyYXBoLlBlcnNvbgB4kQI=","kind":"node","labels":["Person"],"properties":{"birthday":"1991-12-21T08:00:00Z","city":"Adelaide","country":"Australia","id":1,"name":"Alex"}}

Sottoquery

Una subquery è una query nidificata in un'altra query. Alle sottoquery all'interno delle query del grafico si applicano le seguenti regole:

  • Una sottoquery è racchiusa tra una coppia di parentesi graffe {}.
  • Una sottoquery inizia con una clausola GRAPH per specificare il grafico nell'ambito. Il grafico specificato non deve essere lo stesso utilizzato nella query esterna.
  • Una variabile di pattern del grafico dichiarata al di fuori dell'ambito della sottoquery non può essere dichiarata di nuovo all'interno della sottoquery, ma può essere indicata in espressioni o funzioni all'interno della sottoquery.

Utilizza una sottoquery per trovare il numero totale di trasferimenti da ogni account

La seguente query illustra l'utilizzo della sottoquery VALUE. La sottoquery è racchiusa tra parentesi graffe {} con il prefisso della parola chiave VALUE. La query restituisce il numero totale di trasferimenti avviati da un account.

GRAPH graph_db.FinGraph
MATCH (p:Person)-[:Owns]->(account:Account)
RETURN p.name, account.id AS account_id, VALUE {
  GRAPH graph_db.FinGraph
  MATCH (a:Account)-[transfer:Transfers]->(:Account)
  WHERE a = account
  RETURN COUNT(transfer) AS num_transfers
} AS num_transfers;

Il risultato è simile al seguente:

nome account_id num_transfers
Alex 7 2
Dana 20 2
Lee 16 1

Per un elenco delle espressioni di sottoquery supportate, vedi Sottoquery BigQuery Graph.

Parametri di query

Puoi eseguire query su BigQuery Graph con i parametri. Per saperne di più, consulta la sintassi e scopri come eseguire query con parametri.

La seguente query corrisponde ai nodi Person che hanno un valore id corrispondente a un parametro di query:

GRAPH graph_db.FinGraph
MATCH (person:Person {id: @id})
RETURN person.name;

Eseguire query su grafici e tabelle insieme

Puoi combinare query sui grafi e query SQL utilizzando l'operatore GRAPH_TABLE.

L'operatore GRAPH_TABLE accetta una query del grafico lineare e restituisce il risultato in un formato tabellare che può essere integrato in una query SQL. Questa interoperabilità consente di arricchire i risultati delle query del grafico con contenuti non grafici e viceversa.

Ad esempio, puoi creare una tabella CreditReports e inserire alcuni report creditizi, come mostrato nell'esempio seguente:

CREATE TABLE graph_db.CreditReports (
  person_id     INT64 NOT NULL,
  create_time   TIMESTAMP NOT NULL,
  score         INT64 NOT NULL,
  PRIMARY KEY (person_id, create_time) NOT ENFORCED
);
INSERT INTO graph_db.CreditReports (person_id, create_time, score)
VALUES
  (1,"2020-01-10 06:22:20.222", 700),
  (2,"2020-02-10 06:22:20.222", 800),
  (3,"2020-03-10 06:22:20.222", 750);

Successivamente, puoi identificare persone specifiche tramite la corrispondenza dei pattern del grafico in GRAPH_TABLE e unire i risultati della query del grafico alla tabella CreditReports per recuperare i punteggi di credito.

SELECT
  gt.person.id,
  credit.score AS latest_credit_score
FROM GRAPH_TABLE(
  graph_db.FinGraph
  MATCH (person:Person)-[:Owns]->(:Account)-[:Transfers]->(account:Account {is_blocked:true})
  RETURN DISTINCT person
) AS gt
JOIN graph_db.CreditReports AS credit
  ON gt.person.id = credit.person_id
ORDER BY credit.create_time;

Il risultato è simile al seguente:

person_id latest_credit_score
1 700
2 800

Passaggi successivi