You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: devel/docs/ticketsql_grammar.md
+204-1Lines changed: 204 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -764,6 +764,166 @@ Use parentheses to control evaluation order:
764
764
(Status = 'new' OR Status = 'open') AND Priority > 50
765
765
```
766
766
767
+
### CRITICAL: AND/OR Precedence and Parentheses
768
+
769
+
**This section is essential for generating correct queries.** Incorrect parentheses are a common source of bugs that can either return no results or return far more results than intended.
770
+
771
+
#### Operator Precedence Rule
772
+
773
+
**AND has higher precedence than OR.** This means that without explicit parentheses, AND conditions bind together first, then OR connects the results. This is the same as standard SQL and most programming languages.
774
+
775
+
#### The Mandatory Rule
776
+
777
+
**When a query combines AND and OR, you MUST use parentheses to group the OR alternatives together.**
778
+
779
+
The pattern is: `(OR_alternatives) AND filter_condition`
780
+
781
+
Without parentheses, the query will be evaluated incorrectly and return wrong results.
782
+
783
+
#### Correct Patterns to Follow
784
+
785
+
**ALWAYS use these patterns when combining AND with OR:**
786
+
787
+
##### Pattern 1: Multiple Queues with Status Filter
788
+
789
+
**Natural language**: "Open tickets in Support or General queue"
790
+
791
+
```ticketsql
792
+
(Queue = 'Support' OR Queue = 'General') AND Status = 'open'
793
+
```
794
+
795
+
**Natural language**: "New or stalled tickets in the Engineering queue"
796
+
797
+
```ticketsql
798
+
Queue = 'Engineering' AND (Status = 'new' OR Status = 'stalled')
799
+
```
800
+
801
+
##### Pattern 2: Multiple Owners with Additional Filters
802
+
803
+
**Natural language**: "Tickets owned by alice or bob that are high priority"
804
+
805
+
```ticketsql
806
+
(Owner = 'alice' OR Owner = 'bob') AND Priority = 'High'
807
+
```
808
+
809
+
**Natural language**: "Active tickets owned by alice or bob in the Support queue"
810
+
811
+
```ticketsql
812
+
(Owner = 'alice' OR Owner = 'bob') AND Status = '__Active__' AND Queue = 'Support'
813
+
```
814
+
815
+
##### Pattern 3: Multiple Statuses with Queue or Owner Filter
816
+
817
+
**Natural language**: "My tickets that are new or open"
818
+
819
+
```ticketsql
820
+
Owner = '__CurrentUser__' AND (Status = 'new' OR Status = 'open')
821
+
```
822
+
823
+
**Natural language**: "New or stalled tickets in General queue with high priority"
824
+
825
+
```ticketsql
826
+
Queue = 'General' AND (Status = 'new' OR Status = 'stalled') AND Priority = 'High'
827
+
```
828
+
829
+
##### Pattern 4: Multiple Requestors with Filters
830
+
831
+
**Natural language**: "Open tickets from customer@example.com or support@example.com"
832
+
833
+
```ticketsql
834
+
(Requestor = 'customer@example.com' OR Requestor = 'support@example.com') AND Status = 'open'
835
+
```
836
+
837
+
##### Pattern 5: Alternative Conditions with Common Filter
838
+
839
+
**Natural language**: "High priority tickets that are either in Support queue or overdue"
840
+
841
+
```ticketsql
842
+
Priority = 'High' AND (Queue = 'Support' OR Due < 'today')
843
+
```
844
+
845
+
**Natural language**: "My tickets that are either overdue or high priority"
846
+
847
+
```ticketsql
848
+
Owner = '__CurrentUser__' AND (Due < 'today' OR Priority = 'High')
849
+
```
850
+
851
+
##### Pattern 6: Multiple Custom Field Values
852
+
853
+
**Natural language**: "Open tickets in Engineering or Sales department"
854
+
855
+
```ticketsql
856
+
(CF.{Department} = 'Engineering' OR CF.{Department} = 'Sales') AND Status = 'open'
857
+
```
858
+
859
+
**Natural language**: "Active bugs or feature requests"
860
+
861
+
```ticketsql
862
+
Status = '__Active__' AND (CF.{Category} = 'Bug' OR CF.{Category} = 'Feature Request')
863
+
```
864
+
865
+
##### Pattern 7: Complex Multi-Level Grouping
866
+
867
+
**Natural language**: "High priority Support tickets or any Engineering tickets that are open"
868
+
869
+
```ticketsql
870
+
((Queue = 'Support' AND Priority = 'High') OR Queue = 'Engineering') AND Status = 'open'
871
+
```
872
+
873
+
**Natural language**: "Tickets owned by alice in Support or bob in Engineering"
874
+
875
+
```ticketsql
876
+
(Owner = 'alice' AND Queue = 'Support') OR (Owner = 'bob' AND Queue = 'Engineering')
877
+
```
878
+
879
+
##### Pattern 8: Multiple Independent OR Groups
880
+
881
+
**Natural language**: "New or open tickets in Support or General queue"
882
+
883
+
```ticketsql
884
+
(Status = 'new' OR Status = 'open') AND (Queue = 'Support' OR Queue = 'General')
885
+
```
886
+
887
+
Both OR groups need their own parentheses.
888
+
889
+
#### Decision Guide for Parentheses
890
+
891
+
When translating natural language to TicketSQL:
892
+
893
+
1.**Identify the OR conditions**: What alternatives is the user asking for?
894
+
- "Support OR General" → two queue alternatives
895
+
- "new OR open" → two status alternatives
896
+
- "alice OR bob" → two user alternatives
897
+
898
+
2.**Identify the AND conditions**: What filters apply to ALL results?
899
+
- "open tickets" → status filter applies to everything
900
+
- "high priority" → priority filter applies to everything
901
+
- "in my queue" → queue filter applies to everything
902
+
903
+
3.**Group the OR alternatives**: Put parentheses around OR conditions that represent alternatives for the same concept
904
+
905
+
4.**Apply AND conditions outside**: The AND filters should be outside the parenthesized OR group
906
+
907
+
#### When Parentheses Are Optional
908
+
909
+
Parentheses are NOT needed when:
910
+
911
+
1.**Only AND conditions** (no OR):
912
+
```ticketsql
913
+
Queue = 'Support' AND Status = 'open' AND Priority = 'High'
914
+
```
915
+
916
+
2.**Only OR conditions** (no AND):
917
+
```ticketsql
918
+
Queue = 'Support' OR Queue = 'General' OR Queue = 'Sales'
919
+
```
920
+
921
+
3.**OR at the top level with complete AND groups**:
922
+
```ticketsql
923
+
(Queue = 'Support' AND Status = 'open') OR (Queue = 'General' AND Status = 'new')
924
+
```
925
+
Here each OR branch is a complete, self-contained condition.
926
+
767
927
### NOT (via !=)
768
928
TicketSQL uses `!=` rather than explicit NOT:
769
929
```ticketsql
@@ -1406,6 +1566,41 @@ DependsOn IS NOT NULL # Only way to query - check that dependency exists
1406
1566
1407
1567
**Why**: Link fields (DependsOn, RefersTo, etc.) do NOT support subfield syntax. You can only query whether a link exists (`IS NOT NULL`) or query by ticket ID (`DependsOn = 123`). To find tickets depending on open tickets, you would need two queries: first find open tickets, then search for tickets depending on those IDs.
1408
1568
1569
+
### Common Error #15: Missing Parentheses with AND/OR
1570
+
1571
+
**The Rule**: When a query combines AND and OR operators, you MUST wrap the OR alternatives in parentheses.
1572
+
1573
+
AND has higher precedence than OR. Without parentheses, the query will return incorrect results - typically returning far more tickets than intended because one of the OR branches won't be filtered.
1574
+
1575
+
**Correct Examples**:
1576
+
1577
+
"Open tickets in Support or General queue":
1578
+
```ticketsql
1579
+
(Queue = 'Support' OR Queue = 'General') AND Status = 'open'
1580
+
```
1581
+
1582
+
"My tickets that are new or open":
1583
+
```ticketsql
1584
+
Owner = '__CurrentUser__' AND (Status = 'new' OR Status = 'open')
1585
+
```
1586
+
1587
+
"High priority tickets from alice or bob":
1588
+
```ticketsql
1589
+
(Requestor.Name = 'alice' OR Requestor.Name = 'bob') AND Priority = 'High'
1590
+
```
1591
+
1592
+
"Overdue tickets in Support or Sales":
1593
+
```ticketsql
1594
+
(Queue = 'Support' OR Queue = 'Sales') AND Due < 'today'
1595
+
```
1596
+
1597
+
"Active bugs or feature requests":
1598
+
```ticketsql
1599
+
Status = '__Active__' AND (CF.{Type} = 'Bug' OR CF.{Type} = 'Feature')
1600
+
```
1601
+
1602
+
**Key insight**: The OR alternatives (queues, statuses, users, etc.) must be grouped together with parentheses so the AND filter applies to ALL of them.
1603
+
1409
1604
### Translation Decision Tree for AI Systems
1410
1605
1411
1606
When translating natural language to TicketSQL, follow this decision tree:
@@ -1438,13 +1633,21 @@ When translating natural language to TicketSQL, follow this decision tree:
1438
1633
- Column comparisons? → Don't quote the column reference
1439
1634
- Priority strings? → Use Priority = 'High' (if configured) or Priority > 80
1440
1635
1441
-
5.**Validate syntax**:
1636
+
5.**Handle AND/OR combinations** (CRITICAL):
1637
+
- Does the query have both AND and OR? → Apply parentheses rules
1638
+
- Are there OR alternatives that should be filtered by AND conditions? → Wrap OR in parentheses
1639
+
- Example: "open tickets in Support or General" → `(Queue = 'Support' OR Queue = 'General') AND Status = 'open'`
1640
+
- Example: "my tickets that are new or open" → `Owner = '__CurrentUser__' AND (Status = 'new' OR Status = 'open')`
1641
+
- Remember: AND binds tighter than OR, so without parentheses `A OR B AND C` = `A OR (B AND C)`
1642
+
1643
+
6.**Validate syntax**:
1442
1644
- Dates quoted? ✓
1443
1645
- Column references unquoted? ✓
1444
1646
- IS NULL not = NULL? ✓
1445
1647
- Custom role has subfield? ✓
1446
1648
- Time in minutes not hours? ✓
1447
1649
- SHALLOW only on watchers? ✓
1650
+
- AND/OR parentheses correct? ✓ (OR alternatives grouped when filtered by AND)
0 commit comments