Verwerk tekenreeksen en Unicode

Microsoft SQL biedt meerdere stringtypes die de mssql-python-driver aan Python-objecten str koppelt. De belangrijkste beslissing is of je (niet-Unicode) of varchar (Unicode) gebruikt nvarchar :

  • Gebruik nvarchar wanneer je data tekens buiten ASCII kan bevatten, zoals namen, adressen of door gebruikers gegenereerde inhoud in welke taal dan ook.
  • Gebruik varchar wanneer data strikt ASCII is (codes, identificaties, e-mailadressen) en je opslag wilt besparen. varchar gebruikt 1 byte per karakter; nvarchar gebruikt 2 bytes per teken.
SQL-type Unicode Maximale lengte Python-type
char(n) Nee. 8,000 str
varchar(n) Nee. 8,000 str
varchar(max) Nee. 2 GB str
nchar(n) Yes 4,000 str
nvarchar(n) Yes 4,000 str
nvarchar(max) Yes 2 GB str
text Nee. 2 GB (verouderd) str
ntext Yes 2 GB (verouderd) str

Eenvoudige tekenreeksbewerkingen

De driver koppelt alle Microsoft SQL-stringtypes aan Python-objectenstr.

Tekenreeksen invoegen en ophalen

Gebruik geparametriseerde queries om stringgegevens veilig in te voegen en op te halen uit de database.

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'

Strings met speciale tekens

Behandel citaten, hoekhaken en andere speciale tekens in strings met behulp van geparametriseerde queries.

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

Gebruik nvarchar-kolommen en Python str om tekst in elke taal op te slaan en op te halen.

Opslaan Unicode-tekst

Voeg Unicode-inhoud in door Python-strings door te geven aan geparametriseerde queries; de driver codeert deze als UTF-16LE voor nvarchar-kolommen.

# 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 in verschillende schriften

Ondersteun meerdere talen en scripts in één tabel door gebruik te maken van nvarchar-kolommen en bulk-inserts.

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

Zorg voor nvarchar-kolommen voor Unicode

Definieer kolommen altijd als nvarchar in plaats van varchar wanneer je data niet-ASCII-tekens kan bevatten.

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

Overwegingen over snaarlengte

Kies tussen typen met vaste en variabele lengte op basis van hoe consistent je datalengtes zijn.

Vaste versus variabele lengte

char(n) van Microsoft SQL vult waarden op met afsluitende spaties tot de opgegeven lengte. Deze opvulling verspilt opslag voor data met variabele lengte, maar kan de prestaties verbeteren voor kolommen met vaste breedte, zoals landcodes. Gebruik varchar(n) voor de meeste stringkolommen.

Het volgende voorbeeld toont het verschil in hoe opgevulde versus niet-opgevulde kolommen omgaan met gegevensopvraging:

# 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

Afhandelen van afsluitende spaties

Wanneer u gegevens ophaalt uit char-kolommen met vaste lengte, gebruikt u rstrip() om de opvulspaties te verwijderen die door Microsoft SQL Server zijn toegevoegd.

# 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}'")

Grote snaren (MAX-typen)

De nvarchar(max) en varchar(max) types ondersteunen strings tot 2 GB, ideaal voor het opslaan van grote tekstdocumenten, JSON of XML-inhoud.

# 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

Snaarvergelijking en collatie

Het vergelijkingsgedrag van Microsoft SQL-strings hangt af van de collatieset op de database of kolom.

Hoofdlettergevoelig

Het vergelijken van tekenreeksen in Microsoft SQL is afhankelijk van de sortering. Standaard gebruiken de meeste databases een niet-hoofdlettergevoelige sortering, maar je kunt dit overschrijven met de COLLATE-clausule.

# 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"})

LIKE-patroonovereenkomst

Gebruik de LIKE operator met jokertekens om naar stringpatronen te zoeken; escape speciale tekens met haakjesnotatie om literals te matchen.

# 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)}%"})

Encoderingsoverwegingen

Het coderingsgedrag hangt af van het Microsoft SQL-kolomtype en de bron-collatie.

Codeeraannames en Unicode-standaardinstellingen

De mssql-python driver hanteert de codering automatisch op basis van het kolomtype Microsoft SQL. Standaard worden stringparameters verzonden als UTF-16LE voor nvarchar-kolommen en volgens de database-collatie voor varchar-kolommen:

Kolomtype Draadcodering Python-resultaat
nvarchar, nchar, ntext UTF-16LE str (gedecodeerd door de bestuurder)
varchar, char, text Database- of kolomcollatiecodering str (gedecodeerd door de driver met behulp van de broncodering)

Python-strings zijn intern altijd Unicode. Wanneer je een str parameter doorgeeft, codeert de driver deze voor het doelkolomtype. Standaard stuurt de driver stringparameters als nvarchar (Unicode), wat ervoor zorgt dat tekens behouden blijven ongeacht de database-collatie. Voor varchar kolommen geldt UTF-8 alleen wanneer de database of kolom een voor UTF-8 ingeschakelde sortering gebruikt.

Als je kolom van het type varchar is en je niet-Unicodegegevens moet verzenden zodat deze exact overeenkomen met het kolomtype (bijvoorbeeld om impliciete conversiewaarschuwingen te voorkomen), gebruik je setinputsizes() om de standaardinstelling te overschrijven:

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

Voor de meeste toepassingen is het standaardgedrag correct. Overschrijf dit alleen wanneer je impliciete conversiewaarschuwingen ziet in queryplannen of je overeen moet komen met een specifieke varchar-collatie.

Codering van de verbinding

De mssql-python-driver verzorgt automatisch de codering van de verbinding op basis van de Microsoft SQL Server-versie en configuratie. Omdat Python-strings Unicode zijn, codeert de driver ze passend (UTF-8 of UTF-16) voor het doeldatatype. Je hoeft de verbindingscodering niet handmatig te configureren.

VARCHAR-kolommen met verouderde sorteringen

Databases met Windows-1252 (CP1252) collaties, zoals Latin1_General_CI_AS, slaan uitgebreide Latijnse tekens op (bijvoorbeeld , , en geaccenteerde tekens) in varchar kolommen met CP1252-codering. De bestuurder decodeert deze tekens correct op alle platforms.

Dit verschil is belangrijk voor cross-platform implementaties: dezelfde varchar data die correct leest op Windows, leest ook correct op Linux, zonder speciale configuratie.

# 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

Als je schema het toelaat, voorkomt het migreren van varchar-kolommen naar nvarchar coderingsambiguïteit volledig en worden alle Unicode-tekens ondersteund.

Bestandscodering

Bij het lezen van bestanden om in de database in te voegen, specificeer dan de juiste codering om Unicode-inhoud te behouden.

# 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()

Algemene tekenreeksbewerkingen

Deze voorbeelden behandelen veelvoorkomende stringmanipulatiepatronen in zowel Python als SQL.

Samenvoegen

Je kunt strings aan elkaar zetten in Python voordat je ze invoegt of met behulp van SQL's stringoperatoren op de server.

# 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
""")

Tekenreeksopmaak

Pas opmaak toe in Python om strings met currency, padding of alignment weer te geven voordat je ze aan gebruikers toont.

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 versus lege tekenreeks

Microsoft SQL behandelt NULL en lege string ('') als verschillende waarden. NULL betekent "onbekend" terwijl lege string betekent "bekend als leeg." Kies één conventie voor je aanvraag en wees consistent. De meeste applicaties gebruiken NULL voor ontbrekende optionele velden.

Het volgende voorbeeld laat zien hoe je onderscheid kunt maken tussen NULL en lege string:

# 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 = ''")

Trimbewerkingen

Gebruik de stringmethoden van Python om witruimte aan het begin, aan het einde of beide te verwijderen uit waarden die uit de database zijn opgehaald.

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

Sla JSON-documenten op in nvarchar(max)-kolommen en raadpleeg deze met de JSON-functies van Microsoft SQL.

Sla JSON op als nvarchar

Serialiseer Python-woordenboeken naar JSON-strings en voeg ze in nvarchar-kolommen; haal ze op en deserialiseer ze terug in Python-objecten.

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'

Gebruik Microsoft SQL JSON-functies

Gebruik de JSON-functies van Microsoft SQL om JSON-gegevens direct in query's te parsen en te filteren in plaats van in clientcode.

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'

Gebruik LIKE het voor patroonmatching, of schakel een full-text index in voor geavanceerdere tekstzoekopdrachten.

Volledige tekst zoekopdrachten

De LIKE operator met wildcard-patronen biedt een eenvoudig alternatief voor full-text search wanneer er geen full-text index beschikbaar is.

# 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%"})

Beste praktijken

Pas deze richtlijnen toe om stringdata correct te verwerken tussen talen en coderingen.

Gebruik nvarchar voor internationale data

Als je niet zeker weet of een kolom Unicode kan bevatten, gebruik nvarchardan . De opslagkosten zijn bescheiden en voorkomen dataverlies door karakterconversie.

Het volgende voorbeeld toont het verschil tussen het definiëren van kolommen voor Unicode en alleen 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)
);

Controleer de lengte van de tekenreeks

Controleer de lengte van strings in Python voordat je invoegt om afkapfouten te voorkomen en betekenisvolle foutmeldingen aan gebruikers te geven.

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

Behandel binaire tekenreeksen afzonderlijk

Onderscheid tussen tekststrings (Pythonstr, SQLnvarchar) en binaire data (Pythonbytes, SQLvarbinary) om coderingsproblemen te voorkomen.

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