Tengo un requisito comercial de que cada registro en la tabla Factura tenga una identificación que se parezca a YYYYNNNNNN.
La parte NNNNNN necesita reiniciarse al comienzo de cada año. Entonces, la primera fila ingresada en 2016 se vería como 2016000001 y la segunda como 2016000002, etc. Digamos que el último registro para 2016 fue 2016123456, La siguiente fila (de 2017) debería verse como 2017000001
No necesito esta identificación para ser la clave principal y también almaceno la fecha de creación. La idea es que este 'ID de pantalla' es único (por lo que puedo consultar por él) y apto para grupos humanos, por año.
Es poco probable que se eliminen los registros; sin embargo, me inclinaría a codificar defensivamente contra algo así.
¿Hay alguna forma de que pueda crear esta identificación sin tener que consultar la identificación máxima este año cada vez que inserte una nueva fila?
Ideas:
- A
CreateNewInvoiceSP
, que obtiene elMAX
valor para ese año (asqueroso) - Alguna característica mágica incorporada para hacer exactamente esto (puedo soñar bien)
- Ser capaz de especificar algún UDF o algo en la declaración
IDENTITY
oDEFAULT
(??) - Una vista que usa
PARTITION OVER + ROW()
(eliminada sería problemática) - Un activador activado
INSERT
(aún necesitaría ejecutar algunaMAX
consulta :() - Un trabajo de fondo anual, actualizó una tabla con el MAX para cada año insertado que luego ...
Todos los cuales son un poco no ideales. Sin embargo, cualquier idea o variación es bienvenida.
fuente
Respuestas:
Hay 2 elementos en su campo.
No necesitan ser almacenados como un solo campo
Ejemplo:
YEAR(GETDATE())
Luego cree una columna calculada que los concatene (con el formato adecuado). La secuencia se puede restablecer en el cambio de año.
Código de muestra en SQLfiddle : * (SQLfiddle no siempre funciona)
fuente
SEQUENCE
al comienzo de cada año?NEXT VALUE FOR
en unaCASE
declaración (lo intenté)¿Consideró crear un campo de identidad con seed = 2016000000?
Esta semilla debe autoincrementarse cada año, por ejemplo, en la noche de 2017/1/1 debe programar
Pero ya veo problemas con el diseño, por ejemplo: ¿qué pasa si tienes millones de registros?
fuente
Lo que hice en este escenario fue multiplicar el año por 10 ^ 6 y agregarle el valor de secuencia. Esto tiene la ventaja de no requerir un campo calculado con su sobrecarga continua (pequeña) y el campo se puede usar como un
PRIMARY KEY
.Hay dos posibles trucos:
asegúrese de que su multiplicador sea lo suficientemente grande para que nunca se agote, y
no se garantiza una secuencia sin espacios debido al almacenamiento en caché de la secuencia.
No soy un experto en SQL Server, pero probablemente pueda configurar un evento para que se active a 201x 00:00:00 para restablecer su secuencia a cero. Eso también fue lo que hice en Firebird (¿o fue Interbase?).
fuente
Editar: esta solución no funciona bajo carga
No soy un fanático de los desencadenantes, pero esto parece mejor que podría resolver.
Pros:
Editar: Contras:
(Gracias a @gbn porque me inspiré en su respuesta) (Cualquier comentario y señalar los errores obvios son bienvenidos :)
Agregue algunos nuevos
COLUMN
sy unINDEX
Agrega el nuevo
TRIGGER
fuente
NULL
valores. De vuelta al tablero de dibujo ...ON Previous.Id = (I.Id -1)
solo debería buscar), pero sí, todavía no funciona. Si pudiera bloquear la mesa (?) Durante la inserción y el disparo, creo que funcionaría. Pero eso también suena como un olor a código.