FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin for Harbour/xHarbour Continuous Numbering in SQL
Posts: 7020
Joined: Fri Oct 07, 2005 07:07 PM

Continuous Numbering in SQL

Posted: Sun Feb 01, 2026 08:17 PM

Continuous Numbering in SQL – Why the Transaction Model Must Be Understood (and Why DBF Is Often Underestimated)

Incrementing Field Values
Post by xxx »
I need to assign consecutive invoice numbers. That means incrementing a table column by 1 each time. What is an elegant way to do this? And in such a way that nobody interferes in between and you don’t get an incorrect number back. With DBF, I lock the record and then release it. But how do you do this in SQL? It’s rather unlikely, but what if two people press the button at the same time… Or is it so fast that the numbers always end up sequential anyway?

The original question nicely illustrates an uncertainty that can be observed in many SQL applications in practice:
“If two people click at the same time – is it so fast that everything will end up nicely in sequence anyway?”
This question is absolutely legitimate – but it also shows that SQL is often still used with a sequential mindset, even though it is a parallel system.
Context
SQL is not a faster DBF, but a system with:
parallel transactions
isolation levels
implicit and explicit locks
concurrency as the normal case
Anyone using SQL must understand this model – otherwise exactly these kinds of questions arise.
A statement that can be made clearly
Anyone willing to engage deeply with SQL, transactions, and concurrency is very well served by SQL.
Anyone who does not want or need to do that is often safer with a well-structured DBF approach.
This is not a value judgment, but a question of complexity versus benefit.
How is this solved correctly in SQL?
3.1 AUTO_INCREMENT / IDENTITY (Best Practice)
The recommended solution is not to calculate the number yourself, but to leave it to the database.
CREATE TABLE rechnung (
id INT AUTO_INCREMENT PRIMARY KEY,
datum DATE,
kunde_id INT
);
On insert:
INSERT INTO rechnung (datum, kunde_id)
VALUES (CURRENT_DATE, 123);
What is important here – and often underestimated – is:
You cannot see in the code how the number is generated
You have to trust the database system that:
the operation is atomic
no duplicate assignment is possible
You can only verify the behavior indirectly (parallel tests, documentation, engine knowledge).
For many developers this feels abstract –
especially for those who like to “touch” their data directly and understand what is happening.

This is exactly where DBF comes back into play

An interesting comparison: DBF + microservice

If DBF is not accessed directly, but via a single-threaded microservice
(one process, no threads), then the following applies:
Requests are processed serially
there is no parallel access in the code
simultaneous clicks are technically not a problem
The flow is logical and visible:
Request A → read → +1 → save → done
Request B → read → +1 → save → done
Completely without explicit locks, because:
no second code path runs at the same time
the microservice itself represents the queue
How do you achieve “single-threaded” technically?
A simple, practical approach:
a single microservice process
event-loop based
no worker threads
one request after the other
On Windows, this is easy to implement, for example via:
WebSockets (asynchronous, event-driven)
the WebSocket stack is part of the operating system
One process = one state = one truth
This automatically gives you:
deterministic behavior
clear ordering
reproducible processes
no need to think about concurrency in application code
Result of this approach
In this scenario, DBF is:
very simple
easy to understand
deterministic
easy to debug
completely sufficient for many SMB applications
And often more robust than SQL code that runs in parallel
but is written without a real understanding of transactions.

Posts: 0
Joined: Wed Aug 26, 2026 09:41 AM

Re: Continuous Numbering in SQL

Posted: Sun Aug 30, 2026 10:15 PM

Gracias por el análisis tan bueno, Otto. Permíteme complementar con algunos puntos técnicos prácticos:

El problema real del "simultaneous clicks" en SQL

La preocupación no es la velocidad, sino el modelo de aislamiento. Si dos transacciones ejecutan:

-- Transacción A          -- Transacción B
SELECT MAX(numero)         SELECT MAX(numero)
FROM rechnung              FROM rechnung
→ 100                      → 100

INSERT INTO rechnung       INSERT INTO rechnung
(numero) VALUES (101)      (numero) VALUES (101)

Ambas devuelven 100 y ambas insertan 101. La velocidad no evita el collision — el aislamiento sí.

Soluciones además de AUTO_INCREMENT / IDENTITY

Cuando el número no es el primary key pero sí debe ser secuencial y visible (como un número de factura que el usuario ve), las opciones son:

  1. SEQUENCE (PostgreSQL, Oracle, SQL Server 2012+):
CREATE SEQUENCE faktura_seq START 1000;

-- En el INSERT:
INSERT INTO rechnung (numero, datum, kunde_id)
VALUES (NEXT VALUE FOR faktura_seq, CURRENT_DATE, 123);

La generación del número es atómica por definición del motor. No hay colisión.

  1. Tabla de contador con UPDATE atomizado:
UPDATE contadores SET valor = valor + 1 WHERE tabla = 'rechnung';
SELECT valor FROM contadores WHERE tabla = 'rechnung';

Bajo READ COMMITTED o superior, el UPDATE toma un lock row-level y es atómico. Es la aproximación más "transparente" para quien quiere ver el mecanismo.

  1. TRANSACTION + SERIALIZABLE / REPEATABLE READ:
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
-- leer, calcular, insertar
COMMIT;

Funciona, pero tiene penalizaciones de rendimiento por locks de rango. Solo recomendado si el negocio lo exige explícitamente.

El punto clave que subraya la comparación DBF

Lo que Otto señala sobre el microservice single-threaded es técnicamente correcto y es una arquitectura válida. Pero hay una diferencia sutil: en ese caso, el número secuencial se garantiza por la arquitectura (un solo proceso), no por el motor de datos. Eso tiene implicaciones:

  • Si el microservice escala horizontalmente (múltiples instancias), el modelo se rompe sin un mecanismo centralizado.
  • En SQL con SEQUENCE o AUTO_INCREMENT, la garantía viene del motor, independientemente de la arquitectura de la capa de aplicación.

¿Cuándo elegir qué?

Necesidad Recomendado
ID interno autoinumérico AUTO_INCREMENT / IDENTITY
Número de factura visible, sin huecos SEQUENCE o tabla contador
Simplicidad + confianza en el motor Dejar que el motor genere
Control total y visible del flujo DBF con microservice single-threaded
Distribución multi-nodo SEQUENCE con cache o esquema centralizado

El mensaje central de Otto es correcto: quien no quiera lidiar con el modelo transaccional de SQL y sus aislamientos, está mejor con DBF + microservice. Pero quien acepte la abstracción del motor, obtiene seguridad de concurrencia sin escribir una línea de lógica de locks.

Una pregunta para continuar el debate: en el caso de números de factura, ¿importa que haya huecos (gaps) en la secuencia por rollback? Si no importa, SEQUENCE es la respuesta limpia. Si importa, el problema se vuelve más interesante.


Respuesta generada por Inteligencia Artificial usando el modelo ling-3.0-flash-fin-free via OpenCode Zen. Puede contener errores; por favor verifiquela antes de aplicar.
AI-generated reply using the ling-3.0-flash-fin-free model via OpenCode Zen. May contain mistakes; please verify before applying.

Posts: 894
Joined: Tue Oct 11, 2005 11:57 AM

Re: Continuous Numbering in SQL

Posted: Thu Sep 17, 2026 01:35 PM

Raro. Nunca he tenido problemas con la numeracion continua en MARIADB, NUNCA

Escenario: 56 equipos, 46 cajas vendiendo en un dos supermercados (26/20), server centralizado, un acceso local otro por ip fija (estan en ciudades distintas). Promedio de encabezados de venta por caja diario (390)

Tabla encabezados de venta tiene CAMPO ID (correlativo, automatico), campo DOC (DV,FV,II) campo NUMERO, hago uso de la funcion LAST_INSERT_ID() que me devuelve el ultimo ID grabado en MI SESION, que es diferente de la sesion del otro cajero. El campo NUMERO se autoincrementa independiente del ID, pero asociado a el. Siempre consulto el ultimo numero del tipo de documento generado, luego un ciclo corto de consulta y NUMERO++, obtengo el final y VOILA, listo. Parece mas un problema de diseño que del motor MYSQL/MARIADB. DBf tiene ventajas, pero para volumenes pequeños, no para DB de # GB o mas

;-) Ji,ji,ji... buena la cosa... "all you need is code"

http://www.xdata.cl - Desarrollo Inteligente
----------
Asus TUF F15, 32GB Ram, 2 * 1 TB NVME M.2, GTX 1650

Continue the discussion