2010-09-20 38 views
5

Ich erstelle T-SQL-SELECT-Anweisungen für Tabellen, für die ich vorher keine Datentypinformationen habe. In diesen Anweisungen muss ich Zeichenfolgenmanipulationsoperationen ausführen, die von der Länge des ursprünglichen Werts der Tabellenspalten abhängen.T-SQL: Wie erhält man die genaue Länge einer Zeichenfolge in Zeichen?

Ein Beispiel (aber nicht die einzige) ist etwas Text in einer bestimmten Position in einem String einzufügen, einschließlich der Option, es am Ende einzufügen:

SELECT 
    CASE WHEN (LEN ([t0].[Product] = 8) 
    THEN [t0].[Product] + 'test' 
    ELSE STUFF ([t0].[Product], 8, 0, 'test') 
    END 
FROM [OrderItem] [t0] 

(der Fall, wenn + LEN erforderlich, da STUFF es mir nicht erlaubt, Text am Ende eines Strings einzufügen.)

Das Problem ist, dass LEN nachgestellte Leerzeichen ausschließt, was die Berechnung ruinieren wird. Ich weiß, dass ich DATALENGTH verwenden kann, das nachgestellte Leerzeichen nicht ausschließt, aber ich kann die von DATALENGTH zurückgegebenen Bytes nicht in die von STUFF benötigten Zeichen konvertieren, weil ich nicht weiß, ob die Produktspalte vom Typ varchar oder nvarchar ist.

Also, wie kann ich eine SQL-Anweisung generieren, die von der genauen Länge einer Zeichenfolge in Zeichen ohne vorherige Informationen über den verwendeten Zeichenfolgedatentyp abhängt?

Antwort

12

Hier ist, was ich am Ende mit:

SELECT 
    CASE WHEN ((LEN ([t0].[Product] + '#') - 1) = 8) 
    THEN [t0].[Product] + 'test' 
    ELSE STUFF ([t0].[Product], 8, 0, 'test') 
    END 
FROM [OrderItem] [t0] 

Messungen zeigen, dass die LEN (. .. + '#') - 1 Trick ist ungefähr so ​​schnell wie LEN (...) alleine.

Danke für all die guten Antworten!

+0

+1 für eine Lösung, die funktioniert! –

+0

+1 Das könnte ein nützlicher Trick sein. –

3

Können Sie die Typinformationen für die Spalten in den Systemtabellen nicht nachschlagen?

Wenn nicht, dann zu bestimmen, ob eine Spalte varchar oder ist, würde dies tun.

create table #test 
(
c varchar(50), 
n nvarchar(50) 
) 

insert into #test values ('1,2,3,4 ',N'1,2,3,4,5  ') 

SELECT 
     CASE 
       WHEN datalength(CAST(c AS nvarchar(MAX))) = datalength(c) 
       THEN 'c is nvarchar' 
       ELSE 'c is char' 
     END, 
     CASE 
       WHEN datalength(CAST(n AS nvarchar(MAX))) = datalength(n) 
       THEN 'n is nvarchar' 
       ELSE 'n is char' 
     END 
FROM #test 
+0

Nachschlagen der Informationen: wahrscheinlich möglich, aber schwierig. Ich bin mir auch nicht sicher, wie das funktionieren würde. –

+0

Der Test ist auch interessant, aber ich denke, ich mag den REPLACE-Hack etwas besser in Bezug auf die "Lesbarkeit" der resultierenden Aussage. –

+0

@Fabien - Ich bin mir ziemlich sicher, dass das Nachschlagen der Typinformationen eine bessere Leistung bringt, als entweder eine Ersetzung für jede Zeichenfolge in der Spalte oder eine Umwandlung für jede Zeichenfolge. –

4

versuchen Sie dies:

SELECT 
    CASE WHEN (LEN (REPLACE([t0].[Product],' ', '#') = 8) 
    THEN [t0].[Product] + 'test' 
    ELSE STUFF ([t0].[Product], 8, 0, 'test') 
    END 
FROM [OrderItem] [t0] 
+0

Gute Idee, ich hätte das selbst haben sollen ... –

+0

Das ist sehr ineffizient, wie meine Messungen zeigen. –

+1

Eine schnelle Änderung ist jedoch blitzschnell: LEN ([t0]. [Produkt] + '#') - 1 Dies ist ungefähr die gleiche Geschwindigkeit wie LEN ([t0]. [Produkt]) allein. .. –

1

Verwenden DATALENGTH und SQL_VARIANT_PROPERTY:

SELECT 
    CASE 
    WHEN 8 
     = DATALENGTH([t0].[Product]) 
    /CASE SQL_VARIANT_PROPERTY([t0].[Product],'BaseType') WHEN 'nvarchar' THEN 2 ELSE 1 END 
    THEN [t0].[Product] + 'test' 
    ELSE STUFF ([t0].[Product], 8, 0, 'test') 
    END 
FROM [OrderItem] [t0] 
+0

Ich habe dies getestet, und während es genau das aussieht, was ich brauche, funktioniert es nicht mit varchar (max)/nvarchar (max) - weil sql_variant solche Werte nicht halten kann. –

0

Wenn keine führenden Leerzeichen vorhanden sind, gibt len(reverse(column_name)) die Spaltenlänge an.