Hantera strängar och Unicode

Microsoft SQL tillhandahåller flera strängtyper som mssql-python-drivrutinen mappar till Python-objektstr. Det avgörande beslutet är om man ska använda varchar (icke-Unicode) eller nvarchar (Unicode):

  • Använd nvarchar när din data kan innehålla tecken utanför ASCII, såsom namn, adresser eller användargenererat innehåll på vilket språk som helst.
  • Använd varchar när data strikt är ASCII (koder, identifierare, e-postadresser) och du vill spara lagring. varchar använder 1 byte per tecken; nvarchar använder 2 byte per tecken.
SQL-typ Unicode Maxlängd Python-typ
char(n) No 8,000 str
varchar(n) No 8,000 str
varchar(max) No 2 GB str
nchar(n) Ja 4,000 str
nvarchar(n) Ja 4,000 str
nvarchar(max) Ja 2 GB str
text No 2 GB (föråldrad) str
ntext Ja 2 GB (föråldrad) str

Grundläggande strängåtgärder

Drivrutinen mappar alla Microsoft SQL-strängtyper till Python-objektstr.

Sätt in och hämta strängar

Använd parameteriserade frågor för att säkert infoga och hämta strängdata från databasen.

import mssql_python

conn = mssql_python.connect(connection_string)
cursor = conn.cursor()

# Create temp table for demo
cursor.execute("""
    CREATE TABLE #StringDemo (
        ID INT IDENTITY(1,1) PRIMARY KEY,
        Name NVARCHAR(100),
        Email NVARCHAR(200)
    )
""")

# Insert string data
cursor.execute(
    "INSERT INTO #StringDemo (Name, Email) VALUES (%(name)s, %(email)s)",
    {"name": "Alice Smith", "email": "alice@example.com"}
)
conn.commit()

# Retrieve string data
cursor.execute("SELECT Name, Email FROM #StringDemo WHERE ID = 1")
row = cursor.fetchone()
print(row.Name)   # 'Alice Smith'
print(row.Email)  # 'alice@example.com'

Strängar med specialtecken

Hantera citattecken, vinkelparenteser och andra specialtecken i strängar med hjälp av parameteriserade frågor.

# Quotes and special characters handled automatically
cursor.execute("""
    CREATE TABLE #Notes (
        ID INT IDENTITY(1,1) PRIMARY KEY,
        Title NVARCHAR(200),
        Content NVARCHAR(MAX)
    )
""")
cursor.execute(
    "INSERT INTO #Notes (Title, Content) VALUES (%(title)s, %(content)s)",
    {
        "title": "O'Brien's Report",
        "content": 'Contains "quotes" and special chars: <>&'
    }
)
conn.commit()

Unicode-stöd

Använd nvarchar-kolumner och Python str för att lagra och hämta text i vilket språk som helst.

Lagra Unicode-text

Infoga Unicode-innehåll genom att skicka Python-strängar till parameteriserade frågor; drivrutinen kodar dem som UTF-16LE för nvarchar-kolumner.

# International characters - use nvarchar columns
cursor.execute("""
    CREATE TABLE #Messages (
        ID INT IDENTITY(1,1) PRIMARY KEY,
        Content NVARCHAR(MAX)
    )
""")
cursor.execute("""
    INSERT INTO #Messages (Content) VALUES (%(msg)s)
""", {"msg": "Hello 你好 مرحبا שלום 🎉"})

cursor.execute("SELECT Content FROM #Messages WHERE ID = 1")
row = cursor.fetchone()
print(row.Content)  # 'Hello 你好 مرحبا שלום 🎉'

Unicode i olika skript

Stöd flera språk och skript i en enda tabell genom att använda nvarchar-kolumner och bulkinsättningar.

messages = [
    {"lang": "English", "text": "Hello, World!"},
    {"lang": "Chinese", "text": "你好,世界!"},
    {"lang": "Japanese", "text": "こんにちは世界!"},
    {"lang": "Korean", "text": "안녕하세요, 세상!"},
    {"lang": "Arabic", "text": "مرحبا بالعالم!"},
    {"lang": "Hebrew", "text": "שלום עולם!"},
    {"lang": "Russian", "text": "Привет мир!"},
    {"lang": "Greek", "text": "Γειά σου Κόσμε!"},
    {"lang": "Emoji", "text": "👋🌍✨🎉"},
]

cursor.execute("""
    CREATE TABLE #Greetings (
        ID INT IDENTITY(1,1) PRIMARY KEY,
        Language NVARCHAR(50),
        Message NVARCHAR(200)
    )
""")
cursor.executemany("""
    INSERT INTO #Greetings (Language, Message) VALUES (%(lang)s, %(text)s)
""", messages)
conn.commit()

Säkerställ nvarchar-kolumner för Unicode

Definiera alltid kolumner som nvarchar istället för varchar när din data kan innehålla icke-ASCII-tecken.

-- For Unicode data, always use nvarchar, not varchar
CREATE TABLE #UnicodeDemo (
    ID INT IDENTITY PRIMARY KEY,
    Name NVARCHAR(100),        -- Supports Unicode
    Description NVARCHAR(MAX)  -- Supports large Unicode text
);

Stränglängdsöverväganden

Välj mellan typer med fast längd och variabel längd baserat på hur konsekventa dina datalängder är.

Fast kontra variabel längd

Microsoft SQL char(n) fyller ut värden med efterföljande mellanrum till den deklarerade längden. Denna utfyllning slösar bort lagring för data med variabel längd men kan förbättra prestandan för kolumner med fast bredd, såsom landskoder. Använd varchar(n) för de flesta strängkolumner.

Följande exempel visar skillnaden i hur utaddade och icke-vadderade kolumner hanterar datahämtning:

# char(6) pads to fixed length
cursor.execute(
    "SELECT StateProvinceCode FROM Person.StateProvince WHERE StateProvinceID = 1"
)  # nchar(6) column
row = cursor.fetchone()
print(repr(row.StateProvinceCode))  # 'AB    ' - right-padded with spaces

# nvarchar stores actual length
cursor.execute(
    "SELECT Name FROM Person.StateProvince WHERE StateProvinceID = 1"
)  # nvarchar column
row = cursor.fetchone()
print(repr(row.Name))  # 'Alberta' - no padding

Hantera efterföljande utrymmen

När du hämtar data från kolumner med fast längd, använd rstrip() för att ta bort de utfyllnadsutrymmen som lagts till av Microsoft SQL Server.

# Strip trailing spaces from char columns
cursor.execute("SELECT ProductNumber FROM Production.Product")
for row in cursor:
    code = row.ProductNumber.rstrip()  # Remove trailing spaces
    print(f"Code: '{code}'")

Stora strängar (MAX-typer)

Och-typerna nvarchar(max)varchar(max) stödjer strängar upp till 2 GB, idealiskt för lagring av stora textdokument, JSON eller XML-innehåll.

# Large text content
large_content = "x" * 100000  # 100K characters

cursor.execute("""
    CREATE TABLE #Documents (
        ID INT IDENTITY(1,1) PRIMARY KEY,
        Content NVARCHAR(MAX)
    )
""")
cursor.execute("""
    INSERT INTO #Documents (Content) VALUES (%(content)s)
""", {"content": large_content})

cursor.execute("SELECT Content FROM #Documents WHERE ID = 1")
row = cursor.fetchone()
print(len(row.Content))  # 100000

Strängjämförelse och sortering

Microsoft SQL-strängjämförelsebeteende beror på sorteringsuppsättningen i databasen eller kolumnen.

Skiftlägesberoende

Microsoft SQL-strängsjämförelse beror på sorteringen. Som standard använder de flesta databaser kasus-insensitiv sortering, men du kan åsidosätta detta med klausulen COLLATE .

# Case-insensitive collation (default for many databases)
cursor.execute("SELECT * FROM Person.Person WHERE LastName = %(name)s", {"name": "smith"})
# Might match 'Smith', 'SMITH', 'smith' depending on collation

# For case-sensitive comparison
cursor.execute("""
    SELECT * FROM Person.Person 
    WHERE LastName COLLATE Latin1_General_CS_AS = %(name)s
""", {"name": "Smith"})

mönstermatchning med LIKE

Använd operatorn LIKE med joker-tecken för att söka efter strängmönster; escape-specialtecken med parentesnotation för att matcha literaler.

# Wildcard searches
search_term = "Road"
cursor.execute("""
    SELECT Name FROM Production.Product WHERE Name LIKE %(pattern)s
""", {"pattern": f"%{search_term}%"})

# Escape special characters in search
def escape_like(value: str) -> str:
    """Escape LIKE wildcards in search value."""
    return value.replace("[", "[[]").replace("%", "[%]").replace("_", "[_]")

search = "100%"
cursor.execute("""
    SELECT Name FROM Production.Product WHERE Name LIKE %(pattern)s
""", {"pattern": f"%{escape_like(search)}%"})

Kodningsöverväganden

Kodningsbeteendet beror på Microsoft SQL-kolumntypen och källsorteringen.

Kodningsantaganden och Unicode-standardinställningar

Drivrutinen mssql-python hanterar kodning automatiskt baserat på Microsoft SQL-kolumntypen. Som standard skickas strängparametrar som UTF-16LE för nvarchar-kolumner och enligt databasens sortering för varchar-kolumner:

Kolumntyp Trådkodning Python-resultat
nvarchar, nchar, ntext UTF-16LE str (avkodad av föraren)
varchar, char, text Databas- eller kolumnkollationskodning str (avkodas av drivrutinen med hjälp av källkodningen)

Python-strängar är alltid Unicode internt. När du skickar en str parameter kodar drivrutinen den för målkolumntypen. Som standard skickar drivrutinen strängparametrar som nvarchar (Unicode), vilket säkerställer att tecken bevaras oavsett databassortering. För varchar kolumner gäller UTF-8 endast när databasen eller kolumnen använder en UTF-8-aktiverad sortering.

Om din kolumn är det varchar och du behöver skicka icke-Unicode-data för att matcha kolumntypen exakt (till exempel för att undvika implicita konverteringsvarningar), använd setinputsizes() för att åsidosätta standarden:

import mssql_python

conn = mssql_python.connect(connection_string)
cursor = conn.cursor()

# Create temp table for demo
cursor.execute("CREATE TABLE #AsciiTable (Code VARCHAR(100))")

cursor.setinputsizes([(mssql_python.SQL_VARCHAR, 100, 0)])
cursor.execute(
    "INSERT INTO #AsciiTable (Code) VALUES (?)",
    ("ABC123",)
)
conn.commit()

För de flesta applikationer är standardbeteendet korrekt. Åsidosätt endast när du ser implicita konverteringsvarningar i frågeplaner eller behöver matcha en specifik varchar sortering.

Anslutningskodning

mssql-python-drivrutinen hanterar automatiskt kodning för anslutningen baserat på Microsoft SQL Server-versionen och konfigurationen. Eftersom Python-strängar är Unicode, kodar drivrutinen dem lämpligt (UTF-8 eller UTF-16) för måldatatypen. Du behöver inte konfigurera anslutningskodning manuellt.

VARCHAR-kolonner med äldre kollationer

Databaser med Windows-1252 (CP1252)-sorteringar, såsom Latin1_General_CI_AS, lagrar utökade latinska tecken (till exempel , , och accentuerade tecken) i varchar kolumner med CP1252-kodning. Föraren avkodar dessa tecken korrekt på alla plattformar.

Denna skillnad är viktig för plattformsoberoende distributioner: samma varchar data som läses korrekt på Windows läses också korrekt på Linux, utan någon särskild konfiguration.

# Create a temp table with a varchar column and insert extended Latin characters
cursor.execute("CREATE TABLE #Products (Name VARCHAR(100))")
cursor.execute("INSERT INTO #Products (Name) VALUES (%(name)s)", {"name": "Café €100 ™"})
conn.commit()

# CP1252 characters in varchar columns are decoded correctly on all platforms
cursor.execute("SELECT Name FROM #Products WHERE Name LIKE '%€%'")
for row in cursor:
    print(row.Name)  # Correct on both Windows and Linux

Om ditt schema tillåter det undviker du helt tvetydighet i kodningen genom att migrera kolumner till varcharnvarchar, och det stöder alla Unicode-tecken.

Filkodning

När du läser filer som ska infogas i databasen, ange lämplig kodning för att bevara Unicode-innehåll.

# Reading files with explicit encoding
def insert_file_content(cursor, conn, file_path: str, encoding: str = "utf-8"):
    with open(file_path, "r", encoding=encoding) as f:
        content = f.read()
    
    cursor.execute(
        "INSERT INTO #FileContent (Content) VALUES (%(content)s)",
        {"content": content}
    )
    conn.commit()

Vanliga strängoperationer

Dessa exempel täcker vanliga mönster för strängmanipulation i både Python och SQL.

Sammanfogning

Du kan sammanfoga strängar antingen i Python innan du infogar eller använder SQL:s strängoperatorer på servern.

# Concatenate in Python before insert
first_name = "Alice"
last_name = "Smith"
full_name = f"{first_name} {last_name}"

cursor.execute("""
    CREATE TABLE #ConcatDemo (
        ID INT IDENTITY(1,1) PRIMARY KEY,
        FullName NVARCHAR(200)
    )
""")
cursor.execute(
    "INSERT INTO #ConcatDemo (FullName) VALUES (%(name)s)",
    {"name": full_name}
)

# Or concatenate in SQL
cursor.execute("""
    SELECT FirstName + ' ' + LastName AS FullName FROM Person.Person
""")

Strängformatering

Använd formatering i Python för att visa strängar med valuta, utfyllnad eller justering innan du visar dem för användarna.

from decimal import Decimal

# Format for display
cursor.execute("SELECT Name, ListPrice FROM Production.Product WHERE ListPrice > 0")
for row in cursor.fetchall()[:5]:
    print(f"{row.Name}: ${row.ListPrice:.2f}")

# Pad strings
cursor.execute("SELECT ProductNumber FROM Production.Product")
for row in cursor.fetchall()[:5]:
    padded = row.ProductNumber.ljust(15)  # Left-justify, pad to 15 chars
    print(f"[{padded}]")

NULL kontra tom sträng

Microsoft SQL behandlar NULL och tom sträng ('') som olika värden. NULL betyder "okänd" medan tom sträng betyder "känd för att vara tom." Välj en konvention för din ansökan och var konsekvent. De flesta applikationer använder NULL för saknade valfria fält.

Följande exempel visar hur man skiljer mellan NULL och tom sträng:

# NULL is different from empty string
cursor.execute("""
    CREATE TABLE #NullDemo (
        ID INT IDENTITY(1,1) PRIMARY KEY,
        Name NVARCHAR(100),
        MiddleName NVARCHAR(100)
    )
""")
cursor.execute("""
    INSERT INTO #NullDemo (Name, MiddleName) 
    VALUES (%(name)s, %(middle)s)
""", {"name": "Alice", "middle": None})  # NULL

cursor.execute("""
    INSERT INTO #NullDemo (Name, MiddleName) 
    VALUES (%(name)s, %(middle)s)
""", {"name": "Bob", "middle": ""})  # Empty string

# Query differences
cursor.execute("SELECT * FROM #NullDemo WHERE MiddleName IS NULL")
cursor.execute("SELECT * FROM #NullDemo WHERE MiddleName = ''")

Trimning

Använd Pythons strängmetoder för att ta bort inledande, avslutande eller både inledande och avslutande blanktecken från värden som hämtats från databasen.

cursor.execute("SELECT Name FROM Production.Product")
for row in cursor:
    # Remove whitespace
    trimmed = row.Name.strip()  # Both ends
    left_trimmed = row.Name.lstrip()
    right_trimmed = row.Name.rstrip()

JSON-strängdata

Lagra JSON-dokument i nvarchar(max)-kolumner och fråga dem med Microsoft SQL:s JSON-funktioner.

Lagra JSON som nvarchar

Serialisera Python-ordböcker till JSON-strängar och infoga dem i nvarchar-kolumner; hämta och deserialisera dem tillbaka till Python-objekt.

import json

data = {"name": "Alice", "scores": [95, 87, 91], "active": True}
json_string = json.dumps(data)

cursor.execute("""
    CREATE TABLE #Configs (
        ID INT IDENTITY(1,1) PRIMARY KEY,
        ConfigData NVARCHAR(MAX)
    )
""")
cursor.execute("""
    INSERT INTO #Configs (ConfigData) VALUES (%(data)s)
""", {"data": json_string})

# Retrieve and parse
cursor.execute("SELECT ConfigData FROM #Configs WHERE ID = 1")
row = cursor.fetchone()
config = json.loads(row.ConfigData)
print(config["name"])  # 'Alice'

Använd Microsoft SQL JSON-funktioner

Använd Microsoft SQL:s JSON-funktioner för att tolka och filtrera JSON-data direkt i frågor istället för i klientkod.

import json

data = {"name": "Alice", "scores": [95, 87, 91], "active": True}

cursor.execute("""
    CREATE TABLE #Configs (
        ID INT IDENTITY(1,1) PRIMARY KEY,
        ConfigData NVARCHAR(MAX)
    )
""")
cursor.execute(
    "INSERT INTO #Configs (ConfigData) VALUES (%(data)s)",
    {"data": json.dumps(data)}
)
conn.commit()

cursor.execute("""
    SELECT JSON_VALUE(ConfigData, '$.name') AS Name
    FROM #Configs
    WHERE JSON_VALUE(ConfigData, '$.active') = 'true'
""")
for row in cursor:
    print(row.Name)  # 'Alice'

Använd LIKE för mönstermatchning, eller aktivera ett fulltextindex för mer avancerad textsökning.

Fulltextfrågor

Operatorn LIKE med wildcard-mönster ger ett enkelt alternativ till fulltextsökning när ett fulltextindex inte finns tillgängligt.

# Using CONTAINS (requires full-text index on the table)
cursor.execute("""
    SELECT JobTitle FROM HumanResources.Employee
    WHERE JobTitle LIKE %(search)s
""", {"search": "%Engineer%"})

# Pattern-based search as an alternative to full-text
cursor.execute("""
    SELECT Name FROM Production.Product
    WHERE Name LIKE %(search)s
""", {"search": "%Mountain%"})

Metodtips

Tillämpa dessa riktlinjer för att hantera strängdata korrekt över språk och kodningar.

Använd nvarchar för internationella data

Om du är osäker på om en kolumn kan innehålla Unicode, använd nvarchar. Lagringskostnaden är blygsam och det förhindrar dataförlust vid teckenkonvertering.

Följande exempel visar skillnaden mellan att definiera kolumner för Unicode och endast ASCII-data:

-- Good: supports any language
CREATE TABLE #UserProfile (
    Name NVARCHAR(100),
    Bio NVARCHAR(MAX)
);

-- Limited: ASCII/Latin only
CREATE TABLE #UserProfileAscii (
    Name VARCHAR(100),
    Bio VARCHAR(MAX)
);

Validera stränglängd

Kontrollera stränglängden i Python innan du infogar för att undvika trunkeringsfel och ge meningsfulla felmeddelanden till användarna.

def safe_insert(cursor, name: str, max_length: int = 100):
    """Insert with length validation."""
    if len(name) > max_length:
        raise ValueError(f"Name exceeds {max_length} characters")
    
    cursor.execute(
        "INSERT INTO #UserProfile (Name) VALUES (%(name)s)",
        {"name": name}
    )

Hantera binära strängar separat

Skilj mellan textsträngar (Pythonstr, SQLnvarchar) och binär data (Pythonbytes, SQLvarbinary) för att undvika kodningsproblem.

binary_data = b'\x00\x01\x02'  # bytes - use varbinary
text_data = "Hello"            # str - use nvarchar