@Philip, unfortunately,
| summarize dcount(B) by A | where dcount_B > 1;
times out for me, but based on answers to does-a-b-s-where-s-is-a-set-of-tuples-a-b-a-in-a-b, I did find a correct approach that does not time out
// T is the name of a table
// A and B are each a name of a column in the table
let IsOneToOneRelation = (T:(*), A:string, B:string)
{
// 1) Project the requested columns by name (strings) -> ACol, BCol
let S =
T
| project
ACol = column_ifexists(A, ""),
BCol = column_ifexists(B, "")
// | where isnotempty(ACol) and isnotempty(BCol) // and remove rows with empty/null values.
// keep only unique (A,B) pairs to avoid duplicated rows skewing counts
| distinct ACol, BCol;
// 2) Compute the three cardinalities in one go
let Acnt = toscalar(S | distinct ACol | count); // do not use `S | dcount(ACol)` b/c dcount is an estimation
let Bcnt = toscalar(S | distinct BCol | count);
let ABcnt = toscalar(S | count);
// 3) Verdict: bijective iff |pairs| == |A| == |B|
ABcnt == Acnt and ABcnt == Bcnt
};
print IsOneToOneRelation(TenantSnapshot, "Id", "NodeName");