Soy un principiante en T-SQL. Quiero decidir si una cadena de entrada es un palíndromo, con salida = 0 si no lo es y salida = 1 si lo es. Todavía estoy descubriendo la sintaxis. Ni siquiera estoy recibiendo un mensaje de error. Estoy buscando diferentes soluciones y algunos comentarios, para obtener una mejor comprensión y conocimiento de cómo funciona T-SQL, para mejorar en eso. Todavía soy un estudiante.
La idea clave, tal como la veo, es comparar los caracteres más a la izquierda y a la derecha entre sí, verificar la igualdad, luego comparar el segundo carácter de la izquierda con el segundo-del último, etc. Hacemos un bucle: si los personajes son iguales entre sí, continuamos. Si llegamos al final, sacamos 1, si no, sacamos 0.
¿Podría por favor criticar:
CREATE function Palindrome(
@String Char
, @StringLength Int
, @n Int
, @Palindrome BIN
, @StringLeftLength Int
)
RETURNS Binary
AS
BEGIN
SET @ n=1
SET @StringLength= Len(String)
WHILE @StringLength - @n >1
IF
Left(String,@n)=Right(String, @StringLength)
SET @n =n+1
SET @StringLength =StringLength -1
RETURN @Binary =1
ELSE RETURN @Palindrome =0
END
Creo que estoy en el camino correcto, pero todavía estoy muy lejos. ¿Algunas ideas?
LTRIM(RTRIM(...))
espacio en blanco?Respuestas:
Si está utilizando SQL Server, ¿puede usar la función REVERSE () para verificar?
Incluyendo el comentario de Martin Smith, si está en SQL Server 2012+ puede usar la función IIF () :
fuente
Como hay una buena cantidad de soluciones, voy a ir con la parte de "crítica" de su pregunta. Un par de notas: he corregido algunos errores tipográficos y anotado dónde lo hice. Si me equivoco acerca de que sean un error tipográfico, menciónelo en los comentarios y explicaré lo que está sucediendo. Voy a señalar varias cosas que quizás ya sepas, así que no te ofendas si lo supiera. Algunos comentarios pueden parecer exigentes, pero no sé dónde se encuentra en su viaje, así que debo asumir que recién está comenzando.
SIEMPRE incluya la longitud con una
char
ovarchar
definición. Aaron Bertrand habla en profundidad aquí . Él está hablandovarchar
pero lo mismo ocurrechar
. Usaría unvarchar(255)
para esto si solo desea cadenas relativamente cortas o tal vez unvarchar(8000)
para las más grandes o inclusovarchar(max)
.Varchar
es para cadenas de longitud variablechar
es solo para fijas. Dado que no está seguro de la longitud de la cadena que se pasa en usovarchar
. También esbinary
nobin
.A continuación, no necesita poner todas esas variables como parámetros. Declararlos dentro de su código. Solo ponga algo en la lista de parámetros si planea pasarlo dentro o fuera. (Verá cómo se ve esto al final). También tiene @StringLeftLength pero nunca lo usa. Entonces no lo voy a declarar.
Lo siguiente que voy a hacer es volver a formatear un poco para que algunas cosas sean obvias.
Si observa la forma en que hice la sangría, notará que tengo esto:
Esto se debe a que los comandos como
WHILE
yIF
solo afectan la primera línea de código después de ellos. Tienes que usar unBEGIN .. END
bloque si quieres múltiples comandos. Entonces arreglando eso obtenemos:Notarás que solo agregué un
BEGIN .. END
bloque en elIF
. Esto se debe a que aunque laIF
declaración tiene varias líneas de largo (e incluso contiene múltiples comandos), sigue siendo una sola declaración (que cubre todo lo realizado en elIF
y elELSE
partes de la declaración).A continuación, recibirá un error después de ambos
RETURNs
. Puede devolver una variable O un literal. No puede establecer la variable y devolverla al mismo tiempo.Ahora estamos en la lógica. Primero permítanme señalar que las funciones
LEFT
yRIGHT
que está utilizando son excelentes, pero le darán la cantidad de caracteres que pasa desde la dirección solicitada. Digamos que aprobaste la palabra "prueba". En la primera pasada obtendrá esto (eliminando variables):Obviamente eso no es lo que esperabas. Realmente querrás usar
substring
en su lugar. La subcadena le permite pasar no solo el punto de partida sino también la longitud. Entonces obtendrías:A continuación, está incrementando las variables que usa en su ciclo solo en una condición de la instrucción IF. Extraiga la variable incremental de esa estructura por completo. Eso requerirá un
BEGIN .. END
bloqueo adicional , pero puedo eliminar el otro.Necesita cambiar su
WHILE
condición para permitir la última prueba.Y por último, pero no menos importante, tal como está ahora, no probamos el último carácter si hay un número impar de caracteres. Por ejemplo con 'ana' el
n
no se prueba. Eso está bien, pero me hace falta que tengamos en cuenta una palabra de una sola letra (si quieres que cuente como algo positivo). Entonces podemos hacerlo estableciendo el valor por adelantado.Y ahora finalmente tenemos:
Un ultimo comentario. Soy un gran fanático del formato en general. Realmente puede ayudarlo a ver cómo funciona su código y ayudarlo a señalar posibles errores.
Editar
Como mencionó Sphinxxx, todavía tenemos una falla en nuestra lógica. Una vez que tocamos
ELSE
y establecemos@Palindrome
en 0, no tiene sentido continuar. De hecho, en ese momento podríamos simplementeRETURN
.Dado que ahora solo estamos usando
@Palindrome
para "todavía es posible que esto sea un palíndromo", realmente no tiene sentido tenerlo. Podemos deshacernos de la variable y cambiar nuestra lógica a cortocircuito en caso de falla (laRETURN 0
) yRETURN 1
(una respuesta positiva) solo si logra pasar por todo el bucle. Notarás que esto realmente simplifica un poco nuestra lógica.fuente
También podría usar un enfoque de tabla de números.
Si aún no tiene una tabla de números auxiliares, puede crear una de la siguiente manera. Esto se completa con un millón de filas y, por lo tanto, será bueno para longitudes de cadena de hasta 2 millones de caracteres.
A continuación, se compara cada carácter de la izquierda con su correspondiente compañero a la derecha, y si se encuentra alguna discrepancia puede provocar un cortocircuito y devolver 0. Si la cadena tiene una longitud impar, el carácter del medio no se verifica, ya que esto no alterará el resultado .
Si no está seguro de cómo funciona, puede ver a continuación
Este es básicamente el mismo algoritmo que se describe en la pregunta, pero se realiza de una manera basada en un conjunto en lugar de un código de procedimiento iterativo.
fuente
El
REVERSE()
método "mejoró", es decir, invirtió solo la mitad de la cadena:No espero que suceda nada extraño si la cadena tiene un número impar de caracteres; el carácter del medio no tiene que ser verificado.
@Hvd hizo una observación de que esto podría no manejar pares sustitutos correctamente en todas las intercalaciones.
@srutzky comentó que maneja los caracteres suplementarios / pares sustitutos de la misma manera que el
REVERSE()
método, en el sentido de que solo funcionan correctamente cuando termina la clasificación predeterminada de la base de datos actual_SC
.fuente
Sin usar
REVERSE
, que es lo que viene inmediatamente a la mente, pero aún usando una función 1 ; Construiría algo como lo siguiente.Esta parte simplemente eliminó la función existente, si ya existe:
Esta es la función misma:
Aquí, probamos la función:
Esto compara la primera mitad de la palabra con el reverso de la última mitad de la palabra (sin usar la
REVERSE
función). Este código maneja correctamente las palabras de longitud par e impar. En lugar de recorrer toda la palabra, simplemente obtenemos laLEFT
primera mitad de la palabra, luego recorremos la última mitad de la palabra para obtener la parte invertida de la mitad derecha. Si la palabra tiene una longitud impar, omitimos la letra del medio, ya que, por definición, será la misma para ambas "mitades".1 - ¡las funciones pueden ser muy lentas!
fuente
Sin usar REVERSE ... Siempre es divertido usar una solución recursiva;) (hice la mía en SQL Server 2012, las versiones anteriores pueden tener limitaciones en la recursividad)
fuente
Esta es una versión en línea compatible con TVF de la solución basada en sets de Martin Smith , decorada adicionalmente con un par de mejoras superfluas:
fuente
Solo por diversión, aquí hay una función definida por el usuario escalar de SQL Server 2016 con la función OLTP en memoria:
fuente
Un problema importante con el que se encontrará es que con cualquier valor mayor que 1,
LEFT
oRIGHT
devolverá varios caracteres, no el carácter en esa posición. Si quisieras seguir con este método de prueba, una forma muy simple de modificarlo seríaEsto siempre tomará el carácter más a la derecha de la cadena izquierda y el carácter más a la izquierda de la cadena derecha.
Sin embargo, quizás una forma menos indirecta de verificar esto sería usar
SUBSTRING
:Tenga en cuenta que
SUBSTRING
está indexado en 1, de ahí el+ 1
in((LEN(String) - @n) + 1)
.fuente