Nedan finns fem alternativ för att returnera rader som innehåller versaler i SQL Server.
Exempeldata
Anta att vi har en tabell med följande data:
SELECT c1 FROM t1;
Resultat:
+----------------+ | c1 | |----------------| | CAFÉ | | Café | | café | | 1café | | eCafé | | James Bond 007 | | JB 007 | | 007 | | NULL | | | | É | | É 123 | | é | | é 123 | | ø | | Ø | +----------------+
Vi kan använda följande metoder för att returnera de rader som innehåller versaler.
Alternativ 1:Jämför med LOWER()
Sträng
Vi kan använda LOWER()
funktion för att jämföra det ursprungliga värdet med dess gemener:
SELECT c1 FROM t1
WHERE LOWER(c1) COLLATE Latin1_General_CS_AS <> c1;
Resultat:
+----------------+ | c1 | |----------------| | CAFÉ | | Café | | eCafé | | James Bond 007 | | JB 007 | | É | | É 123 | | Ø | +----------------+
Genom att använda inte lika med (<>
) operator (du kan alternativt använda !=
istället för <>
om du föredrar det), returnerar vi bara de rader som skiljer sig från deras gemener. Anledningen till att vi gör detta är att om ett värde är detsamma som dess gemener, så var det redan gemener till att börja med (och vi vill inte returnera det).
Vi använder också COLLATE Latin1_General_CS_AS
för att uttryckligen ange en skiftlägeskänslig (och accentkänslig) sammanställning. Utan detta kan du få oväntade resultat, beroende på vilken sortering som används på ditt system.
Alternativ 2:Jämför med de faktiska tecknen
Ett annat alternativ är att använda LIKE
operatorn och ange de verkliga versaler som vi vill matcha:
SELECT c1 FROM t1
WHERE c1 LIKE '%[ABCDEFGHIJKLMNOPQRSTUVWXYZ]%'
COLLATE Latin1_General_CS_AS;
Resultat:
+----------------+ | c1 | |----------------| | CAFÉ | | Café | | eCafé | | James Bond 007 | | JB 007 | +----------------+
I det här fallet returneras färre rader än i föregående exempel. Detta beror på att jag inte angav tecken som É
och Ø
, som returnerades i föregående exempel. Vårt resultat innehåller É
men den raden returnerades bara eftersom den också innehåller andra versaler som gör match.
Därför är det här alternativet mer begränsat än det föregående, men det ger dig mer kontroll över de karaktärer du vill matcha.
Alternativ 3:Jämför med en rad tecken
Vi kan alternativt specificera intervallet av tecken vi vill matcha:
SELECT * FROM t1
WHERE c1 LIKE '%[A-Z]%'
COLLATE Latin1_General_100_BIN2;
Resultat:
+----------------+ | c1 | |----------------| | CAFÉ | | Café | | eCafé | | James Bond 007 | | JB 007 | +----------------+
I det här fallet använde jag en binär sortering (Latin1_General_100_BIN2
). Jag gjorde detta eftersom binära sammanställningar sorterar varje fall separat (så här:AB....YZ...ab...yz
).
Andra sorteringar tenderar att blanda versaler och gemener (så här:AaBb...YyZz
), som därför skulle matcha både versaler och gemener.
Alternativ 4:Hitta den första instansen av ett versaltecken
Ett annat sätt att göra det är att använda PATINDEX()
funktion:
SELECT * FROM t1
WHERE PATINDEX('%[ABCDEFGHIJKLMNOPQRSTUVWXYZ]%', c1
COLLATE Latin1_General_CS_AS) > 0;
Resultat:
+----------------+ | c1 | |----------------| | CAFÉ | | Café | | eCafé | | James Bond 007 | | JB 007 | +----------------+
I det här exemplet anger vi de exakta tecken som vi vill matcha, så i det här fallet fick vi inte raderna med tecken som É
och Ø
(annat än den som också innehåller andra tecken som matchades).
En fördel med denna teknik är att vi kan använda den för att ignorera det första tecknet (eller specificerat antal tecken) om vi så önskar:
SELECT * FROM t1
WHERE PATINDEX('%[ABCDEFGHIJKLMNOPQRSTUVWXYZ]%', c1
COLLATE Latin1_General_CS_AS) > 1;
Resultat:
Time: 0.472s +-------+ | c1 | |-------| | eCafé | +-------+
Därför kan vi returnera alla rader som innehåller versaler, men där det första tecknet inte är versaler.
Detta beror på att PATINDEX()
returnerar startpositionen för den första förekomsten av mönstret (i vårt fall är mönstret en lista med versaler). Om startpositionen för den första förekomsten är större än 1, finns inte det första tecknet i vår lista med versaler.
Alternativ 5:Hitta den första instansen baserat på ett intervall
Vi kan också använda PATINDEX()
med ett intervall:
SELECT * FROM t1
WHERE PATINDEX('%[A-Z]%', c1
COLLATE Latin1_General_100_BIN2) > 1;
Resultat:
+-------+ | c1 | |-------| | eCafé | +-------+
Jag använde återigen en binär sammanställning (som med det andra exemplet med intervall).