Domanda

Ho una tabella che mi piacerebbe essere in grado di presentare "classificata di X da Y" i dati per.In particolare, mi piacerebbe essere in grado di presentare i dati per una singola riga in maniera relativamente efficiente (cioèsenza la selezione di ogni riga della tabella).La classifica in sé è abbastanza semplice, è un dritto ORDINE su una singola colonna della tabella.

Postgres sembra presentare alcune sfide uniche in questo senso;AFAICT non ha un RANK o ROW_NUMBER o funzione equivalente (almeno in 8.3, che mi sono bloccato per il momento).La risposta canonica negli archivi della mailing list sembra essere quello di creare una sequenza temporanea e selezionare da è:

test=> create temporary sequence tmp_seq;
CREATE SEQUENCE
test=*> select nextval('tmp_seq') as row_number, col1, col2 from foo;

Sembra che questa soluzione non può ancora aiutare quando voglio selezionare solo una singola riga della tabella (e voglio selezionare da PK, non da classifica).

Potrei utilizzo della denormalizzazione e memorizzare il valore in una colonna separata, il che rende la presentazione dei dati banale, ma appena si trasferisce il mio problema.AGGIORNAMENTO non supporta l'ORDINE, quindi non sono sicuro di come mi piacerebbe costruire una query di AGGIORNAMENTO per impostare la truppa (breve di selezionare ogni riga e l'esecuzione di un AGGIORNAMENTO separato per ogni riga, che sembra un po ' troppo DB attività per attivare ogni volta la truppa bisogno di un aggiornamento).

Mi manca qualcosa di ovvio?Qual è il Giusto Modo per fare questo?

MODIFICA:A quanto pare non ero abbastanza chiaro.Io sono consapevole di OFFSET/LIMITE, ma non vedo come si aiuta a risolvere questo problema.Non sto cercando di selezionare X-classifica voce, sto cercando di selezionare un arbitrario elemento (dalla sua PK, ad esempio), e quindi essere in grado di visualizzare all'utente qualcosa di simile a "classificato 43rd di 312."

È stato utile?

Soluzione

Se si desidera che il rango, fare qualcosa di simile

SELECT id,num,rank FROM (
  SELECT id,num,rank() OVER (ORDER BY num) FROM foo
) AS bar WHERE id=4

Se si vuole realmente il numero di riga, utilizzare

SELECT id,num,row_number FROM (
  SELECT id,num,row_number() OVER (ORDER BY num) FROM foo
) AS bar WHERE id=4

Ti differire quando si dispone di valori uguali da qualche parte. C'è anche DENSE_RANK () se avete bisogno di questo.

Ciò richiede PostgreSQL 8.4, naturalmente.

Altri suggerimenti

Non è forse proprio questo:

SELECT  *
FROM    mytable
ORDER BY
        col1
OFFSET X LIMIT 1

O mi manca qualcosa?

Aggiornamento:

Se si desidera mostrare il rango, utilizzare questo:

SELECT  mi.*, values[1] AS rank, values[2] AS total
FROM    (
        SELECT  (
                SELECT  ARRAY[SUM(((mi.col1, mi.ctid) < (mo.col1, mo.ctid))::INTEGER), COUNT(*)]
                FROM    mytable mi
                ) AS values
        FROM    mytable mo
        WHERE   mo.id = @myid
        ) q

ROW_NUMBER funzionalità in PostgreSQL è implementato via LIMIT n OFFSET skip.

EDIT:Dal momento che si sta chiedendo per ROW_NUMBER() al posto di una semplice classifica: row_number() è stato introdotto per PostgreSQL in versione 8.4.Così si potrebbe considerare l'aggiornamento.Altrimenti questa soluzione potrebbe essere utile.

risposte precedenti affrontare la questione "selezionare tutte le righe e ottenere il loro rango", che non è quello che si vuole ...

  • si dispone di una riga
  • vuoi sapere il suo rango

Basta fare:

SELECT count (*) FROM tabella WHERE punteggio> $ 1

Dove $ 1 è il punteggio della riga appena selezionata (suppongo che si desideri visualizzare in modo che lei potrebbe selezionarlo ...).

Oppure fare:

Selezionare un. , (SELECT count () dalla tabella B dove punteggio> b.score) AS rango FROM tabella come WHERE pk = ...

Tuttavia, se si seleziona una riga che è classificata ultima, sì, sarà necessario contare tutte le righe che sono classificati prima di esso, quindi è necessario eseguire la scansione l'intera tabella, e sarà molto lento.

Soluzione:

SELECT count (*) FROM (SELECT 1 FROM tabella WHERE punteggio> $ 1 LIMIT 30)

Si otterrà classifica preciso per i 30 migliori punteggi, e sarà veloce. Chi si preoccupa per i perdenti?

OK, Se davvero si preoccupano i perdenti, è necessario fare un istogramma:

punteggio Supponiamo che può andare da 0 a 100, e si dispone 1000000 perdenti con punteggio <80 e 10 vincitori con il punteggio> 80.

Si effettua un istogramma di quante righe hanno un punteggio di X, si tratta di un piccolo semplice tabella con 100 righe. Aggiungere un trigger per la vostra tabella principale per aggiornare l'istogramma.

Ora, se si desidera rango un perdente che ha segnare X, il suo rango è sum (isto) dove histo_score> X.

Dal momento che il tuo punteggio, probabilmente non è compreso tra 0 e 100, ma (diciamo) compreso tra 0 e 1000000000, avrete bisogno di fudge un po ', allargare i bidoni istogramma, per esempio. in modo che solo bisogno di 100 bidoni di max, o usare qualche funzione di distribuzione di log-istogramma.

A proposito postgres fa questo quando si analizza la tabella, quindi se si imposta statistics_target a 100 o 1000 su punteggio, analizzare, e quindi eseguire:

SPIEGARE SELECT * FROM tabella WHERE punteggio> $ 1

si otterrà un bel stima del conteggio delle righe.

Chi ha bisogno di risposte esatte?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top