string_split separar por name invalid into delimitada comas columns cadena sql postgresql split natural-sort

separar - sql server split string into columns



Sustituyendo valor en campo vacío después de usar split_part (3)

Tengo dos columnas, id integer y version text . Estoy tratando de convertir las cadenas en la version en enteros para que pueda seleccionar la versión máxima (más reciente) de la identificación.

Sin embargo, la primera instancia del id almacena como la version . Ejemplo:

id | version ---+-------- 10 | ''10''

Opuesto a:

id | version ---+-------- 10 | ''10-0''

Las filas adicionales siguen la identificación de la convención: 10, versión: 10-1. Etc.

¿Cómo puedo lograr esto? He intentado split_part() y hechizo como int . Sin embargo, split_part(version, "-", 2) devolverá lo que parece una cadena vacía. He intentado ejecutar esto utilizando un COALESCE(splitpart..., ''0'') en vano ya que intentó leer el campo vacío devuelto por el índice de campo 2.


Para evitar las cadenas de versión que no tienen guión, puede usar una expresión CASE :

CASE WHEN version LIKE ''%-%'' THEN SPLIT_PART(version, ''-'', 2)::int ELSE 0 END

La idea básica es usar el número de versión, convertir a un int, cuando un guión está presente, pero de lo contrario asumir que la versión es cero si el guión está ausente.

Con este obstáculo fuera del camino, su consulta ahora solo se reduce a una consulta ROW_NUMBER() . Aquí, la partición es la id , y el orden se da usando la expresión CASE anterior para la versión.

SELECT t.id, t.version FROM ( SELECT id, CASE WHEN version LIKE ''%-%'' THEN version ELSE version || ''-0'' END AS version, ROW_NUMBER() OVER (PARTITION BY id ORDER BY CASE WHEN version LIKE ''%-%'' THEN SPLIT_PART(version, ''-'', 2)::int ELSE 0 END DESC) rn FROM yourTable ) t WHERE t.rn = 1 ORDER BY t.id;

Demostración aquí:

Rextester


Use la combinación de coalesce () y nullif (), ejemplo:

with my_table(version) as ( values (''10''), (''10-1''), (''10-2'') ) select version, split_part(version, ''-'', 1)::int as major, coalesce(nullif(split_part(version, ''-'', 2), ''''), ''0'')::int as minor from my_table version | major | minor ---------+-------+------- 10 | 10 | 0 10-1 | 10 | 1 10-2 | 10 | 2 (3 rows)


split_part() devuelve la cadena vacía ( '''' ) - no NULL - cuando la parte a devolver está vacía o no existe. Es por eso que COALESCE no hace nada aquí. Y la cadena vacía ( '''' ) no tiene representación como valor integer , por lo tanto, arroja un error cuando intenta lanzarlo.

La forma más corta en este ejemplo debe ser GREATEST(split_part( ... ) , ''0'') antes de la conversión, ya que la cadena vacía se ordena antes que cualquier otra cadena no vacía o incluso NULL (en cualquier configuración regional). Luego use DISTINCT ON () para obtener la fila con la version "más grande" para cada id .

Configuración de prueba

CREATE TABLE tbl ( id integer NOT NULL , version text NOT NULL ); INSERT INTO tbl VALUES (10, ''10-2'') , (10, ''10-1'') , (10, ''10'') -- missing subversion , (10, ''10-111'') -- multi-digit number , (11, ''11-1'') , (11, ''11-0'') -- proper ''0'' , (11, ''11-'') -- missing subversion but trailing ''-'' , (11, ''11-2'');

Soluciones

SELECT DISTINCT ON (id) * FROM tbl ORDER BY id, GREATEST(split_part(version, ''-'', 2), ''0'')::int DESC;

Resultado:

id | version ----+--------- 10 | 10-111 11 | 10-2

O también puede usar NULLIF y usar NULLS LAST (en orden descendente) para ordenar:

SELECT DISTINCT ON (id) * FROM tbl ORDER BY id, NULLIF(split_part(version, ''-'', 2), '''')::int DESC NULLS LAST;

Mismo resultado.

O una declaración CASE más explícita:

CASE WHEN split_part(version, ''-'', 2) = '''' THEN ''0'' ELSE split_part(version, ''-'', 2) END

dbfiddle aquí

Relacionado: