---
title: How do I filter OData results by date or property in Power BI?
description: Filtering OData URLs
---

[Skip to content](https://support.weeversoftware.com/odata-filter#main-content)

[Submit a Support Issue](https://support.weeversoftware.com/kb-tickets/new?hsLang=en)

[![Weever-wordmark-darkgreen-4](https://support.weeversoftware.com/hs-fs/hubfs/Weever-wordmark-darkgreen-4.png?width=112&height=24&name=Weever-wordmark-darkgreen-4.png)](http://weeversoftware.com/)

Open main navigation

Close main navigation

- [Submit a Support Issue](https://support.weeversoftware.com/kb-tickets/new)

 How can we help you?

- There are no suggestions because the search field is empty.

1. [Weever Knowledge Base](https://support.weeversoftware.com/?hsLang=en)
2. [Power BI](https://support.weeversoftware.com/power-bi?hsLang=en)
3. [Reporting Tips](https://support.weeversoftware.com/power-bi?hsLang=en#reporting-tips)

# How do I filter OData results by date or property in Power BI?

## Speed up your data refreshes by filtering your OData tables

Filters let you control how much data your OData connection pulls in by telling it to only return rows that match certain conditions. Instead of loading everything and filtering inside your reporting tool, you're trimming the data at the source — which means faster load times and cleaner reports.

### **How it works**

You add a filter by appending a `$filter` parameter to the end of your OData entity URL. The format looks like this:

`?$filter=PropertyName operator 'value'`

For example, to return only inspections updated after January 1, 2024:

`?$filter=UpdatedAt gt '2024-01-01T00:00:00Z'`

You can combine multiple filters using `and`:

`?$filter=UpdatedAt gt '2024-01-01T00:00:00Z' and CompletedAt gt '2024-01-01T00:00:00Z'`

> **Note:** Filters are applied to specific entity URLs (like `/schedules` or `/scheduledinspections`), not the root URL (like `/inspections`).

Filters must be applied to OData URLs that include the form name. For example: 

https://api.prod.weeverapps.com/v1/odata/v0/site/forms/Centerlines\_323-ab38-456c-4324-80836-0352235?$filter=Form\_Created\_Date

### **Filter operators**

| Operator | Meaning | Example |
| --- | --- | --- |
| `eq` | equals | `Status eq 'Open'` |
| `ne` | does not equal | `Status ne 'Closed'` |
| `lt` | less than | `DueAt lt '2024-06-01T00:00:00Z'` |
| `le` | less than or equal to | `DueAt le '2024-06-01T00:00:00Z'` |
| `gt` | greater than | `CreatedAt gt '2024-01-01T00:00:00Z'` |
| `ge` | greater than or equal to | `CreatedAt ge '2024-01-01T00:00:00Z'` |

### Filtering by date range in Power BI (recommended)

If you add filters in Power BI the usual way, Power BI can still send far more requests to the OData service than it needs. The query below only sends the requests it needs, for the start and end dates you set.

**How it works**

- It sends one request for a single row, just to learn the column names.
- It pulls data in pages of 5,000 rows, only for your date range.
- Everything after that, like removing duplicates and setting data types, happens inside Power Query. That step sends no extra requests.

**Step 1: Set your start and end dates**

1. In Power BI Desktop, select **Transform data** to open Power Query.
2. Go to **Home \> Manage Parameters \> New Parameter**.
3. Create a parameter named `RangeStart` with the **Date/Time** type, and enter your start date.
4. Create a parameter named `RangeEnd` with the **Date/Time** type, and enter your end date.

The names have to be exactly `RangeStart` and `RangeEnd`. If you use [incremental refresh](https://support.weeversoftware.com/incremental-refresh?hsLang=en), Power BI fills in these dates for you on every refresh.

**Step 2: Add the query**

1. In Power Query, select **Home \> New Source \> Blank Query**.
2. Select **Advanced Editor**, delete any text that's already there, and paste in the query below.
3. Select **Done**, then **Close & Apply**.

```
let    base_url = "https://odata.weeverapps.com/v1/odata/<your-site>/inspections",    relPath  = "ScheduledInspections",    PageSize = 5000,    KeyCols  = {"InspectionId"},    startDate = DateTime.ToText(RangeStart, "yyyy-MM-ddTHH:mm:ssZ"),    endDate   = DateTime.ToText(RangeEnd,   "yyyy-MM-ddTHH:mm:ssZ"),    filter    = "DueAt gt " & startDate & " and DueAt lt " & endDate,    Expected =        let            s = try Json.Document(Web.Contents(base_url, [RelativePath=relPath, Query=[#"$top"="1"]]))[value] otherwise {}        in            if List.Count(s) > 0            then List.Distinct(List.Combine(List.Transform(s, each Record.FieldNames(_))))            else {},    GetPage = (skip as number) as list =>        try            Json.Document(                Web.Contents(base_url, [                    RelativePath = relPath,                    Query = [                        #"$filter" = filter,                        #"$top"    = Text.From(PageSize),                        #"$skip"   = Text.From(skip)                    ]                ])            )[value]        otherwise {},    Pages =        List.Generate(            () => [skip=0, v=GetPage(0)],            each List.Count([v])>0,            each [skip=[skip]+PageSize, v=GetPage([skip])],            each [v]        ),    Rows = List.Combine(Pages),    AllFields =        if List.Count(Rows) = 0 then {}        else List.Distinct(List.Combine(List.Transform(Rows, each Record.FieldNames(_)))),    Cols = List.Distinct(Expected & AllFields),    Raw =        if List.Count(Cols) = 0 then #table({}, {})        else Table.FromRecords(Rows, Cols, MissingField.UseNull),    NoErrors = try Table.ReplaceErrorValues(Raw, List.Transform(Table.ColumnNames(Raw), each {_, null})) otherwise Raw,    SafeDistinct = (tbl as table, keys as list) as table =>        let            present = List.Select(keys, each Table.HasColumns(tbl, _))        in            if List.Count(present) = 0 then try Table.Distinct(tbl) otherwise tbl            else try Table.Distinct(tbl, present) otherwise tbl,    T = SafeDistinct(NoErrors, KeyCols),    Final =        let            SafeTypeCol = (tbl as table, col as text) as table =>                let                    sample     = List.First(List.RemoveNulls(Table.Column(tbl, col)), null),                    targetType =                        if sample is list or sample is record then type any                        else if sample is datetimezone then type datetimezone                        else if sample is datetime     then type datetime                        else if sample is date         then type date                        else if sample is number       then type number                        else if sample is logical      then type logical                        else if sample is text         then type text                        else type any,                    result = try Table.TransformColumnTypes(tbl, ) otherwise tbl                in                    result,            TypedT = List.Accumulate(Table.ColumnNames(T), T, (s, c) => SafeTypeCol(s, c))        in            if List.Count(Expected) = 0            then TypedT            else Table.SelectColumns(TypedT, Expected, MissingField.UseNull)in    Final
```

**Step 3: Reuse it for any inspection or form**

To use this query for another table, change these 4 things:

1. **URL:** Update `base_url` and `relPath` for the new form.
2. **Start and end dates:** Make sure the `RangeStart` and `RangeEnd` parameters exist and use the Date/Time type. You don't need to change any code for this.
3. **Date column:** In the `filter` line, replace `DueAt` with the date column that fits the form. Use one of the filterable columns listed below.
4. **Unique key:** In `KeyCols`, set the column that identifies each row, like `InspectionId`.

### **What you can filter on**

Not every column supports filtering. Below is a full list of filterable columns by table.

**A few things to keep in mind**

- Dates must be formatted as `'YYYY-MM-DDTHH:MM:SSZ'` (e.g. `'2024-01-01T00:00:00Z'`)
- Only `and` is supported for combining filters — `or` is not available
- Columns not listed above don't support filtering and will return an error if used

#### **Weever Forms**

*Submission data (all form tables)* :    `_id`, `Form_Created_Date`, `Form_Created_By`, `Form_Created_By_Email`, `Form_Updated_Date`, `Ticket_Created_Date`, `Ticket_Updated_Date`, `Ticket_Updated_By`, `Ticket_Updated_By_Email`, `Ticket_Status`, `Ticket_Time_To_Close`, `Ticket_Assignee`, `Ticket_Assignee_Email`, `Ticket_Comments`, `Ticket_Due_Date`

> **Note:** For forms, filter property names must be written in camelCase (e.g. `FormCreatedDate`, not `Form_Created_Date`).

*FormMetrics:*     `Date`, `FolderId`, `FolderName`, `FormId`, `FormName`, `FormCreatedAt`, `FormDeletedAt`, `FormStatus`, `SubmissionsTotal`, `UniqueSubmittersTotal`, `SubmissionsPointsTotal`

*User :*     `Id`, `FirstName`, `LastName`, `Email`, `UserType`, `Status`, `JoinedAt`, `LatestUpdatedAt`, `PhoneNumber`, `EmployeeNumber`, `TicketCreatorNotificationsEnabled`, `LatestFormSubmissionAt`

*DatabaseItem :*     `DatabaseId`, `DatabaseName`, `TierId`, `TierName`, `TierLevel`, `Id`, `ParentId`, `Name`, `Note`, `Status`, `CreatedAt`, `UpdatedAt`, `ArchivedAt`

---

#### **Weever Inspections**

*Schedules:*     `ScheduleId`, `InspectionTypeId`, `InspectionTypeName`, `AssetId`, `AssetName`, `FormId`, `FormName`, `ShiftId`, `ShiftName`, `AssigneeId`, `AssigneeName`, `Frequency`, `DayOfWeek`, `StartDate`, `ExpectedDurationMinutes`, `Status`, `Note`, `CreatedAt`, `CreatedById`, `UpdatedAt`, `UpdatedById`

*ScheduledInspections:*     `ScheduleId`, `InspectionId`, `InspectionTypeId`, `InspectionTypeName`, `AssetId`, `AssetName`, `FormId`, `FormName`, `FormSubmissionId`, `ShiftId`, `ShiftName`, `AssigneeId`, `AssigneeName`, `ExpectedDurationMinutes`, `TotalChecks`, `PassedChecks`, `FailedChecks`, `NAChecks`, `Status`, `DueAt`, `CompletedAt`, `CompletedById`, `CompletedByName`, `UpdatedAt`, `UpdatedById`, `UpdatedByName`

---

#### **Weever Process**

*Process submissions :*     `FormId`, `FormName`, `Id`, `Status`, `CreatedAt`, `UpdatedAt`, `SkippedAt`, `SkippedByName`, `SkippedReason`, `UpdatedByEmail`

*Process* :    `ProcedureId`, `CategoryId`, `CategoryName`, `DepartmentId`, `DepartmentName`, `LineWorkAreaId`, `LineWorkAreaName`, `Id`, `Name`, `Status`, `StartedAt`, `StartedById`, `StartedByEmail`, `StartedByName`, `LastUpdatedAt`, `ClosedAt`, `ClosedById`, `ClosedByEmail`, `ClosedByName`, `SummaryFormId`, `SummaryFormVersion`, `SummaryFormName`, `SummarySubmissionId`, `SummarySubmissionVersion`, `SummarySubmissionStatus`, `SummarySubmissionCreatedAt`, `SummarySubmissionUpdatedAt`

*ProcessTask* :    `ProcedureId`, `ProcedureVersion`, `CategoryId`, `CategoryName`, `DepartmentId`, `DepartmentName`, `LineWorkAreaId`, `LineWorkAreaName`, `MachineId`, `MachineName`, `ProcessId`, `ProcessName`, `StepId`, `StepName`, `StepSortOrder`, `Id`, `Name`, `SortOrder`, `CreatedAt`, `UpdatedAt`, `UpdatedById`, `UpdatedByEmail`, `DueAt`, `Status`, `Priority`, `RepetitionValue`, `RepetitionUnits`, `RoleId`, `RoleName`, `AssigneeId`, `AssigneeEmail`, `FormId`, `FormVersion`

*Department, LineWorkArea, MachineType, Machine, Shift :*     `Id`, `Name`, `Status`, `Notes`, `CreatedAt`, `UpdatedAt`, `DeletedAt` (plus `DepartmentId` / `LineWorkAreaId` / `MachineTypeId` where applicable)

*User (Process)* :    `Id`, `Email`, `FirstName`, `LastName`, `Phone`, `EmployeeType`, `Status`, `StatusReason`, `CreatedAt`, `UpdatedAt`, `DeletedAt`, `PasswordChangedAt`, `ResetPasswordSentAt`, `CurrentSignInAt`, `LastSignInAt`, `CurrentSignInIp`, `LastSignInIp`, `SignInCount`

---

#### Interested in learning more about Weever? [Book a demo](https://weeversoftware.com/book-a-demo)

[![Weever-wordmark-darkgreen-4](https://support.weeversoftware.com/hs-fs/hubfs/Weever-wordmark-darkgreen-4.png?width=234&height=50&name=Weever-wordmark-darkgreen-4.png "Weever-wordmark-darkgreen-4")](https://weeverapps.com)

Weever Knowledge Base

<https://www.facebook.com/WeeverApps/> <https://www.linkedin.com/company/weever-apps-inc->

Copyright © 2026, Weever