Comment pouvez-vous avoir deux colonnes auto-incrémentielles dans une table?

8

J'ai une table MySQL qui contient des informations sur les factures d'une entreprise. Cependant, cette entreprise possède deux succursales et chacune d'elles a une séquence de facturation unique; une "Serie A" et "Serie B", pour ainsi dire. Cependant, il s'agit d'une seule entreprise et je ne souhaite pas créer deux tableaux de factures. Au contraire, je veux en quelque sorte avoir deux incréments automatiques différents pour une table. Je sais que ce n'est techniquement pas possible, mais je suppose que c'est un problème que d'autres ont déjà abordé, alors j'aimerais savoir s'il existe une «solution» bien connue pour ce problème?

Ce que je fais en ce moment n'est pas d'utiliser la clé primaire comme numéro de facture (ce qui serait idéal), mais plutôt d'utiliser une colonne secondaire avec l'ID de facture, qui est incrémentée manuellement (enfin, en utilisant un script PHP, mais ce n'est toujours pas automatique ), en vérifiant la dernière facture de cette série particulière.

Voici ma configuration actuelle:

CREATE TABLE `invoices` (
  `id` mediumint unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `invoicenumber` mediumint unsigned NOT NULL,
  `branch` enum('A','B') NOT NULL,
  `date` date NOT NULL,
  `client` varchar(100) NOT NULL
) COMMENT='' ENGINE='InnoDB';

Pour vérifier la facture du lateset, je lance:

SELECT MAX(invoicenumber+1) AS new_invoice_number FROM invoices WHERE branch = 'A'

User402841
la source

Réponses:

11

Ce que vous proposez de faire ne peut être fait correctement avec MySQL que dans trois (3) conditions

  • CONDITION # 1 : Utilisez le moteur de stockage MyISAM
  • CONDITION # 2 : Faire de la colonne auto_increment une clé primaire composée
  • CONDITION # 3 : Chaque auto_increment pour un type donné doit exister dans sa propre ligne
  • Voir la documentation auto_increment pour MyISAM

Voici la disposition originale de votre table

CREATE TABLE `invoices` ( 
  `id` mediumint unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY, 
  `invoicenumber` mediumint unsigned NOT NULL, 
  `branch` enum('A','B') NOT NULL, 
  `date` date NOT NULL, 
  `client` varchar(100) NOT NULL 
) COMMENT='' ENGINE='InnoDB'; 

Sur la base des trois conditions que je viens de mentionner, voici la nouvelle disposition de table proposée:

CREATE TABLE `invoices` ( 
  `invoicenumber` mediumint unsigned NOT NULL auto_increment, 
  `branch` enum('A','B') NOT NULL, 
  `date` date NOT NULL, 
  `client` varchar(100) NOT NULL,
  PRIMARY KEY (branch,invoicenumber)
) COMMENT='' ENGINE='MyISAM'; 

Voici un exemple via des exemples de données et SQL:

drop database if exists user1162541;
create database user1162541;
use user1162541
CREATE TABLE `invoices` ( 
  `invoicenumber` mediumint unsigned NOT NULL auto_increment, 
  `branch` enum('A','B') NOT NULL, 
  `date` date NOT NULL, 
  `client` varchar(100) NOT NULL,
  PRIMARY KEY (branch,invoicenumber)
) COMMENT='' ENGINE='MyISAM'; 
INSERT INTO invoices (branch,date,client) VALUES
('A',DATE(NOW()),'John'),
('B',DATE(NOW()),'Jack'),
('A',DATE(NOW()),'Jeff'),
('B',DATE(NOW()),'Joel'),
('A',DATE(NOW()),'Jane'),
('B',DATE(NOW()),'Joan'),
('A',DATE(NOW()),'June');
SELECT * FROM invoices ORDER BY branch,invoicenumber;

Ici, il est exécuté:

mysql> drop database if exists user1162541;
Query OK, 1 row affected (0.01 sec)

mysql> create database user1162541;
Query OK, 1 row affected (0.02 sec)

mysql> use user1162541
Database changed
mysql> CREATE TABLE `invoices` (
    ->   `invoicenumber` mediumint unsigned NOT NULL auto_increment,
    ->   `branch` enum('A','B') NOT NULL,
    ->   `date` date NOT NULL,
    ->   `client` varchar(100) NOT NULL,
    ->   PRIMARY KEY (branch,invoicenumber)
    -> ) COMMENT='' ENGINE='MyISAM';
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO invoices (branch,date,client) VALUES
    -> ('A',DATE(NOW()),'John'),
    -> ('B',DATE(NOW()),'Jack'),
    -> ('A',DATE(NOW()),'Jeff'),
    -> ('B',DATE(NOW()),'Joel'),
    -> ('A',DATE(NOW()),'Jane'),
    -> ('B',DATE(NOW()),'Joan'),
    -> ('A',DATE(NOW()),'June');
Query OK, 7 rows affected (0.02 sec)
Records: 7  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM invoices ORDER BY branch,invoicenumber;
+---------------+--------+------------+--------+
| invoicenumber | branch | date       | client |
+---------------+--------+------------+--------+
|             1 | A      | 2012-04-21 | John   |
|             2 | A      | 2012-04-21 | Jeff   |
|             3 | A      | 2012-04-21 | Jane   |
|             4 | A      | 2012-04-21 | June   |
|             1 | B      | 2012-04-21 | Jack   |
|             2 | B      | 2012-04-21 | Joel   |
|             3 | B      | 2012-04-21 | Joan   |
+---------------+--------+------------+--------+
7 rows in set (0.00 sec)

mysql>

Essaie !!!

CAVEAT: À l'heure actuelle, seul le moteur de stockage MyISAM prend en charge plusieurs valeurs auto_increment regroupées avec d'autres colonnes. Ce n'est pas possible avec InnoDB basé sur des colonnes auto_increment liées directement à gen_clust_index (aka Clustered Index) !!!

RolandoMySQLDBA
la source
C'est TOTALEMENT IMPRESSIONNANT! Je n'avais aucune idée que c'était possible ... merci de m'éclairer !!
User402841
Vous pouvez faire une chose (similaire) dans InnoDB mais malheureusement cela ne fonctionne pas comme on l'espère. Les numéros d'invités seraient (1,3,5,7)et (2,4,6)pour les deux branches respectivement :(
ypercubeᵀᴹ
Vraiment dommage ça ne marche pas pour InnoDB!
User402841
@user, si InnoDB est nécessaire (dans mon cas, j'avais besoin d'une clé étrangère), vous pouvez utiliser un déclencheur pour simuler l'incrémentation automatique de plusieurs champs. Voir cet article
Murta
0

Utilisez un déclencheur après insertion sur le tableau des factures pour définir la valeur du numéro de facture une fois la ligne correctement insérée.

Cela signifie que vous n'avez pas à faire le calcul dans votre script PHP, mais dans la base de données.

Stephen Senkomago Musoke
la source