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
sql: 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')
""")
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
sql: 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
sql: 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
sql: 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
sql: amount
filters: ["{model}.status = 'completed'"]
- name: total_revenue
agg: sum
sql: 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
sql: amount
- name: cost
agg: sum
sql: cost
- name: profit
type: derived
sql: "revenue - cost"
- name: margin
type: derived
sql: "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
sql: amount
- name: running_total
type: cumulative
sql: daily_revenue
window: "7 days"
- name: mtd_revenue
type: cumulative
sql: 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
sql: country
- name: state
type: categorical
sql: state
parent: country
- name: city
type: categorical
sql: 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
sql: status
- name: completed_orders
extends: base_orders
metrics:
- name: revenue
agg: sum
sql: 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.
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 Filters (Deprecated)
YAML
# Parameters are not loaded from YAML.
# Register them in Python via layer.graph.add_parameter().
Python
from sidemantic import Parameter
layer.graph.add_parameter(Parameter(name="start_date", type="date", default_value="2024-01-01"))
layer.graph.add_parameter(Parameter(name="min_amount", type="number", default_value=100))
sql = layer.compile(
metrics=["orders.revenue"],
filters=[
"orders.order_date >= {{ start_date }}",
"orders.amount >= {{ min_amount }}"
],
parameters={"start_date": "2024-06-01", "min_amount": 250}
)
Parameter Syntax and Scope
Parameters are deprecated and only interpolated in query() / compile() filters.
The SQL interface (layer.sql) does not render {{ ... }}.
DON'T add quotes around {{ param }} - they're added automatically by the parameter 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
sql: 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
.sql,.lkml,.malloy,.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.