Jestem początkującym w języku T-SQL. Chcę zdecydować, czy ciąg wejściowy jest palindromem, z wynikiem = 0, jeśli nie jest, a wyjście = 1, jeśli tak jest. Nadal zastanawiam się nad składnią. Nie dostaję nawet komunikatu o błędzie. Szukam różnych rozwiązań i informacji zwrotnych, aby lepiej zrozumieć i zrozumieć działanie T-SQL, aby stać się lepszym - wciąż jestem studentem.
Według mnie kluczową ideą jest porównanie między sobą lewej i prawej strony, sprawdzenie równości, a następnie porównanie drugiego znaku od lewej z drugim od ostatniego itd. Robimy pętlę: jeśli znaki są sobie równe, kontynuujemy. Jeśli osiągnęliśmy koniec, wyprowadzamy 1, jeśli nie, wyprowadzamy 0.
Czy mógłbyś zadowolić krytykę:
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
Myślę, że jestem na dobrej drodze, ale wciąż jestem daleko. Jakieś pomysły?
LTRIM(RTRIM(...))
Biała przestrzeń?Odpowiedzi:
Jeśli używasz programu SQL Server, możesz użyć funkcji REVERSE () do sprawdzenia?
Łącznie z komentarzem Martina Smitha, jeśli korzystasz z SQL Server 2012+, możesz użyć funkcji IIF () :
źródło
Ponieważ istnieje spora liczba rozwiązań, przejdę do części „krytyki” twojego pytania. Kilka uwag: Naprawiłem kilka literówek i zauważyłem, gdzie to zrobiłem. Jeśli się mylę, że są literówką, wspomnij o tym w komentarzach, a wyjaśnię, co się dzieje. Mam zamiar wskazać kilka rzeczy, które być może już wiesz, więc proszę, nie obrażaj się, jeśli to zrobię. Niektóre komentarze mogą wydawać się wybredne, ale nie wiem, gdzie jesteś w podróży, więc musisz założyć, że dopiero zaczynasz.
ZAWSZE uwzględniaj długość z definicją
char
lubvarchar
. Aaron Bertrand mówi tutaj dogłębnie . Mówi,varchar
ale to samo dotyczychar
. Użyłbymvarchar(255)
do tego, jeśli chcesz tylko stosunkowo krótkich łańcuchów, a możevarchar(8000)
dla większych, a nawetvarchar(max)
.Varchar
jest dla ciągów o zmiennej długościchar
jest tylko dla stałych. Ponieważ nie jesteś pewien długości przekazywanego ciągu w użyciuvarchar
. Także tobinary
niebin
.Następnie nie musisz umieszczać wszystkich tych zmiennych jako parametrów. Zadeklaruj je w swoim kodzie. Umieść coś na liście parametrów tylko, jeśli planujesz przekazać lub wyrzucić. (Zobaczysz, jak to wygląda na końcu.) Również masz @StringLeftLength, ale nigdy go nie używaj. Więc nie zamierzam tego deklarować.
Następną rzeczą, którą zamierzam zrobić, jest ponowne sformatowanie, aby kilka rzeczy było oczywistych.
Jeśli spojrzysz na sposób, w jaki zrobiłem wcięcie, zauważysz, że mam to:
Jest tak, ponieważ polecenia takie jak
WHILE
iIF
wpływają tylko na pierwszy wiersz kodu po nich. Musisz użyćBEGIN .. END
bloku, jeśli chcesz mieć wiele poleceń. Naprawiając to, otrzymujemy:Zauważysz, że dodałem tylko
BEGIN .. END
blok wIF
. To dlatego, mimo żeIF
oświadczenie jest wiele linii długo (a nawet zawiera wiele poleceń) jest jeszcze jedno sprawozdanie (obejmujące wszystko wykonywane wIF
aELSE
częściami rachunku).Następnie pojawi się błąd po obu
RETURNs
. Możesz zwrócić zmienną LUB literał. Nie można ustawić zmiennej i zwrócić jej jednocześnie.Teraz jesteśmy w logice. Po pierwsze, pozwól mi zaznaczyć, że funkcje
LEFT
iRIGHT
, których używasz, są świetne, ale podadzą ci liczbę znaków przekazywanych z żądanego kierunku. Powiedzmy, że zdałeś słowo „test”. Przy pierwszym przejściu dostaniesz to (usuwanie zmiennych):Oczywiście nie tego się spodziewałeś. Naprawdę chcesz użyć
substring
zamiast tego. Podciąg pozwala przekazać nie tylko punkt początkowy, ale także długość. Otrzymasz więc:Następnie zwiększasz zmienne używane w pętli tylko w jednym warunku instrukcji IF. Całkowicie wyciągnij zmienną inkrementację z tej struktury. Będzie to wymagało dodatkowego
BEGIN .. END
bloku, ale mogę usunąć drugi.Musisz zmienić swój
WHILE
stan, aby umożliwić ostatni test.I na koniec, tak jak teraz, nie testujemy ostatniego znaku, jeśli liczba znaków jest nieparzysta. Na przykład z „ana”
n
nie jest testowany. W porządku, ale to do mnie należy, że musimy uwzględnić jedno literowe słowo (jeśli chcesz, aby było liczone jako pozytywne). Możemy to zrobić, ustawiając wartość z góry.A teraz w końcu mamy:
Ostatni komentarz. Ogólnie jestem wielkim fanem formatowania. To naprawdę może ci pomóc zobaczyć, jak działa twój kod i pomóc wskazać możliwe błędy.
Edytować
Jak wspomniał Sphinxxx, nadal mamy wadę w naszej logice. Po trafieniu
ELSE
i ustawieniu@Palindrome
na 0 nie ma sensu kontynuować. W tym momencie moglibyśmy właśnieRETURN
.Biorąc pod uwagę, że teraz używamy tylko
@Palindrome
do „wciąż jest to palindrom”, naprawdę nie ma sensu go mieć. Możemy pozbyć się zmiennej i przełączyć naszą logikę na zwarcie w przypadku awarii (RETURN 0
) iRETURN 1
(reakcja pozytywna) tylko wtedy, gdy przejdzie ona przez całą pętlę. Zauważysz, że to faktycznie nieco upraszcza naszą logikę.źródło
Możesz także użyć podejścia do tabeli liczb.
Jeśli nie masz jeszcze tabeli numerów pomocniczych, możesz ją utworzyć w następujący sposób. Jest wypełniony milionem wierszy, więc będzie dobry dla ciągów o długości do 2 milionów znaków.
Poniżej porównuje każdy znak po lewej stronie z odpowiadającym mu partnerem po prawej stronie, a jeśli zostaną znalezione jakiekolwiek rozbieżności, może dojść do zwarcia i zwrócenia 0. Jeśli łańcuch ma dziwną długość, środkowy znak nie jest sprawdzany, ponieważ nie zmieni to wyniku .
Jeśli nie masz pewności, jak to działa, możesz zobaczyć poniżej
Jest to w zasadzie ten sam algorytm, jaki opisano w pytaniu, ale jest wykonywany w oparciu o zestaw, a nie iteracyjny kod proceduralny.
źródło
REVERSE()
Metoda „ulepszone”, czyli cofania tylko połowa napisu:Nie oczekuję, że wydarzy się coś dziwnego, jeśli łańcuch będzie miał nieparzystą liczbę znaków; środkowy znak nie musi być sprawdzany.
@Hvd podniósł uwagę, że może to nie obsługiwać poprawnie par zastępczych we wszystkich zestawieniach.
@srutzky skomentował, że obsługuje pary znaków uzupełniających / zastępczych w taki sam sposób jak
REVERSE()
metodę, ponieważ działają one tylko, gdy kończy się domyślne sortowanie bieżącej bazy danych_SC
.źródło
Bez użycia
REVERSE
, co natychmiast przychodzi na myśl, ale nadal z wykorzystaniem funkcji 1 ; Skonstruowałbym coś takiego.Ta część po prostu usunęła istniejącą funkcję, jeśli już istnieje:
To jest sama funkcja:
Tutaj testujemy funkcję:
Porównuje to pierwszą połowę słowa z odwrotnością ostatniej połowy słowa (bez użycia
REVERSE
funkcji). Ten kod poprawnie obsługuje słowa nieparzyste i parzyste. Zamiast zapętlać całe słowo, po prostu otrzymujemyLEFT
pierwszą część słowa, a następnie zapętlamy ostatnią połowę słowa, aby uzyskać odwróconą część prawej połowy. Jeśli słowo ma nieparzystą długość, pomijamy środkową literę, ponieważ z definicji będzie taka sama dla obu „połówek”.1 - funkcje mogą być bardzo wolne!
źródło
Bez użycia REVERSE ... Zawsze fajnie jest korzystać z rozwiązania rekurencyjnego;) (zrobiłem mój w SQL Server 2012, wcześniejsze wersje mogły mieć ograniczenia rekurencji)
źródło
Jest to wbudowana, przyjazna dla TVF wersja rozwiązania Martina Smitha oparta na zestawie , dodatkowo ozdobiona kilkoma zbędnymi ulepszeniami:
źródło
Dla zabawy, oto skalarna funkcja SQL Server 2016 zdefiniowana przez użytkownika z funkcją OLTP w pamięci:
źródło
Głównym problemem, na który natkniesz się, jest to, że o dowolnej wartości większej niż 1,
LEFT
lubRIGHT
zwróci wiele znaków, a nie znak w tej pozycji. Jeśli chcesz pozostać przy tej metodzie testu, to naprawdę prosty sposób na jej zmodyfikowanieSpowoduje to zawsze złapanie znaku znajdującego się najbardziej na prawo od lewego ciągu i znaku znajdującego się najbardziej na lewo od prawego ciągu.
Być może jednak mniej okrągłym sposobem na sprawdzenie tego byłoby użycie
SUBSTRING
:Zauważ, że
SUBSTRING
jest indeksowany 1, stąd+ 1
in((LEN(String) - @n) + 1)
.źródło