Formatear números rellenando con ceros a la izquierda en SQL Server


119

Tenemos una tabla SQL antigua que fue utilizada por SQL Server 2000 durante casi 10 años.

En él, nuestros números de tarjeta de empleado se almacenan char(6)del 000001al 999999.

Ahora estoy escribiendo una aplicación web y necesito almacenar los números de identificación de los empleados.

En mi nueva tabla, podría tomar el atajo y copiar la tabla anterior, pero espero una mejor transferencia de datos, un tamaño más pequeño, etc., simplemente almacenando los intvalores de 1a 999999.

En C #, puedo formatear rápidamente un intvalor para el número de placa usando

public static string GetBadgeString(int badgeNum) {
  return string.Format("{0:000000}", badgeNum);
  // alternate
  // return string.Format("{0:d6}", badgeNum);
}

¿Cómo modificaría esta simple consulta SQL para formatear también el valor devuelto?

SELECT EmployeeID
FROM dbo.RequestItems
WHERE ID=0

Si EmployeeIDes 7135, esta consulta debería regresar 007135.


Dado que las 0s iniciales son importantes para este campo, ¿por qué cambiarlas a una INT?
Oded

2
SQL Server 2012 finalmente tendrá una FORMATfunción como C # :-)
marc_s

1
@Oden: Los intvalores ocupan mucho menos espacio que char(6), y habrá múltiples de estas entradas por pieza que se fabrique. Eficiencia.
jp2code

¿Está optimizando antes de experimentar un problema?
Oded

4
Veamos, tiene hasta un millón de números de placa y calcula que puede guardar (según DATALENGTH()) dos bytes cada uno. Dado que la columna puede estar en un índice, podría estar ahorrando más de 2 MB. Y con otras columnas sumadas, esos 2 bytes podrían ser suficientes para reducir la longitud de una fila lo suficiente como para ahorrar una página de 4 KB por fila. ¿Se alojará en una plataforma móvil o es posible que centre su atención en un área improductiva?
HABO

Respuestas:


172

Cambie el número 6 a la longitud total que necesite:

SELECT REPLICATE('0',6-LEN(EmployeeId)) + EmployeeId

Si la columna es INT, puede usar RTRIM para convertirla implícitamente en VARCHAR

SELECT REPLICATE('0',6-LEN(RTRIM(EmployeeId))) + RTRIM(EmployeeId)

Y el código para eliminar estos 0 y recuperar el número 'real':

SELECT RIGHT(EmployeeId,(LEN(EmployeeId) - PATINDEX('%[^0]%',EmployeeId)) + 1)

1
+1 ¡Incluso me enseñaste a eliminar los 0! Déjame probar esto y lo marcaré como una respuesta.
jp2code

no necesita código para eliminar los ceros, simplemente asigne o convierta a un int y se eliminarán automáticamente.
Jimbo

2
Esto solo funciona si el valor pasado es una cadena, si pasa un número entero, obtiene el mismo valor que pasó.
Mordy

2
Aunque es antiguo ... usar "+ convert (varchar, EmployeeID)" en lugar de "+ EmployeeID" debería resolver el problema de int
Krishna Sarma

3
es una buena manera a menos que el EmployeeId sea mayor de 6 dígitos, lo que genera un resultado NULL. La función de contacto es la respuesta: SELECT CONCAT (REPLICATE ('0', 6-LEN (CONVERT (varchar, EmployeeId))), EmployeeId)
Mahmoud Moravej

125

Simplemente use la función FORMAT (funciona en SQL Server 2012 o más reciente):

SELECT FORMAT(EmployeeID, '000000')
FROM dbo.RequestItems
WHERE ID=0 

Referencia: http://msdn.microsoft.com/en-us/library/hh213505.aspx


1
Esta es una vieja pregunta, antes de que saliera SQL Server 2012.
jp2code

19
Aún así, me gustaría ver esta burbuja un poco más cerca de la parte superior ahora.
Dave Haynes

4
Por si acaso alguien se lo pregunta. Formatno conserva el tipo de datos, pero lo convierte implícitamente a nvarchar:select sql_variant_property(50, 'BaseType'), sql_variant_property(format(50, N'00000'), 'BaseType')
Ralph

2
De esta manera es la mejor solución y en mi humilde opinión.
Robert Lujo

Tenga en cuenta esta función si la está utilizando para un conjunto de datos grande
amd

33

Puede cambiar su procedimiento de esta manera

SELECT Right('000000' + CONVERT(NVARCHAR, EmployeeID), 6) AS EmpIDText, 
       EmployeeID
FROM dbo.RequestItems 
WHERE ID=0 

Sin embargo, esto supone que su EmployeeIDes un valor numérico y este código cambia el resultado a una cadena, sugiero agregar nuevamente el valor numérico original

EDITAR Por supuesto que no he leído detenidamente la pregunta anterior. Dice que el campo es un char(6)EmployeeID no es un valor numérico. Si bien esta respuesta todavía tiene un valor per se, no es la respuesta correcta a la pregunta anterior.


Creo que esta es la forma más limpia de hacerlo. Gracias
iheartcsharp

¿Es eso '000000'realmente necesario ...? '0'también funciona bien. ¿Es seguro usar solo un 0 ..?
shashwat

1
El OP solicitó una cadena de 6 caracteres de longitud como resultado. Específicamente, si EmployeeID es 7135, esta consulta debería devolver 007135 . Usar solo un '0' devuelve 07135no 007135. La idea es concatenar a una cadena de 06 caracteres compuesta por toda la cadena convertida EmployeedID, luego EMPEZANDO desde el borde derecho tomar 6 caracteres. Cualquiera que sea la longitud de la ID, el método anterior siempre devuelve una cadena con solo el número de caracteres cero necesarios para alcanzar la longitud de 6 caracteres
Steve

Podría ser 5 ceros '00000'ya EmployeeIDque contendrá al menos un dígito. Pero la REPLICATE()función parece más adecuada, como en las otras respuestas
nosklo

26

Odiaba tener que CONVERTIR el int, y esto parece mucho más simple. Incluso podría funcionar mejor, ya que solo hay una conversión de cadena y una simple adición.

seleccione DERECHA (1000000 + EmployeeId, 6) ...

Solo asegúrese de que "1000000" tenga al menos tantos ceros como el tamaño necesario.


11

Estoy publicando todo en un solo lugar, todo funciona para rellenar con 4 cero a la izquierda :)

declare @number int =  1;
print right('0000' + cast(@number as varchar(4)) , 4)
print right('0000' + convert(varchar(4), @number) , 4)
print right(replicate('0',4) + convert(varchar(4), @number) , 4)
print  cast(replace(str(@number,4),' ','0')as char(4))
print format(@number,'0000')

Esto cubre todas las opciones necesarias. Gracias.
Kyurthich

6

De otra forma, solo para completar.

DECLARE @empNumber INT = 7123
SELECT STUFF('000000', 6-LEN(@empNumber)+1, LEN(@empNumber), @empNumber)

O, según su consulta

SELECT STUFF('000000', 6-LEN(EmployeeID)+1, LEN(EmployeeID), EmployeeID) 
         AS EmployeeCode
FROM dbo.RequestItems
WHERE ID=0

@ jp2code: necesita leer sobre lo que es StackOverflow; se edita de manera colaborativa como un wiki; ¡no es su pregunta tan pronto como lo haya publicado! Las cosas que comúnmente se eliminan son "tonterías" excesivas, como agradecer de antemano y una gramática / mayúscula deficiente.
Jamiec

5

A partir de la versión 2012, puede utilizar

SELECT FORMAT(EmployeeID,'000000')
FROM dbo.RequestItems
WHERE ID=0

4

Tan limpio como podría ser y dar margen de reemplazo con variables:

Select RIGHT(REPLICATE('0',6) + EmployeeID, 6) from dbo.RequestItems
WHERE ID=0

Si la EmployeeIDcolumna se define como int, el operador + se tratará como una suma en lugar de una concatenación, por lo que los ceros se perderán. El uso convertevitará este problema.

Llamar a REPLICATE ('0', 6) para evitar escribir '000000' es un desperdicio ;-)
Mladen Mihajlovic

3
SELECT replicate('0', 6 - len(employeeID)) + convert(varchar, employeeID) as employeeID
FROM dbo.RequestItems 
WHERE ID=0

2
SELECT 
    cast(replace(str(EmployeeID,6),' ','0')as char(6)) 
FROM dbo.RequestItems
WHERE ID=0

¡Ups! En realidad, esto me dio 7135.0cuando lo di 7135.
jp2code

1

La solución funciona para números con signo / negativo con ceros a la izquierda, para todas las versiones de Sql:

DECLARE
    @n money = -3,
    @length tinyint = 15,
    @decimals tinyint = 0

SELECT REPLICATE('-', CHARINDEX('-', @n, 1)) + REPLACE(REPLACE(str(@n, @length, @decimals), '-', ''), ' ', '0')

1

Lo más simple es siempre lo mejor:

Select EmployeeID*1 as EmployeeID 

-1

En mi versión de SQL no puedo usar REPLICATE. Entonces hice esto:

SELECT 
    CONCAT(REPEAT('0', 6-LENGTH(emplyeeID)), emplyeeID) AS emplyeeID 
FROM 
    dbo.RequestItems`
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.