Mam następującą tabelę testową w programie SQL Server 2005:
CREATE TABLE [dbo].[TestTable]
(
[ID] [int] NOT NULL,
[TestField] [varchar](100) NOT NULL
)
Wypełniony:
INSERT INTO TestTable (ID, TestField) VALUES (1, 'A value'); -- Len = 7
INSERT INTO TestTable (ID, TestField) VALUES (2, 'Another value '); -- Len = 13 + 6 spaces
Kiedy próbuję znaleźć długość TestField za pomocą funkcji SQL Server LEN (), nie liczy spacji końcowych - np:
-- Note: Also results the grid view of TestField do not show trailing spaces (SQL Server 2005).
SELECT
ID,
TestField,
LEN(TestField) As LenOfTestField, -- Does not include trailing spaces
FROM
TestTable
Jak uwzględnić końcowe spacje w wyniku długości?
sql-server
Jason Snelders
źródło
źródło
Odpowiedzi:
Jest to wyraźnie udokumentowane przez firmę Microsoft w witrynie MSDN pod adresem http://msdn.microsoft.com/en-us/library/ms190329(SQL.90).aspx , który stwierdza, że LEN „zwraca liczbę znaków określonego wyrażenia ciągu, z wyłączeniem końcowe spacje ”. Jest to jednak łatwy szczegół do przeoczenia, jeśli nie jesteś ostrożny.
Zamiast tego należy użyć funkcji DATALENGTH - patrz http://msdn.microsoft.com/en-us/library/ms173486(SQL.90).aspx - która „zwraca liczbę bajtów używanych do reprezentowania dowolnego wyrażenia”.
Przykład:
źródło
DATALENGTH
Wynik należy również podzielić przez 2, jeśli testowane wyrażenie ma typ szerokiego znaku (Unicode; nchar, nvarchar lub ntext), ponieważ wynik jest w bajtach , a nie w znakach .varchar
itp. Może to zależeć od sortowania i nawet proste dzielenie przez 2 nie jest wiarygodne. Zobacz przykład tutajLEN(REPLACE(expr, ' ', '_'))
. Powinno to działać z ciągami znakówvarchar
invarchar
i zawierającymi specjalne znaki sterujące Unicode.DATALENGTH()
nie powinno być traktowane jako alternatywny sposób liczenia znaków, ponieważ liczy bajty zamiast znaków i ma to znaczenie, gdy reprezentuje ten sam ciąg wVARCHAR
/NVARCHAR
.Możesz użyć tej sztuczki:
LEN (Str + 'x') - 1
źródło
Używam tej metody:
Wolę to od DATALENGTH, ponieważ działa to z różnymi typami danych i wolę to niż dodawanie znaku na końcu, ponieważ nie musisz się martwić o przypadek krawędzi, w którym twój ciąg ma już maksymalną długość.
Uwaga: przed użyciem przetestowałbym wydajność w odniesieniu do bardzo dużego zestawu danych; chociaż właśnie przetestowałem go na 2M rzędach i nie był wolniejszy niż LEN bez REPLACE ...
źródło
Możesz poprosić kogoś o zgłoszenie prośby o ulepszenie SQL Server / zgłoszenie błędu, ponieważ prawie wszystkie wymienione tutaj obejścia tego niezwykle prostego problemu mają pewne wady lub są nieefektywne. Nadal wydaje się, że tak jest w SQL Server 2012. Funkcja automatycznego przycinania może pochodzić z ANSI / ISO SQL-92, ale wydaje się, że są jakieś dziury (lub brak ich zliczania).
Zagłosuj na „Dodaj ustawienie, aby LEN liczyło końcowe spacje” tutaj:
https://feedback.azure.com/forums/908035-sql-server/suggestions/34673914-add-setting-so-len-counts-trailing-whitespace
Wycofane łącze Connect: https://connect.microsoft.com/SQLServer/feedback/details/801381
źródło
datalength
Rozwiązanie jest nawet gorzej, począwszy od serwera SQL 2012, ponieważ nie obsługuje zastępczych par w UTF-16, co oznacza, postać może używać maksymalnie 4 bajty. Naprawdę nadszedł czas, aby naprawićlen
funkcję zgodną z ANSI lub przynajmniej zapewnić dedykowaną funkcję do liczenia znaków, w tym spacji końcowych.Wystąpiły problemy z dwoma najczęściej głosowanymi odpowiedziami. Polecająca odpowiedź
DATALENGTH
jest podatna na błędy programisty. WynikDATALENGTH
należy podzielić przez 2 dlaNVARCHAR
typów, ale nie dlaVARCHAR
typów. Wymaga to znajomości typu, którego długość otrzymujesz, a jeśli ten typ się zmieni, musisz pilnie zmieniać miejsca, z których korzystałeśDATALENGTH
.Jest też problem z najbardziej pozytywną odpowiedzią (przyznaję, że był to mój ulubiony sposób, dopóki ten problem mnie nie ugryzł). Jeśli rzecz, której otrzymujesz długość, jest typu
NVARCHAR(4000)
i faktycznie zawiera ciąg 4000 znaków, SQL zignoruje dołączony znak, zamiast niejawnie rzutować wynik naNVARCHAR(MAX)
. Wynik końcowy to nieprawidłowa długość. To samo stanie się z VARCHAR (8000).To, co znalazłem, działa, jest prawie tak szybkie, jak zwykłe stare
LEN
, jest szybsze niż wLEN(@s + 'x') - 1
przypadku dużych ciągów i nie zakłada, że podstawowa szerokość znaku jest następująca:Pobiera długość danych, a następnie dzieli przez długość danych pojedynczego znaku z ciągu. Dodanie „x” obejmuje przypadek, w którym ciąg jest pusty (co w tym przypadku dałoby podzielenie przez zero). Działa
@s
to niezależnie od tego, czy jest,VARCHAR
czyNVARCHAR
. WykonanieLEFT
1 znaku przed dołączeniem pozwala zaoszczędzić trochę czasu, gdy ciąg jest duży. Problem z tym polega jednak na tym, że nie działa poprawnie z łańcuchami zawierającymi pary zastępcze.W komentarzu do zaakceptowanej odpowiedzi wspomniano o innym sposobie użycia
REPLACE(@s,' ','x')
. Ta technika daje poprawną odpowiedź, ale jest o kilka rzędów wielkości wolniejsza niż inne techniki, gdy struna jest duża.Biorąc pod uwagę problemy wprowadzone przez pary zastępcze w dowolnej używanej technice
DATALENGTH
, myślę, że najbezpieczniejsza metoda, która daje prawidłowe odpowiedzi, to:Jest to szybsze niż
REPLACE
technika i znacznie szybsze w przypadku dłuższych strun. Zasadniczo ta technika jestLEN(@s + 'x') - 1
techniką, ale z ochroną dla przypadku krawędzi, w którym łańcuch ma długość 4000 (dla nvarchar) lub 8000 (dla varchar), więc nawet w tym przypadku podano poprawną odpowiedź. Powinien również poprawnie obsługiwać łańcuchy z parami zastępczymi.źródło
N'x𤭢x' COLLATE Latin1_General_100_CI_AS_SC
daje 4, podczas gdyLEN
daje 3.Musisz również upewnić się, że Twoje dane są faktycznie zapisane z końcowymi spacjami. Kiedy ANSI PADDING jest WYŁĄCZONE (inne niż domyślne):
źródło
LEN domyślnie wycina końcowe spacje, więc stwierdziłem, że działa, gdy przesuwasz je do przodu
(LEN (REVERSE (TestField))
Więc jeśli chcesz, możesz powiedzieć
Nie używaj tego oczywiście do wiodących spacji.
źródło
declare @TestField varchar(10);
SET @TestField = ' abc '; -- Length with spaces is 5.
select LEN(REVERSE(@TestField)) -- Returns 4
select LEN(@TestField) -- Returns 4
Powinieneś zdefiniować funkcję CLR, która zwraca pole Długość ciągu, jeśli nie lubisz łączenia ciągów. Używam
LEN('x' + @string + 'x') - 2
w moich przypadkach użycia w produkcji.źródło
Jeśli nie podoba ci się z
DATALENGTH
powodu obaw n / varchar, co powiesz na:co jest sprawiedliwe
owinięte ochroną dzielenia przez zero.
Dzieląc przez DATALENGTH pojedynczego znaku, otrzymujemy znormalizowaną długość.
(Oczywiście nadal występują problemy z parami zastępczymi, jeśli jest to problem).
źródło
użyj SELECT DATALENGTH („ciąg”)
źródło