PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

In psql come eseguire un ciclo per una query Select con CTE e ottenere l'output mostrato se lo eseguo in un db di sola lettura?

Se decifralo bene, in pratica vuoi selezionare tutte le persone in cui il numero di riga in base all'ID discendente appare nell'indirizzo. Il risultato finale dovrebbe quindi essere limitato ad alcuni di questi numeri di riga.

Quindi non è necessario utilizzare quell'ingombrante LIMIT /OFFSET costruire affatto. Puoi semplicemente usare il row_number() funzione finestra.

Per filtrare i numeri di riga puoi semplicemente usare IN . A seconda di cosa vuoi qui puoi usare un elenco di letterali, specialmente se i numeri non sono consecutivi. Oppure puoi usare generate_series() per generare un elenco di numeri consecutivi. Ovviamente puoi anche usare una sottoquery, quando i numeri sono memorizzati in un'altra tabella.

Con un elenco di letterali che assomiglierebbero a questo:

SELECT pn.personid,
       pn.lastname,
       pn.firstname,
       pn.address,
       pn.city
       FROM (SELECT p.personid,
                    p.lastname,
                    p.firstname,
                    p.address,
                    p.city,
                    row_number() OVER (ORDER BY p.personid DESC) n
                    FROM persons p) pn
       WHERE pn.address LIKE concat('%', pn.n, '%')
             AND pn.n IN (1, 2, 4);

Se vuoi usare generate_series() un esempio potrebbe essere:

SELECT pn.personid,
       pn.lastname,
       pn.firstname,
       pn.address,
       pn.city
       FROM (SELECT p.personid,
                    p.lastname,
                    p.firstname,
                    p.address,
                    p.city,
                    row_number() OVER (ORDER BY p.personid DESC) n
                    FROM persons p) pn
       WHERE pn.address LIKE concat('%', pn.n, '%')
             AND pn.n IN (SELECT s.n
                                 FROM generate_series(1, 3) s (n));
                             

E una sottoquery di un'altra tabella potrebbe essere utilizzata in questo modo:

SELECT pn.personid,
       pn.lastname,
       pn.firstname,
       pn.address,
       pn.city
       FROM (SELECT p.personid,
                    p.lastname,
                    p.firstname,
                    p.address,
                    p.city,
                    row_number() OVER (ORDER BY p.personid DESC) n
                    FROM persons p) pn
       WHERE pn.address LIKE concat('%', pn.n, '%')
             AND pn.n IN (SELECT t.nmuloc
                                 FROM elbat t);

Per insiemi di numeri più grandi puoi anche considerare di utilizzare un INNER JOIN sui numeri invece di IN .

Usando generate_series() :

SELECT pn.personid,
       pn.lastname,
       pn.firstname,
       pn.address,
       pn.city
       FROM (SELECT p.personid,
                    p.lastname,
                    p.firstname,
                    p.address,
                    p.city,
                    row_number() OVER (ORDER BY p.personid DESC) n
                    FROM persons p) pn
            INNER JOIN generate_series(1, 1000000) s (n)
                       ON s.n = pn.n
       WHERE pn.address LIKE concat('%', pn.n, '%');

O quando i numeri sono in un'altra tabella:

SELECT pn.personid,
       pn.lastname,
       pn.firstname,
       pn.address,
       pn.city
       FROM (SELECT p.personid,
                    p.lastname,
                    p.firstname,
                    p.address,
                    p.city,
                    row_number() OVER (ORDER BY p.personid DESC) n
                    FROM persons p) pn
            INNER JOIN elbat t
                       ON t.nmuloc = pn.n
       WHERE pn.address LIKE concat('%', pn.n, '%');

Nota che ho anche cambiato la corrispondenza del modello di espressione regolare in un semplice LIKE . Ciò renderebbe le query un po' più portatili. Ma puoi ovviamente sostituirlo con qualsiasi espressione di cui hai veramente bisogno.

db<>violino (con alcune varianti)