Menangani string dan Unicode

Microsoft SQL menyediakan beberapa jenis string yang dipetakan driver mssql-python ke objek Pythonstr. Keputusan utamanya adalah apakah akan menggunakan varchar (non-Unicode) atau nvarchar (Unicode):

  • Gunakan nvarchar saat data Anda mungkin berisi karakter di luar ASCII, seperti nama, alamat, atau konten buatan pengguna dalam bahasa apa pun.
  • Gunakan varchar saat data benar-benar hanya menggunakan ASCII (kode, pengenal, alamat email) dan Anda ingin menghemat ruang penyimpanan. varchar menggunakan 1 byte per karakter; nvarchar Menggunakan 2 byte per karakter.
Jenis SQL Ekasandi Panjang Maks Jenis Python
char(n) Tidak. 8.000 str
varchar(n) Tidak. 8.000 str
varchar(max) Tidak. 2 GB str
nchar(n) Yes 4,000 str
nvarchar(n) Yes 4,000 str
nvarchar(max) Yes 2 GB str
text Tidak. 2 GB (tidak digunakan lagi) str
ntext Yes 2 GB (tidak digunakan lagi) str

Operasi string dasar

Driver memetakan semua jenis string Microsoft SQL ke objek Pythonstr.

Menyisipkan dan mengambil string

Gunakan kueri berparameter untuk menyisipkan dan mengambil data string dengan aman dari 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'

String dengan karakter khusus

Tangani tanda kutip, tanda kurung sudut, dan karakter khusus lainnya dalam string menggunakan kueri berparameter.

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

Dukungan Unicode

Gunakan kolom nvarchar dan Python str untuk menyimpan dan mengambil teks dalam bahasa apa pun.

Menyimpan teks Unicode

Sisipkan konten Unicode dengan meneruskan string Python ke kueri berparameter; driver mengkodekannya sebagai UTF-16LE untuk kolom 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 dalam skrip yang berbeda

Mendukung beberapa bahasa dan skrip dalam satu tabel dengan menggunakan kolom nvarchar dan sisipan massal.

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

Pastikan menggunakan kolom nvarchar untuk data Unicode

Selalu tentukan kolom sebagai nvarchar, bukan varchar saat data Anda mungkin berisi karakter non-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
);

Pertimbangan panjang string

Pilih antara jenis panjang tetap dan panjang variabel berdasarkan seberapa konsisten panjang data Anda.

Panjang tetap versus variabel

char(n) di Microsoft SQL mengisi nilai dengan spasi tambahan di akhir hingga panjang yang ditentukan. Bantalan ini membuang-buang penyimpanan untuk data panjang variabel tetapi dapat meningkatkan performa untuk kolom lebar tetap, seperti kode negara. Gunakan varchar(n) untuk sebagian besar kolom string.

Contoh berikut menunjukkan perbedaan dalam cara kolom berlapis versus kolom yang tidak dilapisi menangani pengambilan data:

# 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

Tangani spasi di akhir

Saat mengambil data dari kolom char dengan panjang tetap, gunakan rstrip() untuk menghapus spasi padding yang ditambahkan oleh 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}'")

String besar (tipe MAX)

nvarchar(max) Jenis dan varchar(max) mendukung string hingga 2 GB, ideal untuk menyimpan dokumen teks besar, JSON, atau konten 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

Perbandingan dan kolasi string

Perilaku perbandingan string Microsoft SQL bergantung pada kumpulan kolase pada database atau kolom.

Peka huruf besar/kecil

Perbandingan string Microsoft SQL bergantung pada kolasi. Secara bawaan, sebagian besar basis data menggunakan kolasi yang tidak peka terhadap huruf besar/kecil, tetapi Anda dapat menggantinya dengan klausa 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"})

Pencocokan pola LIKE

Gunakan operator LIKE dengan karakter wildcard untuk mencari pola string; escape karakter khusus dengan notasi tanda kurung agar cocok dengan karakter literal.

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

Pertimbangan pengkodean

Perilaku pengodean bergantung pada jenis kolom Microsoft SQL dan penyusunan sumber.

Asumsi pengodean dan bawaan Unicode

mssql-python Driver menangani pengodean secara otomatis berdasarkan jenis kolom Microsoft SQL. Secara default, parameter string dikirim sebagai UTF-16LE untuk kolom nvarchar dan sesuai dengan kolase database untuk kolom varchar:

Jenis kolom Pengkodean kawat Hasil Python
nvarchar, nchar, ntext UTF-16LE str (didekodekan oleh driver)
varchar, char, text Pengodean kolasi basis data atau kolom str (didekodekan oleh driver menggunakan pengkodean sumber)

String dalam Python selalu berbentuk Unicode secara internal. Saat Anda meneruskan str parameter, driver mengkodekannya untuk jenis kolom target. Secara default, driver mengirimkan parameter string sebagai nvarchar (Unicode), yang memastikan karakter dipertahankan terlepas dari kolase database. Untuk varchar kolom, UTF-8 hanya berlaku ketika database atau kolom menggunakan kolase yang mendukung UTF-8.

Jika kolom Anda adalah varchar dan Anda perlu mengirim data non-Unicode agar cocok dengan jenis kolom secara persis (misalnya, untuk menghindari peringatan konversi implisit), gunakan setinputsizes() untuk mengganti default:

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

Untuk sebagian besar aplikasi, perilaku defaultnya benar. Ganti hanya jika Anda melihat peringatan konversi implisit dalam rencana kueri atau perlu mencocokkan kolase tertentu varchar .

Pengkodean koneksi

Driver mssql-python secara otomatis menangani pengodean untuk koneksi berdasarkan versi dan konfigurasi Microsoft SQL Server. Karena string Python adalah Unicode, driver mengkodekannya dengan tepat (UTF-8 atau UTF-16) untuk tipe data target. Anda tidak perlu mengonfigurasi pengodean koneksi secara manual.

Kolom VARCHAR dengan kolasi lama

Basis data dengan kolasi Windows-1252 (CP1252), seperti Latin1_General_CI_AS, menyimpan karakter Latin yang diperluas (misalnya, , , dan karakter beraksen) dalam kolom varchar menggunakan pengodean CP1252. Driver memecahkan kode karakter ini dengan benar di semua platform.

Perbedaan ini penting untuk penyebaran lintas platform: data yang sama varchar yang dibaca dengan benar di Windows juga dibaca dengan benar di Linux, tanpa konfigurasi khusus yang diperlukan.

# 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

Jika skema Anda memungkinkan, migrasi varchar kolom untuk nvarchar menghindari pengkodean ambiguitas sepenuhnya dan mendukung semua karakter Unicode.

Pengkodean berkas

Saat membaca file untuk dimasukkan ke dalam database, tentukan pengodean yang sesuai untuk mempertahankan konten 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()

Operasi string umum

Contoh-contoh ini mencakup pola manipulasi string umum di Python dan SQL.

Penggabungan

Anda dapat menggabungkan string baik di Python sebelum menyisipkan atau menggunakan operator string SQL di 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
""")

Pemformatan string

Terapkan pemformatan di Python untuk menampilkan string dalam format mata uang, dengan spasi tambahan, atau perataan sebelum ditampilkan kepada pengguna.

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 dibandingkan dengan string kosong

Microsoft SQL memperlakukan NULL dan string kosong ('') sebagai nilai yang berbeda. NULL berarti "tidak diketahui" sedangkan string kosong berarti "diketahui kosong". Pilih satu konvensi untuk aplikasi Anda dan konsisten. Sebagian besar aplikasi menggunakan NULL untuk bidang opsional yang hilang.

Contoh berikut menunjukkan cara membedakan antara NULL dan string kosong:

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

Operasi pemangkasan

Gunakan metode string Python untuk menghapus spasi di awal, di akhir, atau keduanya dari nilai yang diambil dari basis data.

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

Data string JSON

Simpan dokumen JSON di kolom nvarchar(max) dan kueri dengan fungsi JSON Microsoft SQL.

Simpan JSON sebagai nvarchar

Serialisasi kamus Python ke string JSON dan sisipkan ke dalam kolom nvarchar; ambil dan deserialisasikan kembali ke objek 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'

Menggunakan fungsi JSON Microsoft SQL

Gunakan fungsi JSON Microsoft SQL untuk mengurai dan memfilter data JSON secara langsung dalam kueri, bukan dalam kode klien.

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'

Gunakan LIKE untuk pencocokan pola, atau aktifkan indeks teks lengkap untuk pencarian teks yang lebih lanjut.

Kueri teks lengkap

Operator LIKE dengan pola karakter pengganti memberikan alternatif langsung untuk penelusuran teks lengkap saat indeks teks lengkap tidak tersedia.

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

Praktik terbaik

Terapkan panduan ini untuk menangani data string dengan benar di seluruh bahasa dan pengkodean.

Gunakan nvarchar untuk data internasional

Jika Anda tidak yakin apakah kolom mungkin berisi Unicode, gunakan nvarchar. Biaya penyimpanannya sederhana dan mencegah kehilangan data dari konversi karakter.

Contoh berikut menunjukkan perbedaan antara menentukan kolom untuk Unicode dan data khusus 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)
);

Memvalidasi panjang string

Periksa panjang string di Python sebelum menyisipkan untuk mencegah kesalahan pemotongan dan memberikan pesan kesalahan yang bermakna kepada pengguna.

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

Menangani string biner secara terpisah

Bedakan antara string teks (Python str, SQL nvarchar) dan data biner (Python bytes, SQL varbinary) untuk menghindari masalah pengkodean.

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