Я новичок в T-SQL. Я хочу решить, является ли входная строка палиндромом, с output = 0, если это не так, и output = 1, если это так. Я все еще выясняю синтаксис. Я даже не получаю сообщение об ошибке. Я ищу различные решения и отзывы, чтобы лучше понять и понять, как работает T-SQL, чтобы стать лучше - я еще студент.
Ключевая идея, на мой взгляд, состоит в том, чтобы сравнивать левый и правый символы друг с другом, проверять равенство, затем сравнивать второй символ слева со вторым из последнего и т. Д. Делаем цикл: если символы равны друг другу, мы продолжаем. Если мы достигли конца, мы выводим 1, если нет - выводим 0.
Не могли бы вы критиковать:
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
Я думаю, что я на правильном пути, но мне еще далеко. Любые идеи?
LTRIM(RTRIM(...))
пробельные?Ответы:
Если вы используете SQL Server, вы можете использовать функцию REVERSE () для проверки?
Включая комментарий Мартина Смита, если вы используете SQL Server 2012+, вы можете использовать функцию IIF () :
источник
Поскольку существует немало решений, я собираюсь остановиться на «критической» части вашего вопроса. Несколько замечаний: я исправил некоторые опечатки и отметил, где я сделал. Если я ошибаюсь из-за того, что они опечатки, упомяните об этом в комментариях, и я объясню, что происходит. Я собираюсь указать на несколько вещей, которые вы, возможно, уже знаете, поэтому, пожалуйста, не обижайтесь, если я это сделал. Некоторые комментарии могут показаться придирчивыми, но я не знаю, где вы находитесь в вашем путешествии, поэтому я должен предположить, что вы только начинаете.
ВСЕГДА указывайте длину с определением
char
илиvarchar
. Аарон Бертран подробно рассказывает здесь . Он говорит о,varchar
но то же самое касаетсяchar
. Я бы использовалvarchar(255)
для этого, если вы хотите только относительно короткие строки или, возможно,varchar(8000)
для более крупных или дажеvarchar(max)
.Varchar
для строк переменной длиныchar
- только для фиксированных. Поскольку вы не уверены в длине строки, передаваемой в использованиеvarchar
. И этоbinary
не такbin
.Далее вам не нужно помещать все эти переменные в качестве параметров. Объявите их в своем коде. Поместите что-либо в список параметров только в том случае, если вы планируете передавать его или нет. (Вы увидите, как это выглядит в конце.) Также у вас есть @StringLeftLength, но вы никогда его не используете. Так что я не собираюсь это объявлять.
Следующее, что я собираюсь сделать, это немного переформатировать, чтобы сделать несколько вещей очевидными.
Если вы посмотрите, как я сделал отступ, то заметите, что у меня есть это:
Это потому, что команды любят
WHILE
иIF
влияют только на первую строку кода после них. Вы должны использоватьBEGIN .. END
блок, если вы хотите несколько команд. Так что исправим, что получим:Вы заметите, что я только добавил
BEGIN .. END
блок вIF
. Это связано с тем, что, хотяIF
оператор состоит из нескольких строк (и даже содержит несколько команд), он по-прежнему является одним оператором (охватывающим все, что выполняется в оператореIF
и егоELSE
частях).Далее вы получите ошибку после обоих ваших
RETURNs
. Вы можете вернуть переменную ИЛИ литерал. Вы не можете установить переменную и вернуть ее одновременно.Теперь мы в логике. Прежде всего позвольте мне отметить, что
LEFT
иRIGHT
функции , которые вы используете большие, но они собираются дать вам количество символов , которые проходят в от запрошенной направлении. Допустим, вы прошли слово «тест». На первом проходе вы получите это (удаление переменных):Очевидно, это не то, что вы ожидали. Вы бы действительно хотели использовать
substring
вместо этого. Подстрока позволяет передавать не только начальную точку, но и длину. Таким образом, вы получите:Затем вы увеличиваете переменные, которые используете в цикле, только в одном условии оператора IF. Вытяните переменную, постепенно увеличивающуюся из этой структуры. Это потребует дополнительного
BEGIN .. END
блока, но я могу удалить другой.Вы должны изменить свое
WHILE
состояние, чтобы учесть последний тест.И последнее по порядку, но не по значению: как сейчас, мы не проверяем последний символ, если есть нечетное количество символов. Например, с «аной»
n
не тестируется. Это нормально, но мне нужно учесть одно буквенное слово (если вы хотите, чтобы оно считалось положительным). Таким образом, мы можем сделать это, установив значение заранее.И теперь мы наконец имеем:
Последний комментарий Я большой поклонник форматирования в целом. Это действительно может помочь вам увидеть, как работает ваш код и указать на возможные ошибки.
редактировать
Как упоминал Sphinxxx, у нас все еще есть недостаток в нашей логике. Как только мы нажмем
ELSE
и установим@Palindrome
в 0, продолжать нет смысла. На самом деле в тот момент мы могли простоRETURN
.Учитывая, что мы сейчас используем только
@Palindrome
для «это все еще возможно, это палиндром», на самом деле нет смысла иметь его. Мы можем избавиться от переменной и переключить нашу логику на короткое замыкание при сбое (RETURN 0
) иRETURN 1
(положительный ответ) только в том случае, если оно проходит весь цикл. Вы заметите, что это несколько упрощает нашу логику.источник
Вы также можете использовать подход таблицы чисел.
Если у вас еще нет таблицы вспомогательных номеров, вы можете создать ее следующим образом. Он заполняется миллионами строк и подходит для строк длиной до 2 миллионов символов.
Ниже приведено сравнение каждого символа слева с соответствующим партнером справа, и при обнаружении любых расхождений можно замкнуть накоротко и вернуть 0. Если строка нечетной длины, средний символ не проверяется, так как это не изменит результат ,
Если вы не уверены, как это работает, вы можете увидеть ниже
По сути, это тот же алгоритм, который описан в вопросе, но он выполняется на основе набора, а не итеративного процедурного кода.
источник
REVERSE()
Метод «улучшенный», то есть задний ход только половина строки:Я не ожидаю ничего странного, если строка содержит нечетное количество символов; средний символ не должен быть проверен.
@Hvd заметил, что это может некорректно обрабатывать суррогатные пары во всех сопоставлениях.
@srutzky прокомментировал, что он обрабатывает дополнительные символы / суррогатные пары таким же образом, как и
REVERSE()
метод, в том смысле , что они работают правильно только тогда, когда заканчивается сопоставление по умолчанию для текущей базы данных_SC
.источник
Без использования
REVERSE
, что сразу приходит на ум, но все еще с помощью функции 1 ; Я бы построил что-то вроде следующего.Эта часть просто удалила существующую функцию, если она уже существует:
Это сама функция:
Здесь мы проверяем функцию:
Это сравнивает первую половину слова с обратной стороной последней половины слова (без использования
REVERSE
функции). Этот код правильно обрабатывает как слова нечетной, так и четной длины. Вместо того, чтобы перебирать все слово, мы просто получаемLEFT
первую половину слова, а затем перебираем последнюю половину слова, чтобы получить перевернутую часть правой половины. Если слово нечетной длины, мы пропускаем среднюю букву, поскольку по определению оно будет одинаковым для обеих «половин».1 - функции могут быть очень медленными!
источник
Без использования REVERSE ... всегда интересно использовать рекурсивное решение;) (я делал это в SQL Server 2012, более ранние версии могли иметь ограничения на рекурсию)
источник
Это встроенная в TVF-версия версия решения Мартина Смита на основе множеств , дополнительно украшенная парой лишних улучшений:
источник
Просто для удовольствия, вот скалярная пользовательская функция SQL Server 2016 с функцией In-Memory OLTP:
источник
Одной из основных проблем вы собираетесь работать , состоит в том , что при любом значении больше 1,
LEFT
илиRIGHT
будет возвращать несколько символов, а не символ в этой позиции. Если вы хотите сохранить этот метод тестирования, очень простой способ изменить егоЭто всегда будет захватывать самый правый символ левой строки и самый левый символ правой строки.
Возможно, менее надежный способ проверить это - использовать
SUBSTRING
:Обратите внимание, что
SUBSTRING
1-индексированный, следовательно,+ 1
в((LEN(String) - @n) + 1)
.источник