構造化クエリ言語 (SQL) を使用して、Web API を使用してMicrosoft Dataverseのデータに対してクエリを実行できます。 クエリするテーブルのエンティティ セット名を使用して、SELECT クエリ オプションを使用して SQL sql コマンドを渡します。
Note
各コマンドには、1 つの SELECT ステートメントが含まれている必要があります。
DECLARE、INSERT、DELETE、ALTER TABLEなどのその他の T-SQL ステートメントはサポートされていません。
SELECT name FROM account; SELECT fullname FROM contactなどの複数の結果セットを含むコマンドはサポートされていません。
次のような SQL クエリを使用するには:
SELECT name
FROM account AS a
WHERE a.name LIKE 'Fourth Coffee'
クエリの URL エンコード値を sql クエリ オプションに設定し、クエリのベース テーブルと一致する エンティティセット リソース に設定します。 この場合、エンティティ セット名は accounts。
依頼
GET [Organization URI]/api/data/v9.2/accounts?sql=SELECT%20name%20%0D%0AFROM%20account%20AS%20a%20%0D%0AWHERE%20a.name%20LIKE%20'Fourth%20Coffee' HTTP/1.1
Authorization: Bearer [REDACTED]
OData-MaxVersion: 4.0
OData-Version: 4.0
Prefer: odata.include-annotations="*"
Accept: application/json
応答
応答は、同等の OData クエリで得られる応答と似ています。
/accounts?$select=name&$filter=contains(name,'Fourth Coffee')
HTTP/1.1 200 OK
Content-Type: application/json; odata.metadata=minimal
OData-Version: 4.0
Preference-Applied: odata.include-annotations="*"
{
"@odata.context": "[Organization URI]/api/data/v9.2/$metadata#accounts(name,accountid)",
"@Microsoft.Dynamics.CRM.totalrecordcount": -1,
"@Microsoft.Dynamics.CRM.totalrecordcountlimitexceeded": false,
"@Microsoft.Dynamics.CRM.globalmetadataversion": "173309522",
"value": [
{
"@odata.etag": "W/\"173325408\"",
"accountid": "0bdd4472-981d-f111-8341-0022482aa957",
"name": "Fourth Coffee"
}
]
}
列の選択
SELECT句の特定の列名をコンマで区切って一覧表示します。 テーブルエイリアスを使用して列参照を修飾し、列エイリアスを使用して出力フィールドの名前を変更します。
Important
SELECT *はサポートされていません。 取得する各列に明示的に名前を付ける必要があります。
次の例では、テーブルのエイリアスを使用して、 account テーブルから 3 つの列を選択します。
SELECT a.name, a.telephone1, a.websiteurl
FROM account AS a
列エイリアスを使用して出力フィールドの名前を変更する:
SELECT a.name AS account_name, a.telephone1 AS phone
FROM account AS a
返されるレコードは次の例のようになります。
{
"@odata.etag": "W/\"174033617\"",
"accountid": "667ec6df-4a22-f111-8342-0022482aa3a2",
"account_name@OData.Community.Display.V1.AttributeName": "name",
"account_name": "Wide World Importers",
"phone@OData.Community.Display.V1.AttributeName": "telephone1",
"phone": "(555) 100-0006"
}
Note
集計以外のリテラル値、式、関数の選択はサポートされていません。
SELECT 'abc', 1+2 AS IntValue, DATEADD(day, -3, a.modifiedon), a.name FROM account aは使用しないでください。
テーブルの結合
INNER JOINまたはLEFT JOINを使用して、複数のテーブルの行を結合します。 対応する列(通常は主キーと外部キー)で結合します。
Note
RIGHT JOIN、FULL OUTER JOIN、および CROSS JOIN はサポートされていません。
次の例では、内部結合を使用してアカウントとその関連する連絡先を返します。
SELECT a.name, c.fullname, c.emailaddress1
FROM account AS a
INNER JOIN contact AS c ON a.accountid = c.parentcustomerid
LEFT JOINを使用して、関連する連絡先がないアカウントを含めます。
SELECT a.name, c.fullname
FROM account AS a
LEFT JOIN contact AS c ON a.accountid = c.parentcustomerid
複数のテーブルを結合できます。 次の例では、アカウント、連絡先、営業案件を結合します。
SELECT a.name, c.fullname, o.name AS opportunity_name
FROM account AS a
INNER JOIN contact AS c ON a.accountid = c.parentcustomerid
INNER JOIN opportunity AS o ON a.accountid = o.customerid
自己結合を使用して、同じテーブル内の行を関連付けます。 次の例では、アカウントとその親アカウントを検索します。
SELECT child.name AS account, parent.name AS parent_account
FROM account AS child
INNER JOIN account AS parent ON child.parentaccountid = parent.accountid
その他の ON フィルター
JOIN ... ON 句では、2 つのテーブルの列間で = 演算子を使用する必要があります。 追加のフィルターは、 AND 演算子を使用してこの等値条件と組み合わせる必要があり、結合テーブルに適用する必要があります。
-- Not supported, must join on columns from the two tables
-- SELECT a.name, c.fullname, c.emailaddress1
-- FROM account AS a
-- INNER JOIN contact AS c ON c.emailaddress1 LIKE 'B%'
-- Not supported, must use "="
-- SELECT a.name, c.fullname, c.emailaddress1
-- FROM account AS a
-- INNER JOIN contact AS c ON a.accountid <> c.parentcustomerid
-- Not supported, must combine additional filters using AND
-- SELECT a.name, c.fullname, c.emailaddress1
-- FROM account AS a
-- INNER JOIN contact AS c ON a.accountid = c.parentcustomerid OR c.emailaddress1 LIKE 'B%'
-- Not supported, additional filters must be on the joined table
-- SELECT a.name, c.fullname, c.emailaddress1
-- FROM account AS a
-- INNER JOIN contact AS c ON a.accountid = c.parentcustomerid AND a.name LIKE 'A%'
-- This example works because it has a filter on the joined contact table fullname column:
SELECT a.name, c.fullname, c.emailaddress1
FROM account AS a
INNER JOIN contact AS c ON a.accountid = c.parentcustomerid AND c.fullname LIKE 'A%'
ORを使用して追加のフィルター全体が列の等価性と組み合わされている限り、入れ子になったAND演算子を使用して、追加の条件を相互に組み合わせることができます。
SELECT a.name, c.fullname, c.emailaddress1
FROM account AS a
INNER JOIN contact AS c
ON a.accountid = c.parentcustomerid
AND (c.fullname LIKE 'A%' OR c.emailaddress1 LIKE 'B%')
行の順序を整理する
ORDER BYを使用して、1 つ以上の列で結果を並べ替えます。
ASC (昇順、既定値) またはDESC (降順) を指定します。
Note
ORDER BY は列名のみを参照できます。
ORDER BY LEN(name)などの式はサポートされていません。
次の例では、名前で並べ替えられたアカウントを返します。
SELECT name, telephone1
FROM account
ORDER BY name ASC
複数列で並べ替え:
SELECT name, createdon
FROM account
ORDER BY name ASC, createdon DESC
行のフィルター
WHERE句を使用して、1 つ以上の条件で行をフィルター処理します。
WHERE句は、列と定数値を比較する必要があります。
Important
式とサブクエリは、 WHERE 句ではサポートされていません。 比較は、列とリテラル値の間、または サポートされている関数である必要があります。
比較演算子
サポートされている比較演算子は、 =、 !=、 <>、 <、 >、 <=、および >=です。
SELECT name, statecode
FROM account
WHERE statecode = 0
!=または<>を使用して行を除外します。
SELECT name, statecode
FROM account
WHERE statecode <> 1
範囲比較には、 <、 >、 <=、または >= を使用します。
SELECT name
FROM account
WHERE name > 'M'
ORDER BY name
論理演算子
ANDとORを使用して条件を結合します。 評価順序を制御するには、括弧を使用します。
SELECT name, telephone1
FROM account
WHERE statecode = 0 AND telephone1 IS NOT NULL
SELECT name
FROM account
WHERE (name = 'Contoso' OR name = 'Fabrikam')
SELECT name, telephone1
FROM account
WHERE (statecode = 0 OR statecode = 1) AND telephone1 IS NOT NULL
LIKE パターン
文字列パターンを照合するには、 LIKE を使用します。 サポートされているワイルドカードは次のとおりです。
| ワイルドカード | 説明 | 例 |
|---|---|---|
% |
任意の文字列に一致します |
'Fourth%' は Fourth Coffee に一致します |
_ |
任意の 1 文字と一致します |
'_ontoso' は Contoso に一致します |
[%] |
文字どおりのパーセント記号に一致します |
'[%]off' は 50%off に一致します |
SELECT name FROM account WHERE name LIKE 'Fourth%'
NOT LIKEを使用して、一致する行を除外します。
SELECT name FROM account WHERE name NOT LIKE '%test%'
Tip
可能な限り先頭のワイルドカード (LIKE '%value') は使用しないでください。完全なテーブル スキャンが必要であり、パフォーマンスが低下します。 末尾のワイルドカード (LIKE 'value%') では、インデックスを使用できます。 詳細については、「 フィルター条件でワイルドカードを先頭に表示しないようにする」を参照してください。
IN と NOT IN
INを使用して、リスト内の任意の値と一致させます。
SELECT name
FROM account
WHERE name IN ('Contoso', 'Fabrikam', 'Fourth Coffee')
NOT INを使用して値を除外します。
SELECT name
FROM account
WHERE name NOT IN ('Contoso', 'Fabrikam')
BETWEEN
BETWEENを使用して、包括範囲内の行をフィルター処理します。
SELECT name
FROM account
WHERE name BETWEEN 'A' AND 'B'
IS NULL と IS NOT NULL
IS NULLを使用して列に値がない行を検索し、IS NOT NULLを使用して列に値がある行を検索します。
SELECT name
FROM account
WHERE telephone1 IS NULL
SELECT name, telephone1
FROM account
WHERE telephone1 IS NOT NULL
Note
= NULLを使用して null 値をテストしないでください。
IS NULL を代わりに使用します。 式 WHERE name = NULL は期待される結果を返しません。
DISTINCT
DISTINCTを使用して一意の値を返します。
SELECT DISTINCT a.address1_city
FROM account AS a
DATEADD 関数と GETUTCDATE 関数の使用
Note
リテラル値またはサポートされている別の関数に関数を適用する必要があります。 列の値に関数を適用することはできません。
DATEADD関数を使用して、一定の日付範囲の行を返します。
-- Do not pass column values to functions
-- SELECT a.name
-- FROM account a
-- WHERE DATEADD(day, 3, a.createdon) >= '2023-01-01 17:00:00' (not supported)
SELECT a.name
FROM account a
WHERE a.createdon >= DATEADD(day, -3, '2023-01-01 17:00:00')
GETUTCDATE関数を使用して、現在の時刻を基準に範囲を指定します。
-- Do not pass column values to functions
-- SELECT a.name
-- FROM account a
-- WHERE DATEADD(day, 3, a.createdon) >= GETUTCDATE() (not supported)
SELECT a.name
FROM account a
WHERE a.createdon >= DATEADD(day, -3, GETUTCDATE())
Note
WHEREおよびON句の条件は、これらの関数をサポートします。
SELECT、ORDER BY、およびGROUP BY句は、関数呼び出しをサポートしていません。
サポートされていない WHERE 句の機能
WHERE句では、次の機能はサポートされていません。
- サブクエリ:
WHERE accountid IN (SELECT accountid FROM account)。 -
EXISTSおよびNOT EXISTS: これらの演算子はエラーを返します。 - リテラル同士の比較:
WHERE 1=1とWHERE 1=0。 - 列と列の比較:
WHERE a.modifiedon > a.createdon。 - 式:
WHERE a.revenue > 500.0 + 125.0。 - 列の値に適用される関数:
WHERE DATEADD(day, 3, a.createdon) >= GETUTCDATE()。 - このドキュメントに記載されていない関数。
ページの結果
Prefer: odata.maxpagesize要求ヘッダーと@odata.nextLink注釈で OData ページングを使用します。
ページングの詳細を見る
Note
TOP および OFFSET ... FETCH はクエリではサポートされていません。 レコードの数を制限するには、 Prefer: odata.maxpagesize を使用します。
または、前のページの最後に表示された ID をフィルター処理して、カーソルベースのアプローチを使用します。
SELECT name, accountid
FROM account
WHERE accountid > '00000000-0000-0000-0000-000000000000'
ORDER BY accountid
データの集計
集計関数と GROUP BY を使用してデータを集計します。 サポートされている集計関数は、 COUNT、 SUM、 AVG、 MIN、および MAXです。
Note
HAVINGはサポートされていません。 集計する前に、 WHERE 句を使用してデータをフィルター処理します。
次の例では、連絡先を親アカウント別にグループ化し、カウントします。
SELECT a.name, COUNT(*) AS contact_count
FROM account AS a
INNER JOIN contact AS c ON a.accountid = c.parentcustomerid
GROUP BY a.name
ORDER BY a.name
1 つのクエリで複数の集計関数を使用します。
SELECT COUNT(*) AS total_accounts,
SUM(revenue) AS total_revenue,
AVG(revenue) AS avg_revenue,
MIN(revenue) AS min_revenue,
MAX(revenue) AS max_revenue
FROM account
Note
GROUP BY MONTH(a.createdon)などの日付の一部を含む関数によるグループ化はサポートされていません。
集計クエリのレコード制限
集計値を返すクエリは、50,000 レコードに制限されます。 この制限は、システムのパフォーマンスと信頼性を維持するのに役立ちます。 クエリのフィルター条件から返されるレコード数が 50,000 を超える場合は、次のエラーが発生します。
番号:
-2147164125
コード:8004E023
メッセージ:AggregateQueryRecordLimit exceeded. Cannot perform this operation.
クライアント エラー メッセージ: レコードの最大数を超えています。 レコード数を減らしてください。
このエラーを回避するには、クエリに適切なフィルターを追加して、50,000 を超えるレコードが評価されないようにします。 その後、クエリを複数回実行し、結果を結合します。 適切なフィルターはデータの性質によって異なりますが、日付範囲または選択列の値のサブセットである可能性があります。
行数を数える
COUNT(*)を使用して、クエリに一致する行の数をカウントします。
SELECT COUNT(*) AS account_count
FROM account
COUNTとWHERE句を組み合わせて、条件を満たす行をカウントします。
SELECT COUNT(*) AS active_contacts
FROM contact
WHERE statecode = 0
グループあたりの行数をカウントするには、COUNTでGROUP BYを使用します。
SELECT a.name, COUNT(*) AS contact_count
FROM account AS a
INNER JOIN contact AS c ON a.accountid = c.parentcustomerid
GROUP BY a.name
パフォーマンスを最適化する
Dataverse に対して効率的な SQL クエリを記述するには、次のガイドラインに従ってください。
クエリのアンチパターンを回避する
Dataverse クエリを作成する際に一般的に避けるべきことについての指針については、クエリのアンチ パターンを参照してください。
必要な列のみを選択する
列を少なく選択すると、転送されるデータの量が減ります。 使用しない列を要求しないようにします。
-- Avoid selecting all columns
-- SELECT * FROM account (not supported)
-- Select only needed columns
SELECT name, telephone1
FROM account
インデックス付き列のフィルター処理
主キーやその他のインデックス付き列のフィルター処理は、インデックスのないフィールドでフィルター処理するよりも高速です。
SELECT name, telephone1
FROM account
WHERE accountid = '00000000-0000-0000-0000-000000000000'
JOIN 深度を制限する
複数のテーブル結合を使用できますが、追加の結合ごとにクエリ コストが発生します。 結合をクエリに必要なものに制限します。