Examples
Practical examples of using Sidemantic for semantic layer queries, from basic metrics to advanced cross-model joins and derived metrics.
Basic Query
YAML
models:
- name: orders
table: orders
primary_key: id
metrics:
- name: revenue
agg: sum
expr: amount
Python
from sidemantic import SemanticLayer, Model, Metric
layer = SemanticLayer()
orders = Model(
name="orders",
table="orders",
primary_key="id",
metrics=[
Metric(name="revenue", agg="sum", expr="amount")
]
)
layer.add_model(orders)
Query with SQL:
layer.sql("SELECT revenue FROM orders")
Or with native Python API:
# Get SQL only
sql = layer.compile(metrics=["orders.revenue"])
# Execute and get results
result = layer.query(metrics=["orders.revenue"])
df = result.fetchdf()
Filtering and Grouping
layer.sql("""
SELECT revenue, status
FROM orders
WHERE status IN ('completed', 'shipped')
""")
Tip
No GROUP BY Needed
The semantic layer automatically groups by dimensions. Just select what you want!
Time Dimensions
YAML
dimensions:
- name: order_date
type: time
expr: order_date
granularity: day
Python
from sidemantic import Dimension
Dimension(
name="order_date",
type="time",
expr="order_date",
granularity="day"
)
# Automatic time grouping
layer.sql("""
SELECT revenue, order_date
FROM orders
""")
Cross-Model Queries
YAML
models:
- name: orders
table: orders
primary_key: id
relationships:
- name: customers
type: many_to_one
foreign_key: customer_id
- name: customers
table: customers
primary_key: id
dimensions:
- name: region
type: categorical
expr: region
Python
from sidemantic import Model, Relationship, Dimension
orders = Model(
name="orders",
table="orders",
primary_key="id",
relationships=[
Relationship(name="customers", type="many_to_one", foreign_key="customer_id")
]
)
customers = Model(
name="customers",
table="customers",
primary_key="id",
dimensions=[
Dimension(name="region", type="categorical", expr="region")
]
)
# Automatic join
layer.sql("""
SELECT orders.revenue, customers.region
FROM orders
""")
Segments (Named Filters)
YAML
models:
- name: orders
segments:
- name: completed
sql: "{model}.status = 'completed'"
- name: high_value
sql: "{model}.amount >= 500"
Python
from sidemantic import Segment
orders = Model(
name="orders",
segments=[
Segment(name="completed", sql="{model}.status = 'completed'"),
Segment(name="high_value", sql="{model}.amount >= 500")
]
)
# Use segments in queries
layer.compile(
metrics=["orders.revenue"],
segments=["orders.completed", "orders.high_value"]
)
Metric-Level Filters
YAML
metrics:
- name: completed_revenue
agg: sum
expr: amount
filters:
- "{model}.status = 'completed'"
Python
Metric(
name="completed_revenue",
agg="sum",
expr="amount",
filters=["{model}.status = 'completed'"]
)
Filters are automatically applied in the WHERE clause whenever the metric is used.
Ratio Metrics
YAML
metrics:
- name: completed_revenue
agg: sum
expr: amount
filters: ["{model}.status = 'completed'"]
- name: total_revenue
agg: sum
expr: amount
- name: completion_rate
type: ratio
numerator: completed_revenue
denominator: total_revenue
Python
Metric(name="completed_revenue", agg="sum", expr="amount",
filters=["{model}.status = 'completed'"]),
Metric(name="total_revenue", agg="sum", expr="amount"),
Metric(name="completion_rate", type="ratio",
numerator="completed_revenue", denominator="total_revenue")
layer.sql("SELECT completion_rate FROM orders")
Derived Metrics
YAML
metrics:
- name: revenue
agg: sum
expr: amount
- name: cost
agg: sum
expr: cost
- name: profit
type: derived
expr: "revenue - cost"
- name: margin
type: derived
expr: "profit / revenue"
Python
Metric(name="revenue", agg="sum", expr="amount"),
Metric(name="cost", agg="sum", expr="cost"),
Metric(name="profit", type="derived", expr="revenue - cost"),
Metric(name="margin", type="derived", expr="profit / revenue")
layer.sql("SELECT revenue, profit, margin FROM orders")
Cumulative Metrics
YAML
metrics:
- name: daily_revenue
agg: sum
expr: amount
- name: running_total
type: cumulative
expr: daily_revenue
window: "7 days"
- name: mtd_revenue
type: cumulative
expr: daily_revenue
grain_to_date: month
Python
Metric(name="daily_revenue", agg="sum", expr="amount"),
Metric(name="running_total", type="cumulative",
expr="daily_revenue", window="7 days"),
Metric(name="mtd_revenue", type="cumulative",
expr="daily_revenue", grain_to_date="month")
layer.sql("""
SELECT order_date, running_total, mtd_revenue
FROM orders
""")
Relative Date Ranges
# Use natural language date ranges in filters
layer.compile(
metrics=["orders.revenue"],
filters=["orders.order_date >= 'last 7 days'"]
)
# Other examples:
# - "today"
# - "yesterday"
# - "last 30 days"
# - "this week"
# - "this month"
# - "this quarter"
# - "this year"
Hierarchies & Drill-Down
YAML
dimensions:
- name: country
type: categorical
expr: country
- name: state
type: categorical
expr: state
parent: country
- name: city
type: categorical
expr: city
parent: state
Python
Dimension(name="country", type="categorical", expr="country"),
Dimension(name="state", type="categorical", expr="state", parent="country"),
Dimension(name="city", type="categorical", expr="city", parent="state")
# Use drill-down API
model.get_hierarchy_path("city") # ['country', 'state', 'city']
model.get_drill_down("state") # 'city'
model.get_drill_up("city") # 'state'
Inheritance
YAML
models:
- name: base_orders
table: orders
dimensions:
- name: status
expr: status
- name: completed_orders
extends: base_orders
metrics:
- name: revenue
agg: sum
expr: amount
Python
base = Model(
name="base_orders",
table="orders",
dimensions=[Dimension(name="status", expr="status")]
)
extended = Model(
name="completed_orders",
extends="base_orders",
metrics=[Metric(name="revenue", agg="sum", expr="amount")]
)
Child models inherit all dimensions, metrics, and relationships from parent.
Jinja2 Templates
YAML
metrics:
- name: filtered_revenue
agg: sum
expr: |
{% if include_tax %}
amount * 1.1
{% else %}
amount
{% endif %}
Python
Metric(
name="filtered_revenue",
agg="sum",
expr="""
{% if include_tax %}
amount * 1.1
{% else %}
amount
{% endif %}
"""
)
layer.compile(
metrics=["orders.filtered_revenue"],
parameters={"include_tax": True}
)
Ungrouped Queries
# Get raw rows without aggregation
layer.compile(
metrics=["orders.revenue"], # Still available
dimensions=["orders.order_id", "orders.customer_id"],
ungrouped=True # No GROUP BY
)
Parameterized Queries
YAML
parameters:
- name: start_date
type: date
default_value: "2024-01-01"
- name: min_amount
type: number
default_value: 100
Python
from sidemantic import Parameter
Parameter(name="start_date", type="date", default_value="2024-01-01"),
Parameter(name="min_amount", type="number", default_value=100)
layer.sql(
"SELECT revenue FROM orders WHERE order_date >= {{ start_date }}",
parameters={"start_date": "2024-06-01"}
)
Warning
Parameter Syntax
DON'T add quotes around {{ param }} - they're added automatically based on type:
- ❌
WHERE date >= '{{ start_date }}'(double quotes!) - ✅
WHERE date >= {{ start_date }}
Multi-Hop Joins
YAML
models:
- name: orders
relationships:
- name: customers
type: many_to_one
foreign_key: customer_id
- name: customers
relationships:
- name: regions
type: many_to_one
foreign_key: region_id
- name: regions
dimensions:
- name: country
type: categorical
expr: country
Python
orders = Model(
name="orders",
relationships=[
Relationship(name="customers", type="many_to_one", foreign_key="customer_id")
]
)
customers = Model(
name="customers",
relationships=[
Relationship(name="regions", type="many_to_one", foreign_key="region_id")
]
)
regions = Model(
name="regions",
dimensions=[
Dimension(name="country", type="categorical", expr="country")
]
)
# Spans 2 hops: orders -> customers -> regions
layer.sql("""
SELECT orders.revenue, regions.country
FROM orders
""")
Multi-Format Loading
Load semantic models from different formats (Cube, LookML, Hex, MetricFlow, etc.) all at once:
from sidemantic import SemanticLayer, load_from_directory
layer = SemanticLayer(connection="duckdb:///data.db")
load_from_directory(layer, "semantic_models/")
# Query across all formats seamlessly
result = layer.query(
metrics=["orders.revenue", "products.avg_price"],
dimensions=["customers.region", "products.category"]
)
load_from_directory() automatically:
- Discovers all
.lkml,.yml,.yamlfiles - Detects the format and parses with the right adapter
- Infers relationships from foreign key naming (
customer_id→customers) - Builds the join graph
See the multi_format_demo for a complete working example with Cube, Hex, and LookML.