MySQL: ottieni il numero di riga su Seleziona


181

Posso eseguire un'istruzione select e ottenere il numero di riga se gli articoli sono ordinati?

Ho un tavolo come questo:

mysql> describe orders;
+-------------+---------------------+------+-----+---------+----------------+
| Field       | Type                | Null | Key | Default | Extra          |
+-------------+---------------------+------+-----+---------+----------------+
| orderID     | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| itemID      | bigint(20) unsigned | NO   |     | NULL    |                |
+-------------+---------------------+------+-----+---------+----------------+

Posso quindi eseguire questa query per ottenere il numero di ordini per ID:

SELECT itemID, COUNT(*) as ordercount
FROM orders
GROUP BY itemID ORDER BY ordercount DESC;

Questo mi dà un conto di ciascuno itemIDnella tabella in questo modo:

+--------+------------+
| itemID | ordercount |
+--------+------------+
|    388 |          3 |
|    234 |          2 |
|   3432 |          1 |
|    693 |          1 |
|   3459 |          1 |
+--------+------------+

Voglio ottenere anche il numero di riga, quindi potrei dire che itemID=388è la prima riga, 234è la seconda, ecc. (Essenzialmente la classifica degli ordini, non solo un conteggio grezzo). So che posso farlo in Java quando ottengo il risultato ripristinato, ma mi chiedevo se ci fosse un modo per gestirlo puramente in SQL.

Aggiornare

L'impostazione del grado lo aggiunge al set di risultati, ma non correttamente ordinato:

mysql> SET @rank=0;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @rank:=@rank+1 AS rank, itemID, COUNT(*) as ordercount
    -> FROM orders
    -> GROUP BY itemID ORDER BY rank DESC;
+------+--------+------------+
| rank | itemID | ordercount |
+------+--------+------------+
|    5 |   3459 |          1 |
|    4 |    234 |          2 |
|    3 |    693 |          1 |
|    2 |   3432 |          1 |
|    1 |    388 |          3 |
+------+--------+------------+
5 rows in set (0.00 sec)

1
Per riferimento futuro: se si desidera ordinare dal rango 1 al rango 5, utilizzare ORDER BY rank ASC(ordinamento per rango in ordine crescente). Immagino sia quello che intendi ma non correttamente ordinato
BlueCacti

Risposte:


180

Dai un'occhiata a questo .

Cambia la tua query in:

SET @rank=0;
SELECT @rank:=@rank+1 AS rank, itemID, COUNT(*) as ordercount
  FROM orders
  GROUP BY itemID
  ORDER BY ordercount DESC;
SELECT @rank;

L'ultima selezione è il tuo conteggio.


1
Ciò aggiunge il grado al set di risultati, ma non li mette nell'ordine corretto - domanda aggiornata con risultati
George

1
Prova a mantenere il ORDER BY ordercount DESC, quindi avvolgi l'intera query in un'altra SELECTche ottiene tutto dal primo, ma ordina per colonna di rango (0 in questo caso).
Mike Cialowicz,

1
Puoi mostrare un esempio di questo? Come avvolgere le selezioni?
George

9
Guarda la risposta di
swamibebop

1
@MikeCialowicz, Questo non funziona . Fare riferimento alla mia soluzione o alla soluzione di Swamibebop per la risposta giusta.
Pacerier,

178
SELECT @rn:=@rn+1 AS rank, itemID, ordercount
FROM (
  SELECT itemID, COUNT(*) AS ordercount
  FROM orders
  GROUP BY itemID
  ORDER BY ordercount DESC
) t1, (SELECT @rn:=0) t2;

1
Grazie per il chiarimento, questo ha risolto il problema fuori servizio che stavo avendo.
Thaddeusmt,

1
Grazie, questo è stato davvero utile per me :) Sono sorpreso che non esista un modo più semplice per ottenere "indici" di riga da un set di risultati ... ma comunque grazie è stato utile.
ratto

È possibile aggiungere una quarta riga con un conteggio totale incrementale modificando la prima istruzione select in SELECT \ @rn: = \ @ rn + 1 classifica AS, itemID, conta ordini, \ @tot: = \ @ tot + conta ordini come totale. Per definire il valore iniziale di \ @tot, questo dovrebbe essere aggiunto dopo t2: (SELECT \ @tot: = 0) t3. Elimina il \ before every \ @, che ho dovuto utilizzare per eludere la formattazione del mini-markdown.
Jan Ehrhardt,

2
Qualcuno può spiegare la rilevanza di t1e t2?
Jared,

2
@Jared, la sintassi di MySQL ha solo bisogno di qualcosa per essere lì. Può essere qualsiasi cosa, anche xe y.
Pacerier,

31

La soluzione di Swamibebop funziona, ma sfruttando la table.*sintassi, possiamo evitare di ripetere i nomi delle colonne degli interni selecte ottenere un risultato più semplice / breve:

SELECT @r := @r+1 , 
       z.* 
FROM(/* your original select statement goes in here */)z, 
(SELECT @r:=0)y;

In modo che ti darà:

SELECT @r := @r+1 , 
       z.* 
FROM(
     SELECT itemID, 
     count(*) AS ordercount
     FROM orders
     GROUP BY itemID
     ORDER BY ordercount DESC
    )z,
    (SELECT @r:=0)y;

Sai per caso perché usare @r := @r + 1in un'istruzione select funziona, ma se è in una procedura memorizzata con declare r int; set r = 0;, si lamenta (on r := r +1)?
Dan M.,

@Pacerier, anche l'ordine delle righe è la seconda selezione garantita da qualche parte? So che l'ordine delle righe restituite dalla selezione senza ordine per clausola non è garantito da nessuna parte, e la selezione più esterna è esattamente quella, sebbene selezioni dalla selezione ordinata interna, quindi potrebbe essere un'eccezione. Se non lo è, tuttavia, non riesco a vedere come questa sia una soluzione corretta poiché avrà lo stesso difetto di Mike di Chibu - nessuna garanzia in quale ordine selezionare passerà attraverso i record e li numererà.
Dan M.,

Avresti idea del perché ORDER BY non funziona ogni volta che non è nell'elenco dei campi? Vedi il mio risultato: hastebin.com/aluqefunoy.rb
Inverno

11

È possibile utilizzare le variabili MySQL per farlo. Qualcosa del genere dovrebbe funzionare (tuttavia, è costituito da due query).

SELECT 0 INTO @x;

SELECT itemID, 
       COUNT(*) AS ordercount, 
       (@x:=@x+1) AS rownumber 
FROM orders 
GROUP BY itemID 
ORDER BY ordercount DESC; 

2
Attenzione, questo non funzionerebbe perché order bysuccede dopo che la variabile @xè stata valutata. Prova a sperimentare ordinando utilizzando le altre colonne. Sperimenta anche con entrambi desce asc. Vedrai che molte volte falliranno e le uniche volte in cui funziona, è per pura fortuna perché l'ordine della tua "selezione" originale ha lo stesso ordine di order by. Vedi la mia soluzione e / o la soluzione di Swamibebop.
Pacerier,

@Pacerier ne sei sicuro? Ho stanco query simili in un esempio diverso (sostanzialmente seleziono dalla colonna di numeri e numerali secondo il loro ordine) a quanto pare se ordinassi per var / row num, quando cambiava l'ordine delle righe risultanti, ma ogni numero aveva la stessa riga num. Ma se ordino per la colonna numerica, allora ASC/ DESCcambierebbe l'ordine in cui quei numeri erano numerati (dal più piccolo al più grande o viceversa). Quindi sembra che in quel caso sia order bystato valutato per primo.
Dan M.,

1

Ora è integrato in MySQL 8.0 e MariaDB 10.2:

SELECT
  itemID, COUNT(*) as ordercount,
  ROW_NUMBER OVER (PARTITION BY itemID ORDER BY rank DESC) as rank
FROM orders
GROUP BY itemID ORDER BY rank DESC
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.