subconsultas - taller sql
Determinar si el código postal solo contiene números (9)
Tengo un campo llamado zip, escriba char (5), que contiene códigos postales como
12345
54321
ABCDE
Me gustaría verificar con una declaración SQL si un código postal contiene solo números.
Lo siguiente no funciona
SELECT * FROM S1234.PERSON
WHERE ZIP NOT LIKE ''%''
No puede funcionar porque incluso ''12345'' es una "matriz" de caracteres (es ''%'', ¿verdad?
Descubrí que lo siguiente está funcionando:
SELECT * FROM S1234.PERSON
WHERE ZIP NOT LIKE '' %''
Tiene un espacio antes de%. ¿Por qué está funcionando?
Supongamos que su código postal es un código postal de EE. UU., Compuesto por 5 números.
db2 "with val as (
select *
from S1234.PERSON t
where xmlcast(xmlquery(''fn:matches(/$ZIP,''''^/d{5}$'''')'') as integer) = 1
)
select * from val"
Para obtener más información acerca de xQuery: fn: matches: http://pic.dhe.ibm.com/infocenter/db2luw/v10r5/topic/com.ibm.db2.luw.xml.doc/doc/xqrfnmat.html
USE la función ISNUMERIC; ISUMERIC devuelve 1 si el parámetro contiene solo números y cero si no
EJEMPLO: SELECCIONE * DE S1234.PERSON DONDE ISNUMERIC (ZIP) = 1
Su extracto no valida los números, pero dice obtener todo lo que no comienza con un espacio.
Usa expresiones regulares
SELECT * FROM S1234.PERSON
WHERE ZIP REGEXP ''/d+''
mySql no tiene una función isNumberic () nativa. Esto sería bastante directo en Excel con la función ISNUMBER (), o en T-SQL con ISNUMERIC (), pero tampoco funciona en MySQL, así que después de buscar un poco encontré esta solución ...
SELECT * FROM S1234.PERSON
WHERE ZIP REGEXP (''[0-9]'')
Efectivamente estamos procesando una expresión regular en el contenido del campo ''ZIP'', puede parecer como usar un mazo para romper una nuez y no tengo idea de cómo el rendimiento sería diferente de un enfoque más simple, pero funcionó y supongo ese es el punto.
Intente verificar si hay una diferencia entre minúsculas y mayúsculas. Los números y los caracteres especiales tendrán el mismo aspecto:
SELECT *
FROM S1234.PERSON
WHERE UPPER(ZIP COLLATE Latin1_General_CS_AI ) = LOWER(ZIP COLLATE Latin1_General_CS_AI)
He creado una versión más propensa a errores basada en la solución https://.com/a/36211270/565525 , resultado intermedio agregado, algunos ejemplos:
select
test_str
, TRIM(TRANSLATE(replace(trim(test_str), '' '', ''x''), ''yyyyyyyyyyy'', ''0123456789''))
, case when length(TRIM(TRANSLATE(replace(trim(test_str), '' '', ''x''), ''yyyyyyyyyyy'', ''0123456789'')))=5 then ''5-digit-zip'' else ''not 5d-zip'' end is_zip
from (VALUES
('' 123 '' )
,('' abc '' )
,('' a12 '' )
,('' 12 3 '')
,('' 99435 '')
,(''99323'' )
) AS X(test_str)
;
El resultado para este conjunto de ejemplos es:
TEST_STR 2 IS_ZIP
-------- -------- -----------
123 yyy not 5d-zip
abc abc not 5d-zip
a12 ayy not 5d-zip
12 3 yyxy not 5d-zip
99435 yyyyy 5-digit-zip
99323 yyyyy 5-digit-zip
Usando la respuesta de aquí para verificar si todos son dígitos
SELECT col1,col2
FROM
(
SELECT col1,col2,
CASE
WHEN LENGTH(RTRIM(TRANSLATE(ZIP , ''*'', '' 0123456789''))) = 0
THEN 0 ELSE 1
END as IsAllDigit
FROM S1234.PERSON
) AS Z
WHERE IsAllDigit=0
DB2 no tiene una función de expresión regular como MySQL REGEXP
Aquí hay un ejemplo de trabajo para el caso en el que desee verificar los códigos postales en un rango. Puede usar este código como inspiración para hacer una simple verificación de código postal simple, si lo desea:
if local_test_environment?
# SQLite supports GLOB which is similar to LIKE (which it only has limited support for), for matching in strings.
where("(zip_code NOT GLOB ''*[^0-9]*'' AND zip_code <> '''') AND (CAST(zip_code AS int) >= :range_start AND CAST(zip_code AS int) <= :range_finish)", range_start: range_start, range_finish: range_finish)
else
# SQLServer supports LIKE with more advanced matching in strings than what SQLite supports.
# SQLServer supports TRY_PARSE which is non-standard SQL, but fixes the error SQLServer gives with CAST, namely: Conversion failed when converting the nvarchar value ''US-19803'' to data type int.
where("(zip_code NOT LIKE ''%[^0-9]%'' AND zip_code <> '''') AND (TRY_PARSE(zip_code AS int) >= :range_start AND TRY_PARSE(zip_code AS int) <= :range_finish)", range_start: range_start, range_finish: range_finish)
end
Si usa SQL Server 2012 o superior, la siguiente secuencia de comandos debería funcionar.
DECLARE @t TABLE (Zip VARCHAR(10))
INSERT INTO @t VALUES (''12345'')
INSERT INTO @t VALUES (''54321'')
INSERT INTO @t VALUES (''ABCDE'')
SELECT *
FROM @t AS t
WHERE TRY_CAST(Zip AS NUMERIC) IS NOT NULL