UZUNLUK işlevi SQL Server'da sondaki boşlukları içermiyor


109

SQL Server 2005'te aşağıdaki test tablosuna sahibim:

CREATE TABLE [dbo].[TestTable]
(
 [ID] [int] NOT NULL,
 [TestField] [varchar](100) NOT NULL
) 

Şununla doldurulur:

INSERT INTO TestTable (ID, TestField) VALUES (1, 'A value');   -- Len = 7
INSERT INTO TestTable (ID, TestField) VALUES (2, 'Another value      '); -- Len = 13 + 6 spaces

TestField'in uzunluğunu SQL Server LEN () işlevi ile bulmaya çalıştığımda, sondaki boşlukları saymaz - örneğin:

-- 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

Uzunluk sonucunun sonundaki boşlukları nasıl eklerim?


1
Sanırım buradaki gerçek çözüm Microsoft'un bozuk yazılımlarını düzeltmesi olabilir. Burada oy verin: feedback.azure.com/forums/908035-sql-server/suggestions/…
QA Collective

Yanıtlar:


125

Bu, Microsoft tarafından http://msdn.microsoft.com/en-us/library/ms190329(SQL.90).aspx adresindeki MSDN'de açıkça belgelenmiştir ; bu, LEN "ifadesinin belirtilen dize ifadesinin karakter sayısını döndürdüğünü belirtir. takip eden boşluklar ". Bununla birlikte, dikkatli değilseniz gözden kaçırmanız gereken kolay bir ayrıntıdır.

Bunun yerine DATALENGTH işlevini kullanmanız gerekir - "herhangi bir ifadeyi temsil etmek için kullanılan bayt sayısını döndüren" http://msdn.microsoft.com/en-us/library/ms173486(SQL.90).aspx adresine bakın .

Misal:

SELECT 
    ID, 
    TestField, 
    LEN(TestField) As LenOfTestField,           -- Does not include trailing spaces
    DATALENGTH(TestField) As DataLengthOfTestField      -- Shows the true length of data, including trailing spaces.
FROM 
    TestTable

52
NOT: DATALENGTHTest edilen ifade bir geniş karakter tipiyse (Unicode; nchar, nvarchar veya ntext) sonucu 2'ye bölmeniz gerekir, çünkü sonuç karakter değil bayt cinsindendir .
devstuff

7
Ayrıca, varcharvb. İçin bu, harmanlamaya bağlı olabilir ve doğrudan 2'ye bölme bile güvenilir değildir. Buradaki örneğe
Martin Smith

18
Ben kullanırdım LEN(REPLACE(expr, ' ', '_')). Bu, özel unicode kontrol karakterleri içeren varcharve nvarcharve dizeleri ile çalışmalıdır .
Olivier Jacot-Descombes

6
-1, DATALENGTH()karakterlerin yerine baytları saydığı için karakterleri saymanın alternatif bir yolu olarak düşünülmemelidir ve bu aynı dizeyi VARCHAR/ içinde temsil ederken önemlidir NVARCHAR.
binki

5
SQL server 2012'den başlayarak, sürüm 100 harmanlamalı unicode sütunları artık yedek çiftleri desteklemektedir. Bu, tek bir karakterin 4 bayta kadar kullanabileceği ve ikiye bölünmenin başarısız olmasına neden olabileceği anlamına gelir. Msdn'ye bakın .
Frédéric

85

Bu numarayı kullanabilirsin:

UZUNLUK (Str + 'x') - 1


15
Bizi daha iyi alternatiflerle aydınlatır mısınız lütfen? Veri uzunluğu kesinlikle değil.
Serge

15
Tutarsız bir yöntem kullanmanın (bazı durumlarda sonucunu 2'ye bölersiniz ve bazen bölersiniz) daha iyi bir seçenek olduğuna kesinlikle katılmıyorum. Belki de benim yöntemimle neredeyse sıfıra yakın bir performans artışı var mı?
Serge

5
@usr Serge'in yöntemi en iyisidir, IMHO. Basit ve zarif. DATALENGTH karmaşıktır: tek / çift bayt türüne bağlı, harmanlamaya / dile bağlı, vb.
Bay TA

10
Şimdiye kadarki en iyi ve zarif çözüm bu. Bir bilgisayar korsanlığı gibi HİSSEDİLMESİ umrumda değil (kodlama duygularla ilgili değildir), bu çözümün hiçbir yan etkisi olmadığı gerçeğini gerçekten önemsiyorum. Varchar / nvarchar veri türünü değiştirebilirim ve hala çalışıyor. Aferin.
Mike Keskinov

5
Bu yan etki nedeniyle bir uyarı var. Eğer nvarchar (4000) türünde bir değişkenle çalışıyorsanız ve değişkeniniz 4000 karakterlik bir dizge içeriyorsa, eklenen karakter göz ardı edilir ve yanlış sonucu alırsınız (sondaki boşlukları yok sayan SQL len, 1 hariç) çıkarırsın).
hatchet - SOverflow ile bitti

17

Bu yöntemi kullanıyorum:

LEN(REPLACE(TestField, ' ', '.'))

Bunu DATALENGTH yerine tercih ederim çünkü bu farklı veri türleri ile çalışır ve sonuna bir karakter eklemeyi tercih ederim çünkü dizenizin zaten maksimum uzunlukta olduğu uç durum hakkında endişelenmenize gerek yok.

Not: Performansı kullanmadan önce çok büyük bir veri kümesine karşı test ederdim; 2M satırlarına karşı test etsem de REPLACE olmadan LEN'den daha yavaş değildi ...


14

"Uzunluk sonucunun sonundaki boşlukları nasıl eklerim?"

Birinin bir SQL Server geliştirme isteği / hata raporu hazırlamasını sağlarsınız çünkü burada bu şaşırtıcı derecede basit soruna yönelik hemen hemen tüm listelenen geçici çözümler bazı eksiklikler içerir veya verimsizdir. Bu hala SQL Server 2012'de doğru gibi görünüyor. Otomatik kırpma özelliği ANSI / ISO SQL-92'den kaynaklanıyor olabilir, ancak bazı boşluklar (veya bunların sayılmaması) var gibi görünüyor.

Lütfen burada "LEN'in sondaki beyaz boşluğu sayması için ayar ekle" seçeneğine oy verin:

https://feedback.azure.com/forums/908035-sql-server/suggestions/34673914-add-setting-so-len-counts-trailing-whitespace

Retired Connect bağlantısı: https://connect.microsoft.com/SQLServer/feedback/details/801381


2
datalengthŞimdi bir karakter 4 byte kadar kullanabilirsiniz anlamı UTF-16 vekil çiftleri destekler gelmez çünkü çözüm daha da kötüsü, SQL server 2012 tarihinden itibaren başlıyor. lenANSI'ye uymak için işlevi düzeltmelerinin veya en azından sondaki boşluklar dahil olmak üzere karakter sayımı için özel bir işlev sağlamalarının zamanı geldi .
Frédéric

1
Bunun için geri bildirim bağlantısının daha fazla kullanılması gerekiyor. Bu sorunun yalnızca internet üzerinden aranabilmesi şaşırtıcı. Bağlantımın kesilmesinin nedeninin LEN () işlevi olduğunu düşünmeden önce, kendi kodumda nerede hata yaptığımı anlamaya çalışmak için yaklaşık 2 saat harcadım.
Takophiliac

Buna katılıyorum, ancak bir parametrenin boşlukları kırpmasına izin vermeliyim .. EF ile dize karşılaştırmalarını çok daha kolay hale getirdiğinden, iqueryable ifade oluşturulduğunda dahil edilen boşluk olup olmadığını kontrol etmek zorunda kalmadan.
ganjeii

9

En çok oylanan iki cevapla ilgili sorunlar var. Önerilen cevap DATALENGTHprogramcı hatalarına açıktır. Sonuç, türler DATALENGTHiçin 2'ye bölünmelidir NVARCHAR, ancak VARCHARtürler için değil . Bu, uzunluğunu aldığınız tür hakkında bilgi gerektirir ve bu tür değişirse, kullandığınız yerleri özenle değiştirmeniz gerekir.DATALENGTH .

Ayrıca en çok oylanan yanıtla ilgili bir sorun var (kabul ediyorum ki bu sorun beni ısırana kadar bunu yapmak için tercih ettiğim yoldu). Uzunluğunu aldığınız şey NVARCHAR(4000)bir türdeyse ve aslında 4000 karakterlik bir dize içeriyorsa, SQL sonucu örtük olarak atamak yerine eklenen karakteri yok sayacaktır.NVARCHAR(MAX) . Sonuç, yanlış bir uzunluktur. Aynı şey VARCHAR (8000) için de olacak.

Çalışmalar bulduğum şey, neredeyse eski kadar hızlı LEN, LEN(@s + 'x') - 1büyük dizelerden daha hızlı ve temeldeki karakter genişliğinin aşağıdaki gibi olduğunu varsaymıyor:

DATALENGTH(@s) / DATALENGTH(LEFT(LEFT(@s, 1) + 'x', 1))

Bu, veri uzunluğunu alır ve ardından dizeden tek bir karakterin veri uzunluğuna göre böler. 'X' eki, dizenin boş olduğu durumu kapsar (bu durumda sıfıra bölme verir). Bu ister çalışır @solduğunu VARCHARveya NVARCHAR. YapmakLEFT ekleme parfümünü önce bir süre 1 karakterinin dize büyük olduğunda. Bununla ilgili sorun, vekil çiftler içeren dizelerle düzgün çalışmamasıdır.

Kabul edilen cevaba yapılan bir yorumda belirtilen başka bir yol var REPLACE(@s,' ','x'). Bu teknik doğru cevabı verir, ancak tel büyük olduğunda diğer tekniklerden birkaç kat daha yavaştır.

Vekil çiftler tarafından kullanılan herhangi bir teknikte ortaya çıkan problemler göz önüne alındığında, DATALENGTHbildiğim doğru cevapları veren en güvenli yöntemin şu olduğunu düşünüyorum:

LEN(CONVERT(NVARCHAR(MAX), @s) + 'x') - 1

Bu, REPLACEteknikten daha hızlı ve daha uzun dizelerle çok daha hızlıdır. Temelde bu teknik LEN(@s + 'x') - 1tekniktir, ancak dizinin 4000 (nvarchar için) veya 8000 (varchar için) uzunluğuna sahip olduğu uç durum için koruma sağlar, böylece bunun için bile doğru yanıt verilir. Ayrıca vekil çiftleri olan dizeleri de doğru şekilde işlemelidir.


1
Ne yazık ki, bu yanıt artık SQL Server 2012'de vekil çiftleri içeren dizeler için çalışmıyor. İşleminizi çalıştırmak N'x𤭢x' COLLATE Latin1_General_100_CI_AS_SC4 LENverirken 3 verir.
Douglas

9
@Douglas - Bu yararlı bir bilgi. Keşke Microsoft bize sondaki boşlukları göz ardı etmeyen bir LEN sürümü verseydi.
hatchet - SOverflow ile bitti

5

Ayrıca verilerinizin gerçekte sondaki boşluklarla kaydedildiğinden emin olmanız gerekir. Ne zaman ANSI PADDING KAPALI (varsayılan olmayan) 'dir:

Varchar sütununa eklenen karakter değerlerinin sonundaki boşluklar kırpılır.


3
Bu ayar eski olduğundan ANSI PADDING'i kapatmamanız gerektiğini düşünüyorum. Standart dışı bir değerde olması birçok küçük soruna neden olur.
usr

4

LEN varsayılan olarak arkadaki boşlukları keser, bu yüzden siz onları öne doğru hareket ettirirken bunun işe yaradığını gördüm

(UZUNLUK (TERS (TestField))

Yani istersen diyebilirsin

SELECT
t.TestField,
LEN(REVERSE(t.TestField)) AS [Reverse],
LEN(t.TestField) AS [Count]
FROM TestTable t
WHERE LEN(REVERSE(t.TestField)) <> LEN(t.TestField)

Elbette bunu önde gelen alanlar için kullanmayın.


9
Artık arkadaki boşluklar yerine öndeki boşlukları kırpar . Aynı gün, farklı bir problem :)
Reversed Engineer

@DaveBoltman Önerim muhtemelen daha kıvrımlı, ancak ek olarak TRIM'ed uzunluğuyla da karşılaştırabilirsiniz.
Brian J

Bu, sondaki boşluklar yerine baştaki boşlukların sayılmadığı hatayı tersine çevirir. Aşağıdaki koda bakın: declare @TestField varchar(10); SET @TestField = ' abc '; -- Length with spaces is 5. select LEN(REVERSE(@TestField)) -- Returns 4 select LEN(@TestField) -- Returns 4
Metalogic

1

Dize bitiştirmeyi sevmiyorsanız, Dize Uzunluğu alanını döndüren bir CLR işlevi tanımlamalısınız. Kullandığım LEN('x' + @string + 'x') - 2benim üretim kullanım senaryoları içinde.


0

Eğer DATALENGTHn / varchar endişelerinden hoşlanmıyorsanız , ne dersiniz:

select DATALENGTH(@var)/isnull(nullif(DATALENGTH(left(@var,1)),0),1)

hangisi sadece

select DATALENGTH(@var)/DATALENGTH(left(@var,1))

sıfıra bölünme korumasıyla sarılmış.

Tek bir karakterin DATALENGTH ile bölerek uzunluğu normalize etmiş oluruz.

(Tabii ki, eğer endişeniz varsa, vekil çiftlerle hala sorun var.)


-4

SELECT DATALENGTH ('dize') kullanın


2
Başkalarının 7 yıl önceki yanıtlarını yeniden söylediniz ve yeni hiçbir şey sunmadınız, hatta yanıtladığınız şeyin ne olduğunu veya bu soruyu nasıl yanıtladığını açıkladınız.
Jpsh
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.