Ten typ przemiany nazywa się pivot. Nie określiłeś, z której bazy danych korzystasz, więc udzielę odpowiedzi na SQL Server i MySQL.
SQL Server: Jeśli używasz SQL Server 2005+ można realizować funkcję PIVOT
.
Jeśli masz znaną liczbę wartości, które chcesz przekonwertować na kolumny, wówczas możesz zakodować zapytanie.
select typename, total, Deployed, Inventory, shipped
from
(
select count(*) over(partition by t.typename) total,
s.statusname,
t.typename
from assets a
inner join assettypes t
on a.assettype = t.id
inner join assetstatus s
on a.assetstatus = s.id
) d
pivot
(
count(statusname)
for statusname in (Deployed, Inventory, shipped)
) piv;
Zobacz SQL Fiddle with Demo.
Ale jeśli masz nieznaną liczbę wartości status
, będziesz musiał użyć dynamicznego sql do wygenerowania listy kolumn w czasie wykonywania.
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT distinct ',' + QUOTENAME(statusname)
from assetstatus
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT typename, total,' + @cols + ' from
(
select count(*) over(partition by t.typename) total,
s.statusname,
t.typename
from assets a
inner join assettypes t
on a.assettype = t.id
inner join assetstatus s
on a.assetstatus = s.id
) x
pivot
(
count(statusname)
for statusname in (' + @cols + ')
) p '
execute(@query)
Zobacz SQL Fiddle with Demo
To również może być napisane przy użyciu łączną funkcję danej sprawie wyrażenia:
select typename,
total,
sum(case when statusname ='Deployed' then 1 else 0 end) Deployed,
sum(case when statusname ='Inventory' then 1 else 0 end) Inventory,
sum(case when statusname ='Shipped' then 1 else 0 end) Shipped
from
(
select count(*) over(partition by t.typename) total,
s.statusname,
t.typename
from assets a
inner join assettypes t
on a.assettype = t.id
inner join assetstatus s
on a.assetstatus = s.id
) d
group by typename, total
Zobacz SQL Fiddle with Demo
MySQL: Ta baza zrobić nie ma funkcji przestawnej pivot, więc będziesz musiał użyć funkcji agregującej i wyrażenia CASE
. To również nie ma funkcji okienkowania, więc trzeba będzie zmienić zapytanie nieco na następujące kwestie:
select typename,
total,
sum(case when statusname ='Deployed' then 1 else 0 end) Deployed,
sum(case when statusname ='Inventory' then 1 else 0 end) Inventory,
sum(case when statusname ='Shipped' then 1 else 0 end) Shipped
from
(
select t.typename,
(select count(*)
from assets a1
where a1.assettype = t.id
group by a1.assettype) total,
s.statusname
from assets a
inner join assettypes t
on a.assettype = t.id
inner join assetstatus s
on a.assetstatus = s.id
) d
group by typename, total;
Zobacz SQL Fiddle with Demo
Następnie jeśli potrzebujesz dynamiczne rozwiązanie w MySQL, trzeba będzie użyć przygotowane oświadczenie wygenerować ciąg SQL do wykonania:
SET @sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'sum(CASE WHEN statusname = ''',
statusname,
''' THEN 1 else 0 END) AS `',
statusname, '`'
)
) INTO @sql
FROM assetstatus;
SET @sql
= CONCAT('SELECT typename,
total, ', @sql, '
from
(
select t.typename,
(select count(*)
from assets a1
where a1.assettype = t.id
group by a1.assettype) total,
s.statusname
from assets a
inner join assettypes t
on a.assettype = t.id
inner join assetstatus s
on a.assetstatus = s.id
) d
group by typename, total');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Zobacz SQL Fiddle with Demo.
Rezultat jest taki sam dla wszystkich zapytań w obu bazach danych:
| TYPENAME | TOTAL | DEPLOYED | INVENTORY | SHIPPED |
-----------------------------------------------------
| Desktop | 2 | 1 | 1 | 0 |
| Laptop | 1 | 0 | 0 | 1 |
| Server | 1 | 1 | 0 | 0 |
Co RDBMS używasz? – Taryn
Skąd pochodzą wartości wdrożone (75, 56, 50)? Nie pojawiają się w twoich danych. –
To nie ma dla mnie większego sensu w tej chwili Czy masz kilka przykładów tego, co jest w twoich tabelach, kilka rzeczywistych wierszy ... Musi istnieć pewna wspólność między tabelami jako punktem odniesienia do Połącz je ze sobą ... Jeśli podasz ten szczegół, będę musiał się z tym pogodzić. –