Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Microsoft SQL 2016 ve daha sonraki sürümler ile Azure SQL, sütunlar üzerinde nvarchar çalışan fonksiyonlar aracılığıyla JSON desteği sağlar. mssql-python sürücüsü, JSON'u normal Python dizeleri olarak gönderir ve alır. Şunları yapabilirsiniz:
- JSON verilerini
nvarcharsütunlarda dize olarak sakla. -
JSON_VALUE,JSON_QUERYveOPENJSONkullanarak JSON’u yol ifadeleriyle sorgulayın. - İlişkisel veriyi JSON'a dönüştürün .
FOR JSON - JSON'u ilişkisel formata ile
OPENJSONayrıştırın.
Note
Microsoft SQL, JSON verilerini ayrı bir JSON sütun türünde değil, nvarchar sütunlarında depolar. mssql-python sürücüsü, JSON'u normal dizi olarak gönderir ve alır. İstemci tarafında serileştirmek ve seri durumdan çıkarmak için Python'un yerleşik json modülünü kullanın.
JSON verilerini sakla
Python dict'lerini, nvarchar sütunlarına yerleştirmeden önce dizelere serileştirin json.dumps()
JSON dizisi ekleyin
Bir Python sözlüğünü JSON metni olarak bir veritabanı tablosunda depolayın:
import json
import mssql_python
conn = mssql_python.connect(
"Server=<server>.database.windows.net;"
"Database=<database>;"
"Authentication=ActiveDirectoryDefault;"
"Encrypt=yes"
)
cursor = conn.cursor()
# Create table with JSON column
cursor.execute("""
CREATE TABLE #JsonProducts (
ProductID INT IDENTITY PRIMARY KEY,
Name NVARCHAR(100),
JsonData NVARCHAR(MAX)
)
""")
# Python dict to JSON string
product_data = {
"name": "Widget Pro",
"specs": {
"weight": 2.5,
"dimensions": {"width": 10, "height": 5, "depth": 3}
},
"tags": ["electronics", "gadgets", "bestseller"]
}
cursor.execute("""
INSERT INTO #JsonProducts (Name, JsonData)
VALUES (%(name)s, %(json)s)
""", {"name": "Widget Pro", "json": json.dumps(product_data)})
conn.commit()
JSON'u insert üzerinde doğrulama
Eklemeden önce JSON sözdizimini doğrulamak için fonksiyonu ISJSON() kullanın:
data = {"name": "Widget", "specs": {"weight": 1.5}}
cursor.execute("""
CREATE TABLE #JsonValidate (
ProductID INT IDENTITY, Name NVARCHAR(100), JsonData NVARCHAR(MAX)
)
""")
cursor.execute("""
INSERT INTO #JsonValidate (Name, JsonData)
SELECT %(name)s, %(json)s
WHERE ISJSON(%(json)s) = 1
""", {"name": "Widget", "json": json.dumps(data)})
if cursor.rowcount == 0:
raise ValueError("Invalid JSON data")
JSON verilerini sorgulama
Sunucudaki değerleri çıkarmadan önce istemciye geri göndermek için Microsoft SQL JSON yol fonksiyonlarını kullanın.
Skalar değerleri ayıkla
Tek değerleri çıkarmak için kullanılır JSON_VALUE :
# Create table with sample JSON data
cursor.execute("""
CREATE TABLE #JsonExtract (
ProductID INT IDENTITY, Name NVARCHAR(100), JsonData NVARCHAR(MAX)
)
""")
cursor.execute("""
INSERT INTO #JsonExtract (Name, JsonData) VALUES (
'Widget Pro',
'{"name":"Widget Pro","specs":{"weight":2.5,"dimensions":{"width":10,"height":5,"depth":3}},"tags":["electronics","gadgets"]}'
)
""")
cursor.execute("""
SELECT
Name,
JSON_VALUE(JsonData, '$.specs.weight') AS Weight,
JSON_VALUE(JsonData, '$.specs.dimensions.width') AS Width
FROM #JsonExtract
WHERE JSON_VALUE(JsonData, '$.name') = %(name)s
""", {"name": "Widget Pro"})
row = cursor.fetchone()
print(f"Weight: {row.Weight}, Width: {row.Width}")
Nesneleri veya dizileri çıkarma
Nesneler ve diziler için JSON_QUERY kullanın.
cursor.execute("""
CREATE TABLE #JsonQuery (
ProductID INT IDENTITY, Name NVARCHAR(100), JsonData NVARCHAR(MAX)
)
""")
cursor.execute("""
INSERT INTO #JsonQuery (Name, JsonData) VALUES (
'Widget Pro',
'{"specs":{"weight":2.5,"color":"blue"},"tags":["electronics","gadgets"]}'
)
""")
cursor.execute("""
SELECT
Name,
JSON_QUERY(JsonData, '$.specs') AS Specs,
JSON_QUERY(JsonData, '$.tags') AS Tags
FROM #JsonQuery
""")
for row in cursor:
specs = json.loads(row.Specs) if row.Specs else {}
tags = json.loads(row.Tags) if row.Tags else []
print(f"{row.Name}: {specs}, Tags: {tags}")
JSON dizisi sıralara ayrıştır
Bir JSON dizisini şu şekilde satırlara OPENJSONgenişletin:
cursor.execute("""
CREATE TABLE #JsonArray (
ProductID INT IDENTITY, Name NVARCHAR(100), JsonData NVARCHAR(MAX)
)
""")
cursor.execute("""
INSERT INTO #JsonArray (Name, JsonData) VALUES
('Widget Pro', '{"tags":["electronics","gadgets","bestseller"]}'),
('Gadget X', '{"tags":["tools","gadgets"]}')
""")
cursor.execute("""
SELECT p.Name, t.value AS Tag
FROM #JsonArray p
CROSS APPLY OPENJSON(p.JsonData, '$.tags') t
""")
for row in cursor:
print(f"Product: {row.Name}, Tag: {row.Tag}")
JSON nesnesini sütunlara ayrıştır
JSON nesnelerinden tek tek alanları JSON_VALUE() kullanarak ayıklayın ve sonuçları uygun SQL türlerine dönüştürün.
cursor.execute("""
CREATE TABLE #JsonCols (
ProductID INT IDENTITY, Name NVARCHAR(100), JsonData NVARCHAR(MAX)
)
""")
cursor.execute("""
INSERT INTO #JsonCols (Name, JsonData) VALUES (
'Widget Pro',
'{"name":"Widget Pro","specs":{"weight":2.5,"dimensions":{"width":10,"height":5}}}'
)
""")
cursor.execute("""
SELECT
p.ProductID,
j.name AS ProductName,
j.weight,
j.width,
j.height
FROM #JsonCols p
CROSS APPLY OPENJSON(p.JsonData)
WITH (
name NVARCHAR(100) '$.name',
weight DECIMAL(5,2) '$.specs.weight',
width INT '$.specs.dimensions.width',
height INT '$.specs.dimensions.height'
) j
""")
JSON verilerini değiştir
Bir JSON belgesinde belirli bir yolu tüm değeri yeniden yazmadan güncellemek için kullanın JSON_MODIFY .
JSON değerini güncelleme
Tek bir JSON özelliğini şu JSON_MODIFYşekilde değiştirin:
cursor.execute("""
CREATE TABLE #JsonMod (
ProductID INT IDENTITY, Name NVARCHAR(100), JsonData NVARCHAR(MAX)
)
""")
cursor.execute("""
INSERT INTO #JsonMod (Name, JsonData) VALUES (
'Widget Pro',
'{"specs":{"weight":2.5,"dimensions":{"width":10}},"tags":["electronics"]}'
)
""")
cursor.execute("""
UPDATE #JsonMod
SET JsonData = JSON_MODIFY(JsonData, '$.specs.weight', %(weight)s)
WHERE ProductID = %(id)s
""", {"weight": 3.0, "id": 1})
conn.commit()
JSON özelliğini ekleyin
Mevcut bir JSON nesnesine yeni bir özellik ekleyin:
cursor.execute("""
CREATE TABLE #JsonAdd (
ProductID INT IDENTITY, Name NVARCHAR(100), JsonData NVARCHAR(MAX)
)
""")
cursor.execute("""
INSERT INTO #JsonAdd (Name, JsonData) VALUES (
'Widget Pro', '{"specs":{"weight":2.5}}'
)
""")
cursor.execute("""
UPDATE #JsonAdd
SET JsonData = JSON_MODIFY(JsonData, '$.specs.color', %(color)s)
WHERE ProductID = %(id)s
""", {"color": "blue", "id": 1})
JSON özelliğini kaldırın
Bir JSON nesnesinden bir özelliği şu şekilde NULLayarlayarak silin:
cursor.execute("""
CREATE TABLE #JsonRem (
ProductID INT IDENTITY, Name NVARCHAR(100), JsonData NVARCHAR(MAX)
)
""")
cursor.execute("""
INSERT INTO #JsonRem (Name, JsonData) VALUES (
'Widget Pro', '{"specs":{"weight":2.5,"color":"blue"}}'
)
""")
cursor.execute("""
UPDATE #JsonRem
SET JsonData = JSON_MODIFY(JsonData, '$.specs.color', NULL)
WHERE ProductID = %(id)s
""", {"id": 1})
JSON array'a ekle
JSON_MODIFY içinde, append yönergesini kullanarak bir JSON dizisinin sonuna yeni bir değer ekleyin:
cursor.execute("""
CREATE TABLE #JsonAppend (
ProductID INT IDENTITY, Name NVARCHAR(100), JsonData NVARCHAR(MAX)
)
""")
cursor.execute("""
INSERT INTO #JsonAppend (Name, JsonData) VALUES (
'Widget Pro', '{"tags":["electronics","gadgets"]}'
)
""")
cursor.execute("""
UPDATE #JsonAppend
SET JsonData = JSON_MODIFY(
JsonData,
'append $.tags',
%(tag)s
)
WHERE ProductID = %(id)s
""", {"tag": "new-arrival", "id": 1})
İlişkisel verileri JSON'a dönüştürme
Bu madde, FOR JSON sorgu sonuçlarını sunucu tarafında bir JSON dizisine dönüştürür.
JSON AUTO İÇİN
Sorgu sonuçlarından JSON oluşturun:
cursor.execute("""
SELECT TOP 5 o.SalesOrderID, p.LastName AS CustomerName, o.TotalDue
FROM Sales.SalesOrderHeader o
JOIN Sales.Customer c ON o.CustomerID = c.CustomerID
JOIN Person.Person p ON c.PersonID = p.BusinessEntityID
FOR JSON AUTO
""")
# Result is a single string containing JSON
json_result = cursor.fetchval()
orders = json.loads(json_result)
print(json.dumps(orders, indent=2))
FOR JSON PATH
JSON yapısı üzerinde daha fazla kontrol edin:
cursor.execute("""
SELECT
o.SalesOrderID AS 'order.id',
o.OrderDate AS 'order.date',
p.LastName AS 'customer.name',
e.EmailAddress AS 'customer.email'
FROM Sales.SalesOrderHeader o
JOIN Sales.Customer c ON o.CustomerID = c.CustomerID
JOIN Person.Person p ON c.PersonID = p.BusinessEntityID
JOIN Person.EmailAddress e ON p.BusinessEntityID = e.BusinessEntityID
WHERE o.SalesOrderID = %(id)s
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
""", {"id": 43659})
json_result = cursor.fetchval()
order = json.loads(json_result)
# Structure: {"order": {"id": 43659, "date": "..."}, "customer": {"name": "...", "email": "..."}}
İç İçe JSON
İç içi JSON dizileri ve nesnelerle veri yapılarını sorgulamak, hiyerarşik JSON çıktısı oluşturmak için alt sorgular kullanılır.FOR JSON
cursor.execute("""
SELECT TOP 3
c.CustomerID,
p.LastName AS CustomerName,
(SELECT TOP 3 o.SalesOrderID, o.TotalDue
FROM Sales.SalesOrderHeader o
WHERE o.CustomerID = c.CustomerID
FOR JSON PATH) AS Orders
FROM Sales.Customer c
JOIN Person.Person p ON c.PersonID = p.BusinessEntityID
WHERE c.PersonID IS NOT NULL
FOR JSON PATH
""")
json_result = cursor.fetchval()
customers = json.loads(json_result)
# Each customer has nested Orders array
Python entegrasyon kalıpları
Bu desenler, JSON destekli tablolar üzerinde Python soyutlamalarının nasıl oluşturulacağını gösterir.
JSON ile depo modeli
Python nesnelerini JSON sütunlarına seri olarak serileştirip serilikten çıkaran bir veri erişim katmanı uygulayın; böylece veritabanına tip güvenli bir arayüz sağlar.
from dataclasses import dataclass, asdict
from typing import Optional
import json
@dataclass
class ProductSpecs:
weight: float
color: str
dimensions: dict
@dataclass
class Product:
id: Optional[int]
name: str
specs: ProductSpecs
class ProductRepository:
def __init__(self, connection):
self.conn = connection
cursor = self.conn.cursor()
cursor.execute("""
IF OBJECT_ID('#JsonRepo') IS NULL
CREATE TABLE #JsonRepo (
ProductID INT IDENTITY PRIMARY KEY,
Name NVARCHAR(100),
JsonData NVARCHAR(MAX)
)
""")
self.conn.commit()
def save(self, product: Product) -> int:
cursor = self.conn.cursor()
specs_json = json.dumps(asdict(product.specs))
if product.id:
cursor.execute("""
UPDATE #JsonRepo SET Name = %(name)s, JsonData = %(json)s
WHERE ProductID = %(id)s
""", {"name": product.name, "json": specs_json, "id": product.id})
else:
cursor.execute("""
INSERT INTO #JsonRepo (Name, JsonData)
OUTPUT INSERTED.ProductID
VALUES (%(name)s, %(json)s)
""", {"name": product.name, "json": specs_json})
product.id = cursor.fetchval()
self.conn.commit()
return product.id
def get(self, product_id: int) -> Optional[Product]:
cursor = self.conn.cursor()
cursor.execute("""
SELECT ProductID, Name, JsonData FROM #JsonRepo WHERE ProductID = %(id)s
""", {"id": product_id})
row = cursor.fetchone()
if row is None:
return None
specs_data = json.loads(row.JsonData)
return Product(
id=row.ProductID,
name=row.Name,
specs=ProductSpecs(**specs_data)
)
Veritabanına bağlanın, sonra depoyu oluşturun ve bir ürünü kaydedip almak için kullanın.
save() yöntemi, idNone olduğunda INSERT dalını, aksi takdirde ise UPDATE dalını izler:
conn = mssql_python.connect(connection_string)
repo = ProductRepository(conn)
# id is None, so save() inserts a new row and returns the generated ProductID.
product = Product(
id=None,
name="Widget Pro",
specs=ProductSpecs(weight=2.5, color="black", dimensions={"width": 10, "height": 5})
)
product_id = repo.save(product)
print(f"Saved product {product_id}")
# Read the product back into a typed Product object.
loaded = repo.get(product_id)
print(loaded)
conn.close()
Repository, #JsonRepo öğesini sağladığınız bağlantı kapsamında yerel geçici bir tablo olarak oluşturur; bu nedenle save() ve get() aynı bağlantıyı paylaşmalıdır. Bağlantı kapandığında tablo silinir.
Büyük JSON sonuçlarını verimli bir şekilde yönetin
JSON sonuçları büyük olduğunda, onları birden fazla satır boyunca parçalar halinde getirin.
def fetch_json_in_parts(cursor, query: str, params: dict) -> list:
"""Handle JSON results that might span multiple rows."""
cursor.execute(query, params)
# FOR JSON might split large results across rows
json_parts = []
for row in cursor:
json_parts.append(row[0])
# Combine parts
json_string = "".join(json_parts)
return json.loads(json_string) if json_string else []
# Usage
data = fetch_json_in_parts(cursor, "SELECT TOP 100 * FROM Production.Product FOR JSON AUTO", {})
Sorgu sonuçlarını Python'da JSON'a dönüştürün
İlişkisel sorgu sonuçlarını Python'da JSON formatına dönüştürerek her satırı bir sözlüğe dönüştürür ve ardından JSON'a seri yapar.
def query_to_json(cursor, query: str, params: dict = None) -> str:
"""Execute query and return results as JSON string."""
cursor.execute(query, params or {})
columns = [col[0] for col in cursor.description]
rows = []
for row in cursor:
rows.append(dict(zip(columns, row)))
return json.dumps(rows, default=str, indent=2)
# Usage
json_output = query_to_json(cursor, "SELECT TOP 5 ProductID, Name, ListPrice FROM Production.Product WHERE ProductSubcategoryID = %(cat)s", {"cat": 1})
print(json_output)
JSON verilerini dizine ekleme
Yolu indekslenebilir hale getirmek için JSON yol ifadesi ile desteklenen hesaplanmış bir sütun oluşturun.
İndeksli hesaplanan sütun
Bir JSON değerini çıkaran ve sıkça sorgulanan JSON yollarında verimli filtreleme için ona bir indeks uygulayan hesaplanmış bir sütun tanımlayın. Aşağıdaki örnek kalıcı bir tablo oluşturur, JSON $.specs.weight yolu üzerinde kalıcı bir hesaplanan sütun ekler ve üzerinde bir indeks oluşturur.
cursor.execute("""
IF OBJECT_ID('dbo.ProductCatalog', 'U') IS NOT NULL
DROP TABLE dbo.ProductCatalog
""")
cursor.execute("""
CREATE TABLE dbo.ProductCatalog (
ProductID INT IDENTITY PRIMARY KEY,
Name NVARCHAR(100),
JsonData NVARCHAR(MAX)
)
""")
# Insert sample rows with JSON data
rows = [
("Widget Pro", '{"specs":{"weight":2.5,"color":"blue"}}'),
("Gadget X", '{"specs":{"weight":0.8,"color":"red"}}'),
("Heavy Duty", '{"specs":{"weight":9.1,"color":"gray"}}'),
]
cursor.executemany(
"INSERT INTO dbo.ProductCatalog (Name, JsonData) VALUES (%(name)s, %(json)s)",
[{"name": n, "json": j} for n, j in rows]
)
conn.commit()
# Add a persisted computed column that extracts weight from JSON
cursor.execute("""
ALTER TABLE dbo.ProductCatalog
ADD ProductWeight AS CAST(JSON_VALUE(JsonData, '$.specs.weight') AS DECIMAL(5,2)) PERSISTED
""")
# Index the computed column for efficient range queries
cursor.execute("""
CREATE INDEX IX_ProductCatalog_Weight
ON dbo.ProductCatalog (ProductWeight)
""")
conn.commit()
İndekslenmiş hesaplanmış sütun kullanarak sorgu
Doğrudan hesaplanmış sütuna göre filtreleyin. Sorgu motoru, her JSON belgesini taramak ve ayrıştırmak yerine indeksi kullanır.
cursor.execute("""
SELECT Name, ProductWeight
FROM dbo.ProductCatalog
WHERE ProductWeight > %(min_weight)s
ORDER BY ProductWeight
""", {"min_weight": 1.0})
for row in cursor:
print(f"{row.Name}: {row.ProductWeight} kg")
# Cleanup
cursor.execute("DROP TABLE dbo.ProductCatalog")
conn.commit()
İlişkisel sütunlar ile JSON depolama arasında seçim yapın
Verilerin sabit bir şeması olduğunda, referans bütünlüğü gerektirdiğinde, JOIN'lara katıldığında veya WHERE cümlelerinde sıkça göründüğünde ilişkisel sütunlar kullanın. Veri seyrek, satırlar arasında değişiyorsa veya esnek yapılandırma veya meta veriyi temsil ettiğinde JSON sütunlarını (nvarchar(max)) kullanın.
Sunucu tarafı ile istemci tarafı JSON işlemciliği ne zaman kullanılır
JSON alanlarını filtrelemek, indekslemek veya toplamak gerektiğinde her satırı istemciye getirmeden Microsoft SQL JSON fonksiyonlarını (JSON_VALUE, JSON_QUERY, OPENJSON) kullanın. Bu seçim, sadece satır alt kümesi kriterlerinize uyduğunda veya JSON yollarında hesaplanmış sütun indeksleri istediğinizde doğrudur.
Tüm belgeleri alıp uygulama mantığında işlerken istemci tarafı Python işleme (json.loads()) kullanın. Bu yaklaşım, tam belgeye ihtiyacınız olduğunda ve veritabanındaki JSON alanlarında filtreleme yapmadığınızda iyi işe yarar.
Belge tarzı iş akışları
Uygulamanız tüm belgeleri depolayıp aldığında, Python tarafı serileştirme kullanın ve JSON sütununu opak depolama olarak kabul edin. Belgeleri Python'da tam JSON blob'larını getirip seri durumdan çıkararak işleyin ve sorgulayın:
import json
# Create the settings table
cursor.execute("""
CREATE TABLE #Settings (
UserID INT PRIMARY KEY,
ConfigJson NVARCHAR(MAX)
)
""")
# Store a configuration document
config = {
"theme": "dark",
"notifications": {"email": True, "sms": False},
"custom_fields": {"department": "Engineering", "cost_center": "CC-100"}
}
cursor.execute(
"INSERT INTO #Settings (UserID, ConfigJson) VALUES (%(uid)s, %(cfg)s)",
{"uid": 1, "cfg": json.dumps(config)}
)
# Retrieve and process in Python
cursor.execute("SELECT ConfigJson FROM #Settings WHERE UserID = %(uid)s", {"uid": 1})
row = cursor.fetchone()
config = json.loads(row.ConfigJson)
print(config["notifications"]["email"]) # True
Sunucu tarafı JSON sorguları
JSON alanlarını filtrelemek, indekslemek veya toplamak için her satırı getirmeden Microsoft SQL JSON fonksiyonlarını kullanın. Bu yaklaşım, tüm satırları bellekte filtrelemek için Python'a yüklemekten daha verimlidir:
-
JSON_VALUEskaler değerleri çıkarır ve hesaplanan sütun indekslerini destekleyebilir. -
JSON_QUERYnesneleri ve dizileri çıkarır. -
OPENJSON, JSON'uJOIN'ler ve toplama için satırlara ayırır. -
JSON_MODIFYTüm belgeyi yeniden yazmadan belirli yolları güncelliyor.
# Filter by a JSON field server-side
cursor.execute("""
SELECT UserID, ConfigJson
FROM #Settings
WHERE JSON_VALUE(ConfigJson, '$.custom_fields.department') = %(dept)s
""", {"dept": "Engineering"})
Sıkça sorgulanan JSON yolları için, bir indeksle hesaplanmış bir sütun oluşturun:
ALTER TABLE Settings
ADD Department AS JSON_VALUE(ConfigJson, '$.custom_fields.department');
CREATE INDEX IX_Settings_Department ON Settings(Department);
En iyi uygulamalar
JSON sütunlarını güvenilir şekilde kullanmak için bu yönergeleri uygulayın.
JSON'u depolamadan önce doğrulayın
Enjeksiyon saldırılarını önlemek için JSON ve tablo/sütun tanımlayıcılarını kaydetmeden önce doğrulayın.
def store_json_safely(cursor, table: str, json_column: str, data: dict):
"""Store JSON with validation."""
# Validate identifiers to prevent SQL injection
import re
if not re.match(r'^[A-Za-z_][A-Za-z0-9_.]*$', table):
raise ValueError(f"Invalid table name: {table}")
if not re.match(r'^[A-Za-z_][A-Za-z0-9_]*$', json_column):
raise ValueError(f"Invalid column name: {json_column}")
json_str = json.dumps(data)
# Check if valid JSON in Microsoft SQL
cursor.execute("SELECT ISJSON(%(json)s)", {"json": json_str})
if cursor.fetchval() != 1:
raise ValueError("Invalid JSON")
cursor.execute(f"INSERT INTO {table} ({json_column}) VALUES (%(json)s)", {"json": json_str})
JSON'u fazla kullanma
Kullanıcı tercihleri veya özel alanlar gibi esnek veya seyrek veriler için JSON sütunlarını kullanın. İlişkisel sütunları şu amaçlarla kullanın:
- Sıkça sorgulanan veriler.
- Referans bütünlüğü gerektiren veriler.
-
WHEREyan tümcelerinde kullanılan sütunlar.
None/NULL'u doğru şekilde yönetin
Eksik veya isteğe bağlı JSON alanlarını, veri olmayan sütunlar için NULL değerleri ekleyerek yönetin.
cursor.execute("""
CREATE TABLE #JsonOpt (
ProductID INT IDENTITY, Name NVARCHAR(100), JsonData NVARCHAR(MAX)
)
""")
cursor.execute("""
INSERT INTO #JsonOpt (Name, JsonData) VALUES (
'Widget Pro', '{"required_field":"value"}'
)
""")
cursor.execute("""
SELECT
Name,
JSON_VALUE(JsonData, '$.optional_field') AS OptionalValue
FROM #JsonOpt
""")
for row in cursor:
# JSON_VALUE returns NULL if path doesn't exist
value = row.OptionalValue or "default"
print(f"{row.Name}: {value}")