2012-01-28 15 views
11

ho bisogno di essere in grado di generare eseguire una query che restituirà il valore successivo di ID sul seguente tabella:MySQL equivalente di SEQUENCE.NEXTVAL di Oracle

CREATE TABLE animals (
    id MEDIUMINT NOT NULL AUTO_INCREMENT, 
    name CHAR(30) NOT NULL, 
    PRIMARY KEY (id) 
) 

In Oracle è possibile chiamare NEXTVAL su una sequenza e ti dà la sequenza successiva (nota: senza dover fare un inserto sul tavolo).

Dopo googling in giro ho trovato che è possibile trovare il valore corrente di auto_increment utilizzando la seguente query:

SELECT Auto_increment 
FROM information_schema.tables 
WHERE table_name='animals'; 

Il problema è Vorrei che il valore da incrementare ogni volta che il valore viene interrogato. In Oracle, quando si chiama nextval, il valore della sequenza viene incrementato anche se non si inserisce una riga in una tabella.

Esiste un modo per modificare la query precedente in modo che il valore restituito sia sempre diverso dall'ultima chiamata alla query? Ad esempio, Auto_increment viene incrementato ogni volta che viene controllato e quando viene utilizzato su una query utilizza un nuovo valore.

Sto usando Spring JDBCTemplate quindi se può essere eseguito in una query, meglio è.

risposta

5

questo esempio con InnoDB dimostra un modo per implementare il proprio contatore utilizzando query intrecciate:

http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html

cosa hai bisogno per creare un gap per? Per prenotare gli ID? Preferisco "aggiustare" il design a tutti i costi e aggiornare gli altri moduli invece di toccare una sequenza.

Invece di solo incrementare esplicitamente la sequenza, lo implicherei inserendo una riga predefinita (contrassegnata come non valida) per ciascun ID per allocare e restituire l'id. Questo approccio è coerente e portatile. Successivamente, invece di forzare gli inserti utilizzando un valore di sequenza esplicito, è possibile aggiornare queste righe predefinite con i relativi valori di sequenza corrispondenti. Ciò richiede più memoria ma nessun blocco. La raccolta dei dati inutili sulle righe scadute può aiutarti qui. le istruzioni "inserisci o aggiorna" possono ricreare le righe raccolte inutilmente, ma non lo farei.

+0

A tutti i costi? Veramente? –

4

Si potrebbe aggiungere la tua funzione di MySQL - come dimostrato a http://www.microshell.com/database/mysql/emulating-nextval-function-to-get-sequence-in-mysql/ - permette di fare qualcosa di simile:

SELECT nextval('sq_my_sequence') as next_sequence; 
+0

ho visto che ad esempio mentre googling. Sfortunatamente richiede la rimozione dell'uso di AUTO_INCREMENT sulla colonna ID che al momento non è possibile in quanto dovrò cambiare gli altri moduli che usano questa tabella - Grazie. – ziggy

+1

Nei commenti su quella pagina qualcuno solleva la preoccupazione che potrebbe esserci una condizione di competizione. Sembra più facile usare il metodo auto_increment @Ivan ha dato, dove il lavoro è fatto in una singola istruzione, ed è quindi atomico. Potresti avvolgere il metodo di Ivan in una funzione, il che sarebbe comunque carino, offrendoti il ​​meglio di entrambi gli approcci. –

+0

puoi aggiornare la tua risposta per il contenuto effettivo invece del link? la query fornita da sola non funzionerà. – jangorecki

2

MySQL utilizza AUTO_INCREMENT che serve gli scopi. Ma vi sono differenze di seguito:

MySQL AUTO_INCREMENT a Oracle SEQUENCE Differenze

  • AUTO_INCREMENT è limitata ad una colonna per tabella
  • AUTO_INCREMENT deve essere assegnato ad una specifica table.column (non permettendo multi uso tabella)
  • AUTO_INCREMENT viene inserito come colonna non specificata, o un valore NULL

se si desidera sE e un'implementazione SEQUENCE con MySQL, può fare con SP.

Fare riferimento al collegamento seguente spiegando tutto ciò che si desidera.

http://ronaldbradford.com/blog/sequences-in-mysql-2006-01-26/

1

si desidera che il valore successivo su quel tavolo in modo da poter fare le righe che non sono ancora inseriti senza disturbare gli altri processi che utilizzano l'auto-incremento?

Alcune opzioni:

andare avanti e basta inserire le righe di "usare la sequenza", contrassegnarli come sospeso e quindi aggiornare in un secondo momento.

Inserire in una transazione e interrompere la transazione: la sequenza del numero automatico dovrebbe essere utilizzata e creare una "distanza" nella tabella normalmente - quel numero è ora libero per l'uso.

Con Oracle, la sequenza è completamente indipendente dalla tabella, quindi i processi possono utilizzare la sequenza o meno (e possono anche utilizzare la stessa sequenza per tabelle diverse).In tal caso, è possibile implementare una tabella solo in sequenza a cui si accede tramite un tipo di funzione e per gli altri processi che devono fare affidamento sull'auto-incremento, rimuovere l'auto-incremento e utilizzare un trigger che assegna dallo stesso funzione di sequenza se non viene fornito alcun ID.

10

http://docs.oracle.com/cd/E17952_01/refman-5.5-en/example-auto-increment.html

3.6.9. Utilizzando AUTO_INCREMENT

L'attributo AUTO_INCREMENT può essere utilizzato per generare un'identità unica per nuove righe:

CREATE TABLE animals (
    id MEDIUMINT NOT NULL AUTO_INCREMENT, 
    name CHAR(30) NOT NULL, 
    PRIMARY KEY (id) 
); 

INSERT INTO animals (name) VALUES 
    ('dog'),('cat'),('penguin'), 
    ('lax'),('whale'),('ostrich'); 

SELECT * FROM animals; 
Which returns: 

+----+---------+ 
| id | name | 
+----+---------+ 
| 1 | dog  | 
| 2 | cat  | 
| 3 | penguin | 
| 4 | lax  | 
| 5 | whale | 
| 6 | ostrich | 
+----+---------+ 

Nessun valore è stato specificato per la colonna AUTO_INCREMENT, quindi MySQL assegnato automaticamente numeri di sequenza. È inoltre possibile assegnare in modo esplicito NULL o 0 alla colonna per generare numeri di sequenza.

È possibile recuperare il valore AUTO_INCREMENT più recente con la funzione SQL LAST_INSERT_ID() o la funzione API C mysql_insert_id(). Queste funzioni sono specifiche della connessione, quindi i loro valori di ritorno non sono influenzati da un'altra connessione che sta anche eseguendo inserimenti.

Utilizzare il tipo di dati intero più piccolo per la colonna AUTO_INCREMENT di dimensioni sufficienti a contenere il valore di sequenza massimo necessario. Quando la colonna raggiunge il limite superiore del tipo di dati, il tentativo successivo di generare un numero di sequenza fallisce. Utilizzare l'attributo UNSIGNED se possibile per consentire un intervallo maggiore. Ad esempio, se si utilizza TINYINT, il numero di sequenza massimo consentito è 127. Per TINYINT UNSIGNED, il massimo è 255. Vedere Sezione 11.2.1, "Tipi interi (valore esatto) - INTEGER, INT, SMALLINT, TINYINT, MEDIUMINT, BIGINT "Per gli intervalli di tutti i tipi interi.

Nota Per un inserimento di più righe, LAST_INSERT_ID() e mysql_insert_id() restituiscono effettivamente la chiave AUTO_INCREMENT dalla prima delle righe inserite. Ciò consente di riprodurre correttamente inserimenti su più righe su altri server in una configurazione di replica.

Se la colonna AUTO_INCREMENT è parte di più indici, MySQL genera valori di sequenza utilizzando l'indice che inizia con la colonna AUTO_INCREMENT, se ce n'è uno. Ad esempio, se la tabella degli animali contenesse gli indici PRIMARY KEY (grp, id) e INDEX (id), MySQL ignorerebbe il PRIMARY KEY per generare valori di sequenza. Di conseguenza, la tabella conterrà una singola sequenza, non una sequenza per valore di grp.

iniziare con un valore AUTO_INCREMENT diverso da 1, impostare tale valore con CREATE TABLE o ALTER TABLE, in questo modo:

mysql> ALTER TABLE tbl AUTO_INCREMENT = 100; Note InnoDB

Per le tabelle InnoDB, fare attenzione se si modifica la colonna contenente il valore di incremento automatico nel mezzo di una sequenza di istruzioni INSERT. Ad esempio, se si utilizza un'istruzione UPDATE per inserire un nuovo valore più grande nella colonna di incremento automatico, un INSERT successivo potrebbe riscontrare un errore "Duplicate entry". Il test se un valore di auto-incremento è già presente si verifica se si esegue una DELETE seguita da più istruzioni INSERT o quando si COMMIT la transazione, ma non dopo un'istruzione UPDATE.

MyISAM Note

Per le tabelle MyISAM, è possibile specificare AUTO_INCREMENT su una colonna secondaria in un indice a più colonne. In questo caso, il valore generato per la colonna AUTO_INCREMENT viene calcolato come MAX (auto_increment_column) + 1 prefisso WHERE = prefisso dato. Questo è utile quando vuoi mettere i dati in gruppi ordinati.

CREATE TABLE animals (
    grp ENUM('fish','mammal','bird') NOT NULL, 
    id MEDIUMINT NOT NULL AUTO_INCREMENT, 
    name CHAR(30) NOT NULL, 
    PRIMARY KEY (grp,id) 
) ENGINE=MyISAM; 

INSERT INTO animals (grp,name) VALUES 
    ('mammal','dog'),('mammal','cat'), 
    ('bird','penguin'),('fish','lax'),('mammal','whale'), 
    ('bird','ostrich'); 

SELECT * FROM animals ORDER BY grp,id; 
Which returns: 

+--------+----+---------+ 
| grp | id | name | 
+--------+----+---------+ 
| fish | 1 | lax  | 
| mammal | 1 | dog  | 
| mammal | 2 | cat  | 
| mammal | 3 | whale | 
| bird | 1 | penguin | 
| bird | 2 | ostrich | 
+--------+----+---------+ 

In questo caso (quando la colonna AUTO_INCREMENT è parte di un indice a più colonne), valori AUTO_INCREMENT si riutilizzano se si elimina la riga con il più grande valore AUTO_INCREMENT in qualsiasi gruppo. Questo accade anche per le tabelle MyISAM, per le quali i valori AUTO_INCREMENT normalmente non vengono riutilizzati.

Ulteriori letture

Maggiori informazioni su AUTO_INCREMENT è disponibile qui:

Come assegnare l'attributo AUTO_INCREMENT per una colonna: Sezione 13.1.17, “CREATE TABLE sintassi”, e la Sezione 13.1.7, “ ALTER TABLE Sintassi ".

Come si comporta AUTO_INCREMENT in base alla modalità SQL NO_AUTO_VALUE_ON_ZERO: Sezione 5.1.7, "Modalità SQL del server".

Come utilizzare la funzione LAST_INSERT_ID() per trovare la riga che contiene il valore AUTO_INCREMENT più recente: Sezione 12.14, "Funzioni di informazione".

Impostazione del valore AUTO_INCREMENT da utilizzare: Sezione 5.1.4, "Variabili di sistema del server".

AUTO_INCREMENT e replica: Sezione 16.4.1.1, "Replica e AUTO_INCREMENT".

Variabili del sistema server relative a AUTO_INCREMENT (auto_increment_increment e auto_increment_offset) che è possibile utilizzare per la replica: Sezione 5.1.4, "Variabili di sistema del server".

http://search.oracle.com/search/search?q=auto_increment&group=Documentation&x=0&y=0

0

Dai un'occhiata alla MariaDBs SEQUENCE motore.Con esso è possibile generare sequenze facile come

SELECT seq FROM seq_1_to_5; 
+-----+ 
| seq | 
+-----+ 
| 1 | 
| 2 | 
| 3 | 
| 4 | 
| 5 | 
+-----+ 

dettagli here: https://mariadb.com/kb/en/mariadb/sequence/

Con questo si dovrebbe essere in grado di fare qualcosa di simile

SELECT min(seq) as nextVal FROM seq_1_to_500 
WHERE seq NOT IN (SELECT ID FROM customers) 
+0

Cosa interessante, ma molto probabilmente non è una risposta alla domanda. – hgoebl

Problemi correlati