Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
SQL NULL repräsentiert fehlende oder unbekannte Daten. Der mssql-python-Treiber ordnet SQL NULL Python None zu. Die Unterscheidung ist wichtig, weil NULL nichts bedeutet, auch nicht sich selbst. In SQL wird NULL = NULL zu NULL (unbekannt) ausgewertet, nicht zu wahr. Verwenden Sie daher IS NULL in Abfragen und is None in Python.
NULL-Werte empfangen
NULL in den Abrufergebnissen
Der Treiber liefert NULL-Werte aus SQL Server als Python Nonezurück:
import mssql_python
conn = mssql_python.connect(connection_string)
cursor = conn.cursor()
cursor.execute(
"SELECT TOP 1 FirstName, MiddleName, LastName "
"FROM Person.Person WHERE MiddleName IS NULL"
)
row = cursor.fetchone()
print(row.FirstName) # First name value
print(row.MiddleName) # None (NULL in database)
print(row.LastName) # Last name value
Prüfe auf NULL-Werte
Überprüfen Sie beim Durchlaufen der Ergebnisse mit dem is-Operator, ob ein Wert None ist:
cursor.execute(
"SELECT FirstName, MiddleName, LastName FROM Person.Person WHERE BusinessEntityID <= 10"
)
for row in cursor:
if row.MiddleName is None:
print(f"{row.FirstName} {row.LastName}: No middle name")
else:
print(f"{row.FirstName} {row.MiddleName} {row.LastName}")
Verwenden Sie is None anstelle von == None
Immer für NULL-Prüfungen verwenden is None . Der Operator is prüft die Identität (ob der Wert genau None ist), während ==__eq__ aufruft und bei benutzerdefinierten Objekten zu unerwarteten Ergebnissen führen kann:
# Correct
if row.MiddleName is None:
full_name = f"{row.FirstName} {row.LastName}"
# Avoid (works but not idiomatic)
if row.MiddleName == None:
full_name = f"{row.FirstName} {row.LastName}"
Senden Sie NULL-Werte
Fügen Sie NULL mit „None“ ein
Um NULL-Werte einzufügen, geben Sie None ein:
cursor.execute(
"CREATE TABLE #NullInsertDemo "
"(Name NVARCHAR(50), Email NVARCHAR(100), Phone NVARCHAR(20))"
)
cursor.execute(
"INSERT INTO #NullInsertDemo (Name, Email, Phone) "
"VALUES (%(name)s, %(email)s, %(phone)s)",
{"name": "Alice", "email": None, "phone": "555-1234"}
)
conn.commit()
Update auf NULL
Setzen Sie eine Spalte auf NULL, indem Sie die folgenden Parameter eingeben None :
cursor.execute(
"CREATE TABLE #UpdateDemo (ID INT, Email NVARCHAR(100))"
)
cursor.execute("INSERT INTO #UpdateDemo VALUES (100, 'old@example.com')")
cursor.execute(
"UPDATE #UpdateDemo SET Email = %(email)s WHERE ID = %(id)s",
{"email": None, "id": 100}
)
conn.commit()
Bedingte NULL-Behandlung
Definieren Sie Funktionen, die optionale Parameter verarbeiten, indem Sie sie auf None setzen, wenn sie nicht bereitgestellt werden:
def update_record(cursor, record_id: int, name: str, email: str | None = None):
"""Update record, setting email to NULL if not provided."""
cursor.execute(
"UPDATE #Records SET Name = %(name)s, Email = %(email)s "
"WHERE ID = %(id)s",
{"name": name, "email": email, "id": record_id}
)
NULL in WHERE-Klauseln
IS NULL in Abfragen
Verwendung IS NULL in SQL für NULL-Vergleiche:
# Find people without a middle name
cursor.execute("SELECT FirstName FROM Person.Person WHERE MiddleName IS NULL")
# Find people with a middle name
cursor.execute("SELECT FirstName FROM Person.Person WHERE MiddleName IS NOT NULL")
Dynamische NULL-Handhabung
Wenn ein Parameter NULL sein könnte, verwenden Sie bedingte Logik, um die entsprechende Abfrage zu konstruieren:
def find_people(cursor, middle_name: str | None = None):
"""Find people, optionally filtering by middle name."""
if middle_name is None:
# Find people with NULL middle name
cursor.execute("SELECT * FROM Person.Person WHERE MiddleName IS NULL")
else:
# Find people with specific middle name
cursor.execute(
"SELECT * FROM Person.Person WHERE MiddleName = %(middle_name)s",
{"middle_name": middle_name},
)
return cursor.fetchall()
COALESCE zur Ersetzung von NULL
Verwenden Sie COALESCE, um NULL-Werte auf SQL-Ebene durch Standardwerte zu ersetzen.
COALESCE ist effizienter, als in Python auf None zu prüfen, weil die Substitution auf dem Server erfolgt und dadurch der Umfang bedingter Logik in Ihrer Anwendung verringert wird:
cursor.execute("""
SELECT
FirstName,
COALESCE(MiddleName, '(none)') AS MiddleName,
COALESCE(Suffix, 'N/A') AS Suffix
FROM Person.Person
WHERE BusinessEntityID <= 10
""")
for row in cursor:
# MiddleName and Suffix will never be None
print(f"{row.FirstName}: {row.MiddleName}, {row.Suffix}")
NULL-sichere Operationen
Standardwerte in Python
cursor.execute("SELECT TOP 10 Name, Color FROM Production.Product")
for row in cursor:
# Use or to provide default
color = row.Color or "No color"
print(f"{row.Name}: {color}")
NULL-Werte formatieren
def format_address(row):
"""Format address handling NULL components."""
parts = [
row.AddressLine1,
row.AddressLine2,
row.City,
row.PostalCode,
]
# Filter out None values
return ", ".join(str(p) for p in parts if p is not None)
cursor.execute(
"SELECT TOP 10 AddressLine1, AddressLine2, City, PostalCode "
"FROM Person.Address"
)
for row in cursor:
print(format_address(row))
NULL in Aggregationen
SQL-Aggregatfunktionen behandeln NULL-Werte anders, als man vielleicht erwarten würde.
COUNT(column) zählt nur nicht-NULL-Werte, während COUNT(*) alle Zeilen zählt.
AVG, SUM, , MINund MAX alle ignorieren NULL-Werte. Wenn jeder Wert in der Spalte NULL ist, geben diese Funktionen NULL (nicht null) zurück.
# COUNT excludes NULL values
cursor.execute("SELECT COUNT(Color) FROM Production.Product") # Counts non-NULL colors
color_count = cursor.fetchval()
# COUNT(*) includes all rows
cursor.execute("SELECT COUNT(*) FROM Production.Product") # Counts all products
total_count = cursor.fetchval()
# AVG ignores NULL
cursor.execute("SELECT AVG(Weight) FROM Production.Product") # Average of non-NULL weights
average_weight = cursor.fetchval()
NULL bei Datentypen
NULL-Numerische Werte
from decimal import Decimal
cursor.execute("SELECT ListPrice FROM Production.Product WHERE ProductID = 1")
row = cursor.fetchone()
# Check before arithmetic
if row.ListPrice is not None:
tax = row.ListPrice * Decimal("0.08")
total = row.ListPrice + tax
else:
total = Decimal("0")
NULL-Datumswerte
Prüfen Sie, ob eine Datumsspalte vorhanden ist None , bevor Sie sie für Vergleiche oder Berechnungen verwenden:
from datetime import date
cursor.execute("SELECT Name, SellEndDate FROM Production.Product WHERE ProductID <= 10")
for row in cursor:
if row.SellEndDate is None:
print(f"{row.Name}: Currently selling")
else:
print(f"{row.Name}: Discontinued on {row.SellEndDate}")
NULL-String-Werte
Behandeln Sie NULL-Zeichenfolgenspalten, indem Sie sie vor der Verkettung auf None prüfen:
cursor.execute(
"SELECT TOP 10 FirstName, MiddleName, LastName FROM Person.Person"
)
for row in cursor:
# Build full name, handling NULL middle name
if row.MiddleName:
full_name = f"{row.FirstName} {row.MiddleName} {row.LastName}"
else:
full_name = f"{row.FirstName} {row.LastName}"
print(full_name)
Massenvorgänge mit NULL
executemany mit NULL-Werten
Bei Verwendung von executemany() übergib None in Wörterbüchern für Spalten, die auf NULL gesetzt werden sollen:
users = [
{"name": "Alice", "title": "Ms.", "suffix": "Jr."},
{"name": "Bob", "title": None, "suffix": "Sr."}, # NULL title
{"name": "Carol", "title": "Dr.", "suffix": None}, # NULL suffix
]
cursor.executemany(
"SELECT FirstName FROM Person.Person WHERE FirstName = %(name)s",
users
)
Massenkopieren mit NULL
Massenkopieroperationen bewahren NULL-Werte aus Ihren Datenstrukturen:
cursor = conn.cursor()
cursor.execute("CREATE TABLE ##NullDemo (Name NVARCHAR(50), Email NVARCHAR(100), Phone NVARCHAR(20))")
conn.commit()
data = [
("Alice", "alice@example.com", "555-0001"),
("Bob", None, "555-0002"), # NULL Email
("Carol", "carol@example.com", None), # NULL Phone
]
result = cursor.bulkcopy("##NullDemo", data)
conn.commit()
print(f"Copied {result['rows_copied']} rows")
Allgemeine Muster
Optionale Feldverarbeitung
Verwenden Sie Typhinweise, um zu verdeutlichen, welche Felder beim Abbilden von Zeilen auf Datenklassen NULL sein können:
from dataclasses import dataclass
from typing import Optional
@dataclass
class PersonRecord:
business_entity_id: int
first_name: str
middle_name: Optional[str] = None
suffix: Optional[str] = None
def fetch_person(cursor, person_id: int) -> Optional[PersonRecord]:
cursor.execute(
"SELECT BusinessEntityID, FirstName, MiddleName, Suffix "
"FROM Person.Person WHERE BusinessEntityID = %(id)s",
{"id": person_id},
)
row = cursor.fetchone()
if row is None:
return None
return PersonRecord(
business_entity_id=row.BusinessEntityID,
first_name=row.FirstName,
middle_name=row.MiddleName, # Will be None if NULL
suffix=row.Suffix, # Will be None if NULL
)
JSON-Serialisierung mit NULL
Python-Werte None werden bei Verwendung des json-Moduls automatisch in JSON null konvertiert:
import json
cursor.execute(
"SELECT TOP 5 BusinessEntityID, FirstName, MiddleName FROM Person.Person"
)
rows = cursor.fetchall()
# Convert to JSON-serializable list
people = []
for row in rows:
people.append({
"id": row.BusinessEntityID,
"name": row.FirstName,
"middle_name": row.MiddleName, # None becomes null in JSON
})
json_output = json.dumps(people, indent=2)
print(json_output)
# [
# {"id": 1, "name": "Ken", "middle_name": "J"},
# {"id": 3, "name": "Roberto", "middle_name": null}
# ]
Wörterbuch mit NULL-Filterung
Wählen Sie aus, NULL-Werte beim Umwandeln von Zeilen in Wörterbücher auszuschließen:
def row_to_dict(row, cursor) -> dict:
"""Convert row to dict, optionally excluding NULL values."""
columns = [col[0] for col in cursor.description]
return {col: val for col, val in zip(columns, row) if val is not None}
cursor.execute("SELECT * FROM Person.Person WHERE BusinessEntityID = 1")
row = cursor.fetchone()
person_dict = row_to_dict(row, cursor)
# Only includes non-NULL columns
NULL in DataFrames
Wenn du mit Pandas oder Polars DataFrames arbeitest, musst du besonders auf Nullwerte achten, da diese Bibliotheken ihre eigenen Sentinel-Werte verwenden.
Pandas NaN und NaT
pandas verwendet NaN (Keine Zahl) für fehlende Zahlen- und Zeichenkettenwerte und NaT (Keine Zeit) für fehlende Datumszeitwerte. Keiner der beiden Werte ist derselbe wie bei PythonNone:
import pandas as pd
import numpy as np
# When reading SQL results into pandas, NULL becomes NaN or NaT
cursor.execute("SELECT Name, Weight, SellEndDate FROM Production.Product")
table = cursor.arrow()
df = table.to_pandas()
# Check for missing values (covers NaN, NaT, and None)
print(df["Weight"].isna().sum()) # Count of NULL weights
print(df["SellEndDate"].isna().sum()) # Count of NULL dates
# Stage the data in a temp table to avoid mutating the source table
cursor.execute("CREATE TABLE #ProductWeights (Name NVARCHAR(100), Weight DECIMAL(8, 2) NULL)")
# Convert NaN back to None so NULL values round-trip correctly
for _, row in df.iterrows():
weight = None if pd.isna(row["Weight"]) else float(row["Weight"])
cursor.execute(
"INSERT INTO #ProductWeights (Name, Weight) VALUES (%(name)s, %(weight)s)",
{"name": row["Name"], "weight": weight}
)
Warning
Vergleiche nicht mit == np.nan oder == pd.NaT. Diese Vergleiche ergeben immer False. Verwenden Sie stattdessen pd.isna() oder pd.notna().
Umgang mit Nullwerten in Polars
Polars verwendet seinen eigenen null Wert (nicht NaN), der direkt auf Python Noneabgebildet wird:
import polars as pl
cursor.execute("SELECT Name, Weight, Color FROM Production.Product")
table = cursor.arrow()
df = pl.from_arrow(table)
# Filter rows with non-null values
has_weight = df.filter(pl.col("Weight").is_not_null())
# Replace null with a default
df = df.with_columns(pl.col("Color").fill_null("No color"))