Final implementation
I experimented a bit and related to my upper possibilities is this outcome:
Not entirely possible with just multiple joins. Grouping would have to be implemented as well which makes resulting query too complex and a lot less maintainable
Requires upper layer post processing to parse concatenated data. Haven't implemented it because it would require more upper layer code changes which would also be more bound to the data layer than desired.
I prepared a CTE that generated content interaction data grouped by content items and users and joining results to original query. Runs fine and works as expected. The tricky part is to filter data within each group of records to only count particular interactions (see below).
A similar approach to #3 is using
pivot
relational operator and I also implemented that, although prepared pivoted data also needs to be grouped beforehand to get one record per item.
Between #3 and #4 I decided to go with #3 as it had a better execution plan.
Filtering within record group solution
As stated in #3 (final implementation) to make my query perform as it should I had to only group once and then filter data within each group of records to get info about individual content interactions.
As I only needed an indication whether a particular user interacted on a content item all these return boolean (SQL bit
type). The best part is to use a function within count
aggregation so that only particular records within group are used.
with Interactions (Id, UpVoted, DownVoted)
as (
select
p.Id,
cast(count(iif(pa.ActionTypeId = @UpVoteType, 1, null)) as bit),
cast(count(iif(pa.ActionTypeId = @DownVoteType, 1, null)) as bit)
from PostActions pa
join Posts p
on (p.Id = pa.PostId)
where pa.UserId = @UserId
group by p.Id
)
select
...
isnull(i.UpVoted, 0) as UpVoted,
isnull(i.DownVoted, 0) as DownVoted
from Posts p
...
left join Interactions i
on (p.Id = i.Id)
where ...
order by ...
The good thing with count
is that it only counts non null records so I took advantage of this fact to filter out individual specific user interactions within the same group related to content item.
COUNT
is my new love. :)