I'm trying to create a call to odata webservice that would select only distinct values of some property. Is there any good example of how to do this?
2 Answers
Currently the OData protocol doesn't support the distinct operator, or any other operator which would help with such query (assuming you're looking for disctinct values of a primitive property on some entity). You should be able to workaround this by implementing a service operation on the server which performs such query on the underlying provider which usually has that ability. And then the client can call that service operation instead.

- 13,130
- 1
- 34
- 30
-
Yeh, since OData protocol doesn't support such simple operation the only workaround seems to be to implement it yourself. Thank you for your answer. – igorti Oct 02 '10 at 14:39
-
12
-
7
-
1
-
Just to be clear, OData v4 has had support for distinct from the start, it is part of the OASIS specification and the .Net Web API has always supported simple implementations OOTB. – Chris Schaller Jan 25 '19 at 02:02
-
1
-
1@ChrisSchaller - where is it? I just checked odata.org and don't see any mention of it in any of the v4 documents. – absmiths Sep 09 '19 at 15:09
-
1@absmiths Distinct is specifically mentioned in the spec: http://docs.oasis-open.org/odata/odata-data-aggregation-ext/v4.0/cs01/odata-data-aggregation-ext-v4.0-cs01.html#_Toc378326329 but the simple syntax specified is not supported by ODataLib, hence my response https://stackoverflow.com/a/54357853/1690217 – Chris Schaller Sep 09 '19 at 23:54
-
4
-
1
-
13
-
1
Note: I know this is old, but still shows up in search responses. There is now a good solution to this problem.
In OData v4, there is support for $apply, amongst other things, $apply
can be used to return a distinct set of fields from a result set.
See related discussion: Applying Distinct to ODataQuery
from the OData v4 spec,
The query option$apply
takes a sequence of set transformations, separated by forward slashes to express that they are consecutively applied, e.g. the result of each transformation is the input to the next transformation $apply is a function that requires
tl;dr;
Basically, if I have a table that has many fields, but I want to return just the distinct records of a number of specific fields the first step is to identify the distinct columns, lets call them Name
and Id
.
Simply use the $apply
function to get a distinct result set containing just the Names and Id columns with syntax like this:
http://url.to/tableresource?$apply=groupby((Name,Id))
Lets do this by example, TuberInspections
has 1000s of rows, but only a few contractors, I want to display the names of the contractors in a drop down list to use in a filtering query.
My distinct columns are ContractorName
and ContractorId
GET /odata/TuberInspections?$apply=groupby((ContractorName,ContractorId)) HTTP/1.1
Host: localhost:1230
Response:
{
"@odata.context": "http://localhost:1230/odata/$metadata#TuberInspections(ContractorName,ContractorId)",
"value": [
{
"@odata.id": null,
"ContractorId": 11534,
"ContractorName": "Kermit d'Frog"
},
{
"@odata.id": null,
"ContractorId": 11539,
"ContractorName": "Carlos Spicy Wiener"
},
{
"@odata.id": null,
"ContractorId": 16827,
"ContractorName": "Jen Gelfling"
}
]
}
If your data structure is no flat enough, there is limited OOTB support for retrieving simple nested results structures.
If his data structure is hard to consume and you have control over the API, then you should consider creating a custom Function to return the specific recordset that you desire, that is trivial exercise that has many different options available to you, but outside of the scope of this response.
This response is directed at how to query an existing OData service for distinct values, not how to modify a service to provide such information.
Currently only a single navigation path is supported with the following syntax. The above query can also be written as:
GET /odata/TuberInspections?$apply=groupby((Contractor/EntityID,Contractor/Initials))
Host: localhost:1230
Response:
{
"@odata.context": "http://localhost:1230/odata/$metadata#TuberInspections(Contractor(EntityID,Initials))",
"@odata.count": 3,
"value": [
{
"@odata.id": null,
"Contractor": {
"@odata.id": null,
"Initials": "KdF",
"EntityID": 11534
}
},
{
"@odata.id": null,
"Contractor": {
"@odata.id": null,
"Initials": "SW",
"EntityID": 11539
}
},
{
"@odata.id": null,
"Contractor": {
"@odata.id": null,
"Initials": "Jen",
"EntityID": 16827
}
}
]
}
There are more advanced (complicated) variations to nested or stacked $apply
transformations that include returning a count of the number of unique rows that correspond to each of the distinct results.
Including a
$count
of distinct records within the group is sort of documented here System Query Option $apply - groupby and in response to OData v4 groupby with $countGroupBy supports an aggregate extension, so we can use this in the previous URL, remember to alias the projected column name.
groupby((Contractor/EntityID,Contractor/Initials),aggregate($count as Items))
the response now includes the count:
{ "@odata.id": null, "Items": 260, "Contractor": { "@odata.id": null, "Initials": "SW", "EntityID": 11539 } },
For more information please post specific questions and tag with OData-v4 and you'll find all the help you need :)

- 13,704
- 3
- 43
- 81
-
That seems akin to using select a,b group by a,b to get what should be select distinct a,b. I still like the concept of a distinct operator - I don't want to implement a data transformation service. – absmiths Sep 09 '19 at 15:21
-
In it's essence, distinct and group by take the same server resources and are the same computation, it makes sense to only have one response type to cover the two scenarios. The issue has been how to define the standard response within the specification. In many cases where a distinct query is used, it can be useful to have the count of items that match, if the structure is not altered, then one has to assume as part of the OData spec, that each row has a unique id at the corresponding resource, but because we have only requested the unique values, there is no unique key. – Chris Schaller Sep 09 '19 at 23:41
-
If you have control over the service code, then by all means create a function that returns just the distinct record set that you desire :) this response is more around how to query an existing or 3rd party API for a distinct record set. I am 100% behind custom endpoints to facilitate ease of use at the client end. – Chris Schaller Sep 09 '19 at 23:43
-
@ChrisSchaller in the second to last paragraph, you mention being able to also return the count of the unique rows. could you show me what that url would look like? having trouble finding it in the odata documentation – A. Dixon Oct 28 '20 at 16:45
-
@A.Dixon just use the standard `aggregate` component of the `groupby` function, it's detailed here https://stackoverflow.com/a/58620281/1690217 but I'll add an example into my answer – Chris Schaller Oct 29 '20 at 01:33
-
Just for some closure (for me) @A.Dixon I use this pattern a lot with faceted search interfaces, so when showing the list of facets (or slices) to choose from I include the the count of expected items. – Chris Schaller Oct 29 '20 at 23:49
-
@ChrisSchaller that’s what I’m needing it for. To show the expected number of child properties for the filter. See my question here: https://stackoverflow.com/q/64392114/9069327 – A. Dixon Oct 30 '20 at 01:15
-
I tried using this with Dynamics 365 OData but it doesn't seem to work. It just ignores the `$apply` function and returns the full result set. – FullStackOverflowDev Jan 14 '21 at 15:25
-
1$apply is not in the list of supported query options for Dynamics 365: https://learn.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/data-entities/odata#supported-features-from-the-odata-specification – Chris Schaller Jan 14 '21 at 20:46