Грязно, но работает
select c.categoryid,c.categoryname
,COALESCE((select top 1 categoryorder from categoryposition where categoryid=c.categoryid and positionid=1),0) as [top]
,COALESCE((select top 1 categoryorder from categoryposition where categoryid=c.categoryid and positionid=2),0) as [left]
,COALESCE((select top 1 categoryorder from categoryposition where categoryid=c.categoryid and positionid=3),0) as [right]
from categoryposition cp,category c
where cp.categoryid=c.categoryid
group by c.categoryid,c.categoryname
order by 1
Две вещи, которые нужно иметь в виду. Если вы можете убедиться, что для каждой позиции категории существует не более одной позиции, вы можете удалить верхнюю 1, но подзапрос должен вернуть 1 строку или ничего, чтобы он работал.