It is possible using unless operator:

item_stock unless item_purchases

Results in a vector consisting of the elements of item_stock for which there are no elements in item_purchases with exactly matching label sets. All matching elements in both vectors are dropped.

Note that the metrics in question do not have 'exactly matching label sets' (name is common but count and in_stock are not). In this case you can use on to set the list of labels to match:

item_stock unless on(name) item_purchases
Answer from anemyte on Stack Overflow
🌐
Robust Perception
robustperception.io › left-joins-in-promql
Left joins in PromQL – Robust Perception | Prometheus Monitoring Experts
December 30, 2019 - Another difference here is that PromQL binary operators work on expressions, whereas a SELECT statement works on tables. So PromQL's joins are more like doing a join over two SQL subqueries rather than than two tables so can have more expressive power.
Discussions

prometheus - Is there a way to express a true "left join" in PromQL? - Stack Overflow
Is there any way to express the equivalent to the SQL "left join" operation in PromQL with vector matching? I want to join on info metrics, but I want to retain the non-info metric even if More on stackoverflow.com
🌐 stackoverflow.com
simpler syntax for joins on labels with different names
Background When doing joins, I usually encounter cases where I want to join through a label that has different names on each side. For example, suppose I have: A container_fs_reads_total metric wit... More on github.com
🌐 github.com
8
October 10, 2024
promql - join prometheus queries while keeping data from the left side - Stack Overflow
I want to build promql query that joins two vectors: one with some metrics and other is informational. The caveat is that info vector doesn't have all the information for "joining label",... More on stackoverflow.com
🌐 stackoverflow.com
prometheus - PromQL "outer-join"-like behaviour - Stack Overflow
Prometheus is lacking outer join functionality. You can see very in-depth description of situation and possible workaround for left outer join from Brian Brazil here. More on stackoverflow.com
🌐 stackoverflow.com
🌐
Grafana
grafana.com › blog › how-to-use-promql-joins-for-more-effective-queries-of-prometheus-metrics-at-scale
How to use PromQL joins for more effective queries of Prometheus metrics at scale | Grafana Labs
August 5, 2021 - Run a single rule per metric that uses a PromQL join to inject the appropriate reference label into the generated series. ... groups: - name: slo_metric expr: count(api_response_latency{labelone="xyz", labeltwo="abc"} > 100) labels: reference_label: xyzabc ... This file would be collected by Grafana Agent. Then the following rule group could be used in Cortex: ... groups: - name: slo_metric expr: count by (reference_label) ((api_response_latency * on (labelone,labeltwo) group_left(reference_label) sli_info > 100)
Top answer
1 of 1
1

Best workaround: union with "or"

The closest I've come uses set operations to execute the query as two branches - one for the "inner join" side, and one that's an anti-join that returns only LHS rows that don't match the RHS. This is very verbose if the LHS is a nontrivial expression instead of a simple stand-alone metric, and it's really inefficient too.

(
  important_metric{}
  * on (join_labels)
    group_left(info_label)
    group by (join_labels, info_label) (
      workload_priorities_info{}
    )
)
# if there's no series on the LHS with the same labels as the RHS after ignoring
# the "info_label" label on each side, add the RHS series to the output, otherwise
# output the LHS series.
or ignoring (info_label)
important_metric{}

with inputs

important_metric{join_labels="1"} 100
important_metric{join_labels="2"} 64
important_metric{join_labels="3"} 5

workload_priorities_info{join_labels="1",info_label="highprio"}
workload_priorities_info{join_labels="3",info_label="lowprio"}

this produces

{join_labels="1",info_label="highprio"} 100
{join_labels="2"} 64
{join_labels="3",info_label="lowprio"} 5

Based on Proposal: PromQL arithmetic with default value, or outer join (issue#13625) this is probably the best workaround that is currently possible.

SQL analogues for comparison

The SQL translation of this would be something like

# inner join to find rows with matching info metrics
SELECT
  important_metric.value * workload_priorities_info.value,
  important_metric.join_labels,
  workload_priorities_info.info_label
FROM important_metric
INNER JOIN workload_priorities_info USING (join_labels)
# append two sets of rows
UNION ALL
# find rows that do NOT have any matching info-metric and append them to
# the result set
SELECT important_metric.value,
  important_metric.join_labels,
  NULL
FROM important_metric
LEFT JOIN INNER JOIN workload_priorities_info USING (join_labels)
WHERE workload_priorities_info.info_label IS NULL

where what we want is the equivalent of

SELECT
  important_metric.value * coalesce(workload_priorities_info.value, 1),
  important_metric.join_labels,
  workload_priorities_info.info_label
FROM important_metric
LEFT JOIN workload_priorities_info USING (join_labels)
🌐
Google Groups
groups.google.com › g › prometheus-users › c › qlHK7r1hQVs
Joining two metrics in promtheus and having all labels from both
March 6, 2023 - > I have tried doing a join but it only seems to bring in one of the `ltmPoolMbrStatusEnabledState` and `ltmPoolMbrStatusAvailState` metrics depending on if its a left or right join, but I would like both to appear.
🌐
Felixhummel
blag.felixhummel.de › 25 › 08-01-til-prometheus-promql-left-join.html
TIL: Prometheus (PromQL) LEFT JOIN — Felix' Wobsite
August 1, 2025 - SELECT * FROM node_exporter_build_info LEFT JOIN node_os_info ON a.foo = b.foo AND a.bar = b.bar
🌐
Reddit
reddit.com › r › PrometheusMonitoring › comments › ehjyl0 › left_joins_in_promql
r/PrometheusMonitoring - Left joins in PromQL
December 30, 2019 - robustperception.io/left-j... 0 comments · share · save · hide · report · 99% Upvoted · Sort by: best · no comments yet · Be the first to share what you think! r/PrometheusMonitoring · Prometheus Monitoring subreddit · 5.3k · Members · 4 · Online · Created Jul 12, 2015 · Join ·
🌐
Iximiuz
iximiuz.com › en › posts › prometheus-vector-matching
Prometheus Cheat Sheet - How to Join Multiple Metrics (Vector Matching)
November 30, 2021 - How to join metrics on matching labels? Vector matching: one-to-one, one-to-many and many-to-one, many-to-many. What on/ignoring clause is for? group_left and group_right explained. Logical/set operations explained.
Find elsewhere
🌐
Yannick Pereira-Reis
ypereirareis.github.io › blog › 2020 › 02 › 21 › how-to-join-prometheus-metrics-by-label-with-promql
How to join Prometheus metrics by label with PromQL – Yannick Pereira-Reis
sum(node_disk_bytes_read * on(instance) group_left(node_name) node_meta{}) by (node_name) on(instance) => this is how to JOIN on label instance.
🌐
SigNoz
signoz.io › guides › how can i 'join' two metrics in a prometheus query? - joining metrics in promql
How can I 'join' two metrics in a Prometheus query? - Joining Metrics in PromQL | SigNoz
July 24, 2024 - PromQL doesn't have explicit inner and outer join operations. Instead, it uses vector matching with modifiers like group_left and group_right to achieve similar results.
🌐
OneUptime
oneuptime.com › home › blog › how to join two metrics in prometheus query
How to Join Two Metrics in Prometheus Query
December 17, 2025 - Learn how to join two metrics in Prometheus using vector matching with on(), group_left(), and group_right(). This guide covers one-to-one, many-to-one, and many-to-many joins with practical examples. By @nawazdhandala • Dec 17, 2025 • Reading time · Prometheus PromQL Vector Matching Joins Metric Monitoring Label Matching Observability
🌐
GitHub
github.com › prometheus › prometheus › issues › 15146
simpler syntax for joins on labels with different names · Issue #15146 · prometheus/prometheus
October 10, 2024 - component/promqlkind/feature · npazosmendez · opened · on Oct 10, 2024 · Issue body actions · When doing joins, I usually encounter cases where I want to join through a label that has different names on each side. For example, suppose I have: A container_fs_reads_total metric with a pod label · A some_custom_pod_info metric with a exported_pod label · To join them, I would do something like: container_fs_reads_total{} * on(pod) group_left label_replace(some_custom_pod_info{}, "pod", "$1", "exported_pod", "(.*)") I find this query verbose for what it's doing, and it usually (if not always), requires me to go through the docs to remind me what the arguments of label_replace are.
Author: prometheus
🌐
InfluxData Documentation
docs.influxdata.com › flux › v0 › stdlib › internal › promql › join
promql.join() function | Flux Documentation
April 8, 2024 - Important: The internal/promql package is not meant for external use. (fn: (left: A, right: B) => C, left: stream[A], right: stream[B]) => stream[C] where A: Record, B: Record, C: Record · For more information, see Function type signatures. (Required) First of two streams of tables to join.
🌐
Last9
last9.io › blog › promql-cheat-sheet
PromQL Cheat Sheet: Queries, Functions, and Labels | Last9
September 12, 2024 - Sometimes, you might want to join time series from two different metrics, but they don’t have matching labels. In that case, you can use group_left() or group_right() to indicate how to join them.
🌐
Google Groups
groups.google.com › g › prometheus-users › c › U9WZyM1HRss › m › ud2rKm-GDwAJ
Perform a left join
I chose "label1" because that is what we want to join on anyway. Note that first part of the "or" expression loses its metric name because of the arithmetic + operation. The label_replace expression after the "or" retains the metric name. ... but the metric name can be eliminated in the second expression with an identity arithmetic operation. metric1 + on(label1) group_left(label3) metric2*0 or label_replace(metric1, "label3", "None", "label1", ".*")+0
🌐
GitHub
github.com › prometheus › prometheus › issues › 3094
Making joins simpler in PromQL · Issue #3094 · prometheus/prometheus
August 20, 2017 - At yesterday's dev summit, and as part of the discussion around prometheus/snmp_exporter#180 , @brian-brazil also suggested making joins easier to write. This issue is to document possible chan...
Author: prometheus
🌐
GitHub
github.com › prometheus › prometheus › issues › 5841
Promql outer join support · Issue #5841 · prometheus/prometheus
August 7, 2019 - Proposal Outer join (especially left join & right join) are very useful. For example: We have one host level CPU alert (CPU > 70%), and we have another spatial aggregation metrics on pool level (host count in a pool). If we wants to get ...
Author: prometheus
🌐
Stack Overflow
stackoverflow.com › questions › 74287092 › promql-join-a-metric-with-a-group-left-with-another-metric-resticted-by-a-boolea
PromQL join a metric with a group left with another metric resticted by a boolean condition - Stack Overflow
The above query returns mi timeseries joined with m2 but "> xxxx" is applied to value of m1 instead of reducing the set of m2 timeseries This could be a syntax m1 > on(...) group left (m2 > xxxx) but, obviously I get a parse error · promql · Share · Improve this question ·