It turns out a rather complicated script consisting of dynamic column formation for PIVOT, as well as for other operations. It should be noted that it is formed as a string and the final script will eventually also form a string.
The result is such a Frankenstein
declare @DynamicPivotQuery as nvarchar(max) declare @ColumnName as nvarchar(max) declare @ColumnNameMax as nvarchar(max) declare @ColumnNameSum as nvarchar(max) select @ColumnName= isnull(@ColumnName + ',','') + quotename(p_date) from (select distinct p_date from tbl_payment) as Dates select @ColumnNameMax= isnull(@ColumnNameMax + ',','') + 'max(' + quotename(p_date) + ') as ' + quotename(p_date) from (select distinct p_date from tbl_payment) as Dates select @ColumnNameSum = isnull(@ColumnNameSum + '+','') + 'isnull(' + quotename(p_date) + ', 0)' from (select distinct p_date from tbl_payment) as Dates set @DynamicPivotQuery = N' select inv.inv_id, inv.inv_code, inv.inv_nettotal,' + @ColumnName + ', inv.inv_nettotal - ('+@ColumnNameSum+') as amount_due from tbl_invoice as inv left join ( select inv_id, ' + @ColumnNameMax + ' from tbl_payment pivot(sum(p_amount) for p_date in (' + @ColumnName + ')) as PVTTable group by inv_id) as pay on pay.inv_id = inv.inv_id' exec sp_executesql @DynamicPivotQuery
Of course, the script with the expansion of columns in the horizontal is much better when the names are known in advance. That's how it would look if the dates were fixed. If your application has the ability to define them before sending to the script execution and dynamically generate it, it is better to use it. Or choose a different approach in forming the totals on the client.
select inv.inv_id, inv.inv_code, inv.inv_nettotal, [2016-01-01], [2016-02-08], [2016-02-10], inv.inv_nettotal - (isnull([2016-01-01], 0)+isnull([2016-02-08], 0)+isnull([2016-02-10], 0)) as amount_due from tbl_invoice as inv left join ( select inv_id, max([2016-01-01]) as [2016-01-01],max([2016-02-08]) as [2016-02-08],max([2016-02-10]) as [2016-02-10] from tbl_payment pivot(sum(p_amount) for p_date in ([2016-01-01],[2016-02-08],[2016-02-10])) as PVTTable group by inv_id) as pay on pay.inv_id = inv.inv_id