Color scheme: Light
You are here: start » en » Documentation » Data integration and data access » WKL OData ODBC Driver » OData ODBC driver reference » Supported SQL (reference)

Supported SQL (reference)

This reference shows which SQL statements the driver translates into OData requests, how it translates them, and what it rejects. You need this page if a query from Access, ADO.NET, or VBA doesn't run as expected, or if you want to write a query so that it works without custom statements. The concept How the driver translates statements gives the overview. Which sets and columns exist and where their types come from is described first in How an OData service becomes a relational ODBC model.

Syntax

SELECT <COLUMNS | aggregates> FROM <entity-set> [WHERE <condition>] [GROUP BY <columns> [HAVING <condition>]]
  [ORDER BY <columns> [OFFSET n ROWS [FETCH NEXT m ROWS ONLY]]]
INSERT INTO <entity-set> (…) VALUES (…)
UPDATE <entity-set> SET … WHERE <key> = ? [AND <row-version> = ?]
DELETE FROM <entity-set> WHERE <key> = ? [AND <row-version> = ?]

A translated statement reads exactly one entity set. Everything else goes to the address for custom statements or is rejected.

Parameters

Conditions

SQLOData
=, <>, <, <=, >, >=, IS NULL, IS NOT NULLeq, ne, lt, le, gt, ge, eq null, ne null
Column against column of the same table (C.ParentId = C.Id), also under a table aliasParentId eq Id; the driver rejects columns of different type families (number against text). Needs a service that accepts field-to-field comparison
AND, OR, NOT, parenthesesand, or, not, parentheses
IN (…), NOT IN (…)or-chain, negated
LIKE 'x%', '%x', '%x%'startswith, endswith, contains
LIKE with one character in square brackets ('B[_]%')the character itself, as in SQL Server
Parameter ?bound value, as a literal in the filter

Grouping and summarizing

Access sends totals and groups over a linked table to the driver regardless of what SQLGetInfo says about it, and doesn't compute them itself if the driver refuses – the query then fails with “ODBC–call failed” (also with SQL_ODBC_SQL_CONFORMANCE = 0). With an address for custom statements, they go to the database unchanged. Without one, the driver translates them to $apply (OData Data Aggregation 4.0) – but only if the schema document announces Org.OData.Aggregation.V1.ApplySupported with the required transformations. A service without this announcement would at best answer $apply with an error and at worst, if it ignores unknown options, with the ungrouped rows, which the application would take for the groups.

Access doesn't send AVG, but SUM and COUNT(x), and divides itself; for StDev and Var, additionally SUM(x * x); it keeps TOP n; ORDER BY names the column fully qualified ("dbo"."Artikel"."Gruppe"), even inside an aggregate; it computes a grouping by Year(…) itself over the column it read.

Access sendsThe driver requests
SELECT SUM("x") FROM "dbo"."t" "R"t?$apply=aggregate(x with sum as gw_a1)
SELECT "g", COUNT(*) FROM … WHERE ("id" > 3) GROUP BY "g" ORDER BY "dbo"."t"."g" DESC$apply=filter(id gt 3)/groupby((g),aggregate($count as gw_a1))&$orderby=g desc
… GROUP BY "g" HAVING (COUNT(*) > 1)$filter=gw_a1 gt 1 on the groups
… HAVING SUM("b") >= ? (aggregate not selected)requested as gw_a1, compared, but not shown as a column
… ORDER BY SUM("dbo"."t"."id") DESCthe same aggregate as in the selection, $orderby=gw_a1 desc
SELECT DISTINCT "g" FROM …groupby((g))
SELECT COUNT("x"), SUM(("x" * "x")), SUM("x") FROM …compute((x mul x) as gw_c1)/aggregate(x with Wkl.Store.V1.count as gw_a1,gw_c1 with sum as gw_a2,x with sum as gw_a3)
SELECT COUNT(*) FROM … on its ownstill $count – every service answers that

The protocol doesn't know COUNT(x) – the values that aren't missing – as a standard method; for it, the driver uses Wkl.Store.V1.count if the service announces it with Aggregation.CustomAggregationMethods, and refuses otherwise. It chooses the aliases gw_aN and gw_cN so that no property of the set has that name.

Column types as with Microsoft's driver for SQL Server, so that Access creates the same fields: a count is int, the sum of integers up to int is int (a larger value fails, as there, on the overflow), the sum of bigint is bigint, and that of a decimal number decimal(38, s); MIN and MAX have the type of the column. One deliberate difference: the average of integers is float with decimal places, where SQL Server returns an integer – the service computes the true average, and describing it as an integer would truncate what it sends. A column takes the name of its alias in the statement; without an alias it has no name, as with ODBC Driver 18 (Access then names it Expr1000, Expr1001 … itself).

Rejected with 42000 instead of approximated: calculating between aggregates (SUM(a) - SUM(b)), division, functions other than SUM, MIN, MAX, AVG, COUNT, a column in the selection that isn't grouped, DISTINCT in SUM or AVG, a parameter inside an aggregate, * alongside GROUP BY. With an address for custom statements, these go to the database as well.

In Access, a translated totals query returns the same values and field types as through Microsoft ODBC Driver 18. A sum that overflows int fails as it does there.

Paging with OFFSET/FETCH

An application that shows a large result screen by screen requests each page with the paging form of SQL Server and the SQL standard. The driver translates it without an address for custom statements: OFFSET n becomes $skip=n, FETCH NEXT m ROWS ONLY becomes $top=m; condition and sorting go along as $filter and $orderby as usual. An example of how a data grid sends it over its own connection with SQLExecDirect:

SELECT S."ID", S."Kunde", S."Umsatz" FROM "dbo"."Umsatz" S
ORDER BY S."Umsatz" DESC, S."ID" OFFSET 500000 ROWS FETCH NEXT 200 ROWS ONLY

becomes Umsatz?$select=ID,Kunde,Umsatz&$orderby=Umsatz desc,ID&$skip=500000&$top=200.

RuleReason
OFFSET only after ORDER BY; ROW/ROWS, FIRST/NEXT equivalent; FETCH may be omittedAs in SQL Server: without an order, there's no fixed position
Values as an integer or a parameter (?); OFFSET from 0, FETCH from 1What SQL Server rejects (errors 10742, 10744), the driver rejects too
TOP alongside OFFSET is rejectedSQL Server rejects such a statement as well (error 10741)
Grouped statements (GROUP BY, DISTINCT) page the same wayThe service pages the groups after $apply with $skip/$top
SQL_ATTR_MAX_ROWS additionally limits FETCHAs with TOP
COUNT(*) with a condition – including the rank condition for the position of a record – stays $count; COUNT(*) AS name keeps the nameOtherwise the column has no name, and a reader looking it up by name wouldn't find it

The driver recognizes the words OFFSET, FETCH, ROWS, NEXT, and so on only at the end of ORDER BY; a column named Next can still be written as is.

How expensive a deep page is depends on the service and its database, not on the driver. The data service Wkl.Data.Gateway turns $skip into an OFFSET … ROWS, and SQL Server reads all rows before it for that. Through the driver, a shallow page additionally costs the fixed overhead of an HTTP request.

Return value

Column names are the alias in the statement; without an alias the name is empty, as with ODBC Driver 18. Column types follow the rules under “Grouping and summarizing”.

Remarks

  • LIKE works only in the forms x%, %x, %x%, and without _ as a wildcard. A single character in square brackets ([_], [%]) or after an escape character (ESCAPE) counts as that character and is allowed. A character class such as [a-c] or [^a] has no equivalent in OData.
  • The driver translates expressions in the field list only inside an aggregate.
  • SQLGetInfo doesn't announce joins and subqueries; Access sends joins anyway, and they run only through the address for custom statements.
  • The cursor reads forward, without bookmarks and without locks.
  • GUID values (uniqueidentifier, Edm.Guid): as a literal in the Access notation ({guid {33333333-…}}), as text, or as a parameter of type Guid or as 16 bytes; the OData v4 form without a type name goes to the service. For ODBC 2 applications such as Access, the driver returns a GUID without a requested type as text, as ODBC Driver 18 does. This applies in Access to datasheets, forms, subforms, and lookup lists.

Example

Access:  SELECT ... FROM Artikel WHERE Gruppe = 'S' ORDER BY Nummer
Service: GET .../Artikel?$filter=Gruppe eq 'S'&$orderby=Nummer&$select=...

Applies to

Driver Wkl OData, both bitnesses; grouping only against a service that announces $apply (see Requirements for an OData service).

Exceptions

SQLSTATECondition
42000The statement can't be translated and there's no address for custom statements; the message names the reason, for example the column or the construct

See also

en/wiki/data-conectivity/odata-odbc/reference/supported-sql.txt · Last modified: by Wolfgang van der Stille