Processar cadeias de caracteres e Unicode

O Microsoft SQL fornece vários tipos de strings que o driver mssql-python mapeia para objetos Pythonstr. A decisão chave é se deve usar varchar (não-Unicode) ou nvarchar (Unicode):

  • Use nvarchar quando os seus dados possam conter caracteres fora do ASCII, como nomes, endereços ou conteúdo gerado pelos utilizadores em qualquer língua.
  • Use varchar quando os dados forem estritamente ASCII (códigos, identificadores, endereços de email) e quiser poupar armazenamento. varchar usa 1 byte por carácter; nvarchar Usa 2 bytes por carácter.
Tipo SQL Unicode Comprimento máximo Tipo Python
char(n) No 8,000 str
varchar(n) No 8,000 str
varchar(max) No 2 GB str
nchar(n) Sim 4,000 str
nvarchar(n) Sim 4,000 str
nvarchar(max) Sim 2 GB str
text No 2 GB (descontinuado) str
ntext Sim 2 GB (descontinuado) str

Operações básicas de cadeia de caracteres

O driver mapeia todos os tipos de strings Microsoft SQL para objetos Pythonstr.

Inserir e recuperar cadeias de caracteres

Use consultas parametrizadas para inserir e obter dados de cadeia de caracteres da base de dados com segurança.

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'

Cadeias com caracteres especiais

Trate aspas, colchetes angulares e outros caracteres especiais em strings usando consultas parametrizadas.

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

Suporte a Unicode

Use colunas nvarchar e Python str para armazenar e recuperar texto em qualquer linguagem.

Armazenar texto Unicode

Insira conteúdo Unicode ao passar cadeias de caracteres Python para consultas com parâmetros; o controlador codifica-as como UTF-16LE nas colunas nvarchar.

# 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 em diferentes sistemas de escrita

Suportar vários idiomas e sistemas de escrita numa única tabela utilizando colunas do tipo nvarchar e inserções em massa.

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

Garantir colunas nvarchar para Unicode

Defina sempre as colunas como nvarchar em vez de varchar quando os seus dados possam conter caracteres não ASCII.

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

Considerações sobre o comprimento das cordas

Escolha entre tipos de comprimento fixo e de comprimento variável com base na consistência dos seus comprimentos de dados.

Comprimento fixo versus variável

O Microsoft SQL preenche os valores com espaços à direita até ao comprimento declarado. Este enchimento desperdiça armazenamento para dados de comprimento variável, mas pode melhorar o desempenho para colunas de largura fixa, como códigos de país. Utilize varchar(n) para a maioria das colunas de cadeias de caracteres.

O exemplo seguinte mostra a diferença na forma como colunas preenchidas e não acolchoadas lidam com a recuperação de dados:

# 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

Tratar espaços à direita

Ao recuperar dados de colunas de caracteres de comprimento fixo, use rstrip() para remover os espaços de enchimento adicionados pelo 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}'")

Cadeias de caracteres grandes (tipos MAX)

Os tipos nvarchar(max) e varchar(max) suportam cadeias de caracteres com até 2 GB, ideais para armazenar documentos de texto extensos, conteúdo JSON ou XML.

# 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

Comparação e colação de cordas

O comportamento de comparação de strings SQL do Microsoft depende do conjunto de colações na base de dados ou coluna.

Sensível às maiúsculas e minúsculas

A comparação de strings no Microsoft SQL depende da intercalação. Por predefinição, a maioria das bases de dados usa ordenação sem distinção entre maiúsculas e minúsculas, mas pode alterar este comportamento com a cláusula 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"})

Correspondência de padrões com LIKE

Use o LIKE operador com caracteres coringa para procurar padrões de cadeia; escape caracteres especiais com notação de parênteses para corresponder literais.

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

Considerações de codificação

O comportamento da codificação depende do tipo da coluna do Microsoft SQL e da ordenação de origem.

Suposições de codificação e padrões Unicode

O mssql-python driver gere a codificação automaticamente com base no tipo de coluna Microsoft SQL. Por defeito, os parâmetros de cadeia de caracteres são enviados como UTF-16LE para colunas nvarchar e de acordo com o agrupamento da base de dados para colunas varchar:

Tipo de coluna Codificação por fio Resultado em Python
nvarchar, nchar, ntext UTF-16LE str (decifrado pelo condutor)
varchar, char, text Codificação do agrupamento da base de dados ou da coluna str (decodificado pelo driver usando a codificação de origem)

As strings Python são sempre Unicode internamente. Quando passa um str parâmetro, o driver codifica-o para o tipo de coluna alvo. Por defeito, o driver envia parâmetros de cadeia como nvarchar (Unicode), o que garante que os caracteres são preservados independentemente da ordenação da base de dados. Nas colunas varchar, o UTF-8 só se aplica quando a base de dados ou a coluna utiliza uma ordenação com suporte para UTF-8.

Se a sua coluna for varchar e precisar de enviar dados não-Unicode para corresponder exatamente ao tipo de coluna (por exemplo, para evitar avisos implícitos de conversão), use setinputsizes() para sobrepor o padrão:

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

Para a maioria das aplicações, o comportamento padrão está correto. Anule apenas quando vir avisos implícitos de conversão nos planos de consulta ou precisar de corresponder a uma colação específica varchar .

Codificação de ligação

O driver mssql-python trata automaticamente da codificação da ligação com base na versão e configuração do Microsoft SQL Server. Como as strings de Python são Unicode, o driver codifica-as adequadamente (UTF-8 ou UTF-16) para o tipo de dado alvo. Não precisas de configurar manualmente a codificação da ligação.

Colunas VARCHAR com ordenações legadas

Bases de dados com colações Windows-1252 (CP1252), como Latin1_General_CI_AS, armazenam caracteres latinos estendidos (por exemplo, , , e caracteres acentuados) em varchar colunas usando a codificação CP1252. O driver decodifica corretamente estes caracteres em todas as plataformas.

Esta diferença é importante para implementações multiplataforma: os mesmos varchar dados que lêem corretamente no Windows também são lidos corretamente no Linux, sem necessidade de configuração especial.

# 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

Se o seu esquema permitir, migrar varchar colunas para nvarchar evita completamente ambiguidade de codificação e suporta todos os caracteres Unicode.

Codificação de ficheiros

Ao ler ficheiros para inserir na base de dados, especifique a codificação apropriada para preservar o conteúdo Unicode.

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

Operações comuns com cadeias de caracteres

Estes exemplos abrangem padrões comuns de manipulação de strings tanto em Python como em SQL.

Concatenação

Podes concatenar strings em Python antes de inserir ou usar os operadores de strings do SQL no servidor.

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

Formatação de cadeia de caracteres

Aplique formatação em Python para apresentar cadeias de caracteres com valores monetários, preenchimento ou alinhamento antes de as apresentar aos utilizadores.

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

O Microsoft SQL trata NULL e string vazio ('') como valores diferentes. NULL significa "desconhecido", enquanto cadeia vazia significa "conhecida por ser vazia". Escolha uma convenção para a sua candidatura e seja consistente. A maioria das aplicações usa NULL para campos opcionais em falta.

O exemplo seguinte demonstra como distinguir entre NULL e cadeia vazia:

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

Operações de recorte

Utilize os métodos de string do Python para remover espaços em branco iniciais, posteriores ou ambos dos valores recuperados da base de dados.

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

Dados de cadeia de caracteres JSON

Armazene documentos JSON em colunas nvarchar(max) e interrogue-os com as funções JSON do Microsoft SQL.

Armazenar JSON como nvarchar

Serializar dicionários Python para cadeias JSON e inseri-los em colunas nvarchar; recuperá-los e desserializá-los de volta para objetos Python.

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'

Utilizar funções JSON SQL do Microsoft

Use as funções JSON do Microsoft SQL para analisar e filtrar dados JSON diretamente em consultas, em vez de no código do cliente.

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'

Use LIKE para correspondência de padrões, ou ative um índice de texto completo para pesquisa de texto mais avançada.

Pesquisas de texto completo

O LIKE operador com padrões de wildcard oferece uma alternativa direta à pesquisa em texto completo quando não existe um índice em texto completo disponível.

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

Melhores práticas

Aplique estas diretrizes para lidar corretamente com dados de cadeia entre línguas e codificações.

Use nvarchar para dados internacionais

Se não tiver a certeza se uma coluna pode conter Unicode, use nvarchar. O custo de armazenamento é modesto e previne a perda de dados devido à conversão de caracteres.

O exemplo seguinte mostra a diferença entre definir colunas para dados Unicode e apenas ASCII:

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

Validar o comprimento da cadeia de caracteres

Verifique o comprimento da string em Python antes de inserir para evitar erros de truncamento e fornecer mensagens de erro significativas aos utilizadores.

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

Tratar as cadeias binárias separadamente

Distingue entre cadeias de texto (Pythonstr, SQLnvarchar) e dados binários (Pythonbytes, SQLvarbinary) para evitar problemas de codificação.

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