> `user_id`, `currency_id`, and `transaction_amount` are all defined as `NOT
> NULL` columns in `dbo.transactions`

It looks to me that SQL Server has a blanket assumption that an aggregate can produce a `null` even if the field(s) it operates on are `not null`. This is obviously true in certain cases:

    create table foo(bar integer not null);
    select sum(bar) from foo
    -- returns 1 row with `null` field

And is also true in the generalized versions of `group by` like [`cube`](http://msdn.microsoft.com/en-US/library/ms175939(v=SQL.90).aspx)

This simpler test case illustrates the point that any aggregate is interpreted as being nullable:

    CREATE VIEW dbo.balances
    with schemabinding
    AS
    SELECT
          user_id
        , sum(1)   AS balance_amount
    FROM dbo.transactions
    GROUP BY
          user_id
    ;
    GO

IMO this is a limitation (albeit a minor one) of SQL Server - some other RDBMSs allow the creation of certain constraints on views that are not enforced and exist only to give clues to the optimizer, though I think 'uniqueness' is more likely to help in generating a good query plan than 'nullability'

---

If the nullability of the column is important, perhaps for use with an ORM, consider wrapping the indexed view in another view that simply guarantees the non-nullability using `ISNULL`:

    CREATE VIEW dbo.balancesORM
    WITH SCHEMABINDING
    AS
    SELECT 
        B.[user_id],
        B.currency_id,
        balance_amount = ISNULL(B.balance_amount, 0),
        transaction_count = ISNULL(B.transaction_count, 0)
    FROM dbo.balances AS B;

[![SSMS Object Explorer Details][1]][1]


  [1]: https://i.sstatic.net/s9EE3.png