Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Este artigo descreve os métodos disponíveis para consultar dados do Dataverse usando o SDK para Python. Você pode consultar dados usando SQL (Structured Query Language) e APIs baseadas em OData.
Os desenvolvedores Python devem primeiro conhecer o SDK para Python lendo Primeiros passos antes de continuar com este artigo.
QueryBuilder
QueryBuilder é a maneira recomendada de consultar registros. Ele fornece uma interface fluente com segurança de tipos que gera consultas OData corretas automaticamente. Você não precisa se lembrar da sintaxe do filtro OData.
# Fluent query builder (recommended)
from PowerPlatform.Dataverse.models.filters import col
for record in (client.query.builder("account")
.select("name", "revenue")
.where(col("statecode") == 0)
.where(col("revenue") > 1000000)
.order_by("revenue", descending=True)
.top(100)
.page_size(50)
.execute()):
print(f"{record['name']}: {record['revenue']}")
O QueryBuilder gerencia automaticamente a formatação de valores, o uso de maiúsculas e minúsculas nos nomes das colunas e a sintaxe OData. Crie expressões de filtro com operadores col() e Python padrão.
# Get results as a pandas DataFrame (consolidates all pages)
df = (client.query.builder("account")
.select("name", "telephone1")
.where(col("statecode") == 0)
.top(100)
.execute()
.to_dataframe())
print(f"Got {len(df)} accounts")
# Comparison filters using col() expressions
query = (client.query.builder("contact")
.where(col("statecode") == 0) # statecode eq 0
.where(col("revenue") > 1000000) # revenue gt 1000000
.where(col("name").contains("Corp")) # contains(name, 'Corp')
.where(col("statecode").in_([0, 1])) # Microsoft.Dynamics.CRM.In(...)
.where(col("revenue").between(100000, 500000)) # revenue ge 100000 and revenue le 500000
.where(col("telephone1").is_null()) # telephone1 eq null
)
Para lógica complexa (OR, NOT, agrupamento), redigir expressões com &, , |: ~
from PowerPlatform.Dataverse.models.filters import col
# OR conditions: (statecode = 0 OR statecode = 1) AND revenue > 100k
for record in (client.query.builder("account")
.select("name", "revenue")
.where(((col("statecode") == 0) | (col("statecode") == 1))
& (col("revenue") > 100000))
.execute()):
print(record["name"])
# NOT, between, and in operators
for record in (client.query.builder("account")
.where(col("statecode") != 2) # NOT inactive
.where(col("revenue").between(100000, 500000)) # revenue in range
.execute()):
print(record["name"])
Valores formatados e anotações
Este exemplo demonstra como solicitar rótulos localizados, símbolos de moeda e nomes de exibição.
# Get formatted values (choice labels, currency, lookup names) — via query builder
for record in (client.query.builder("account")
.select("name", "statecode", "revenue")
.include_formatted_values()
.execute()):
status = record["statecode@OData.Community.Display.V1.FormattedValue"]
print(f"{record['name']}: {status}")
# Get formatted values — via records.list() / records.retrieve() include_annotations param
result = client.records.list(
"account",
select=["name", "statecode"],
include_annotations="OData.Community.Display.V1.FormattedValue",
)
for record in result:
label = record.get("statecode@OData.Community.Display.V1.FormattedValue")
print(f"{record['name']}: {label}")
record = client.records.retrieve(
"account", account_id,
select=["name", "statuscode"],
include_annotations="OData.Community.Display.V1.FormattedValue",
)
if record:
print(record.get("statuscode@OData.Community.Display.V1.FormattedValue"))
Expandir propriedades de navegação
Use a expansão aninhada com opções para expandir as propriedades de navegação usando $select, $filter, $orderby e $top.
from PowerPlatform.Dataverse.models.query_builder import ExpandOption
# Expand related tasks with filtering and sorting
for record in (client.query.builder("account")
.select("name")
.expand(ExpandOption("Account_Tasks")
.select("subject", "createdon")
.filter("contains(subject,'Task')")
.order_by("createdon", descending=True)
.top(5))
.execute()):
print(record["name"], record.get("Account_Tasks"))
Paging
Use execute_pages() para transmitir grandes conjuntos de resultados com opções completas do construtor, como filtragem, classificação e valores formatados. Para consultas de filtro OData baseadas em cadeia de caracteres mais simples, use records.list() e records.list_pages() como atalhos.
# Preferred: query.builder().execute_pages() — stream one page at a time, memory stays flat
# Supports composable filters, sorting, formatted values, and expand with nested selects
for page_num, page in enumerate(
client.query.builder("account")
.select("accountid", "name", "revenue")
.where(col("statecode") == 0)
.order_by("name")
.page_size(500) # optional: override Dataverse default (~5000/page)
.execute_pages()
):
print(f"Page {page_num + 1}: {len(page)} records")
for record in page:
print(f" {record['name']}")
# Simple shortcut: records.list() — automatic paging, all records in memory
# Use for basic filter+select queries; string OData filter only (no composable expressions)
result = client.records.list(
"account",
filter="statecode eq 0",
select=["name", "revenue"],
orderby=["name asc"], # optional sort
top=500, # bounds total records returned and number of HTTP round-trips
page_size=200, # optional: hint Dataverse default page size
)
for record in result:
print(record["name"])
# Simple streaming shortcut: records.list_pages() — same params as records.list(), yields one page at a time
for page_num, page in enumerate(
client.records.list_pages("account", filter="statecode eq 0", select=["name"], orderby=["name asc"])
):
print(f"Page {page_num + 1}: {len(page)} records")
for record in page:
print(record["name"])
Note
Ambos execute(by_page=True) e execute(by_page=False) são preteridos e emitem um UserWarning. Substitua-os por execute_pages() (streaming) ou simples execute() (ansioso).
QueryBuilder.to_dataframe() também é preterido – use .execute().to_dataframe() em vez disso.
A ferramenta de migração reescreve todas essas chamadas automaticamente. Instale a ferramenta de migração executando pip install PowerPlatform-Dataverse-Client[migration] e execute dataverse-migrate path/to/your/scripts/. Como alternativa, execute python -m PowerPlatform.Dataverse.migration.migrate_v0_to_v1 para checkouts de desenvolvimento.
Contagem de registros
Para obter uma contagem de registros, inclua $count=true na solicitação.
# Via query builder
results = (client.query.builder("account")
.where(col("statecode") == 0)
.count()
.execute())
# Via records.list() — count=True adds $count=true to the OData request
results = client.records.list("account", filter="statecode eq 0", count=True)
Consultas FetchXML
A chamada client.query.fetchxml() retorna um objeto inert FetchXmlQuery . Nenhuma solicitação HTTP é feita até você ligar .execute() ou .execute_pages().
xml = """
<fetch>
<entity name="account">
<attribute name="name"/>
<attribute name="revenue"/>
<filter><condition attribute="statecode" operator="eq" value="0"/></filter>
</entity>
</fetch>
"""
# .execute() — blocking, fetches all pages and returns a single QueryResult
result = client.query.fetchxml(xml).execute()
df = result.to_dataframe()
# .execute_pages() — streaming, yields one QueryResult per HTTP page
# Use count="N" in the FetchXML <fetch> element to set page size
for page_num, page in enumerate(client.query.fetchxml(xml).execute_pages()):
print(f"Page {page_num + 1}: {len(page)} records")
for record in page:
print(record["name"])
Atalho para lista simples
A records.list() chamada aceita uma cadeia de caracteres de filtro OData bruta para consultas básicas. Para qualquer caso que vá além de filtrar e selecionar de forma simples, prefira usar client.query.builder(), que oferece filtros composáveis, valores formatados e expansão aninhada.
# records.list() shortcut — raw OData filter string, all records loaded into memory
# Column names in filter must be lowercase logical names
for record in client.records.list(
"account",
select=["name"],
filter="statecode eq 0",
top=100,
):
print(record["name"])
# Discover navigation property names for $expand (metadata-discovery helper, kept at GA)
nav_props = client.query.odata_expands("account") # → list of navigation property metadata
# Expand navigation properties using the query builder
from PowerPlatform.Dataverse.models.query_builder import ExpandOption
for record in (client.query.builder("contact")
.select("fullname")
.expand(ExpandOption("parentcustomerid_account").select("name"))
.execute()):
acct = record.get("parentcustomerid_account") or {}
print(f"{record['fullname']} -> {acct.get('name')}")
# Build @odata.bind for lookup fields (deprecated helper, still functional with DeprecationWarning)
bind = client.query.odata_bind("contact", "account", account_id)
# Returns: {"parentcustomerid_account@odata.bind": "/accounts(guid)"}
client.records.create("contact", {"firstname": "Jane", **bind})
Consultar dados usando SQL
O Dataverse fornece uma interface de somente leitura para um conjunto limitado de comandos SQL SELECT. Há suporte para JOINs SQL, funções de agregação, GROUP BY, DISTINCT e paginação OFFSET FETCH.
Você também pode acessar a funcionalidade de consulta SQL usando o parâmetro ?sql= da API Web do Dataverse para que o código escrito em idiomas diferentes de Python possa acessar dados do Dataverse. Para obter mais informações, consulte Usar o SQL para consultar dados com a API Web do Dataverse.
Importante
O suporte ao SQL é limitado a consultas de leitura apenas. Não há suporte para junções complexas, subconsultas e determinadas funções SQL. A consulta SQL deve seguir o subconjunto com suporte:
- WHERE só pode ser uma árvore de expressão booliana em que as folhas são operadores binários (=, >, como etc.) com um dos argumentos sendo uma referência de coluna direta e outro é uma constante
- TOP permite apenas um literal inteiro
- ORDERBY só pode referenciar colunas e não permite expressões complexas
O código de exemplo a seguir demonstra uma consulta SQL no Python.
# Basic query
results = client.query.sql(
"SELECT TOP 10 accountid, name FROM account WHERE statecode = 0"
)
# JOINs and aggregates work
results = client.query.sql(
"SELECT a.name, COUNT(c.contactid) as cnt "
"FROM account a "
"JOIN contact c ON a.accountid = c.parentcustomerid "
"GROUP BY a.name"
)
# SQL results directly as a DataFrame
df = client.dataframe.sql(
"SELECT name, revenue FROM account ORDER BY revenue DESC"
)
# Discover columns from metadata (schema-discovery helper, kept at GA)
cols_meta = client.query.sql_columns("account")
col_names = [c["LogicalName"] for c in cols_meta]
# Build queries using the discovered column names
sql = f"SELECT TOP 10 {', '.join(col_names[:5])} FROM account"
df = client.dataframe.sql(sql)