25

以下の結果を作成するのに助けが必要です。SQLピボットを考えましたが、使い方がわかりません。いくつかの例を見て、解決策を思い付くことができません。これを達成する方法に関する他のアイデアも大歓迎です。ステータス列は動的に生成する必要があります。

assets、assettypes、assetstatus の 3 つのテーブルがあります。

表: 資産
資産 ID 整数
assettag varchar(25)
資産タイプ int
資産ステータス int

表: アセットタイプ
id int
typename varchar(20) (例: デスクトップ、ラップトップ、サーバーなど)

表: 資産の状態
id int
statusname varchar(20) (例: 配備済み、在庫、出荷済みなど)

望ましい結果:

AssetType デプロイされたインベントリの合計 出荷された ...
-------------------------------------------------- ----------
デスクトップ 100 75 20 5 ...
ラップトップ 75 56 19 1 ...
サーバー 60 50 10 0 ...

一部のデータ:

アセット テーブル:
1,hol1234,1,1
2,hol1233,1,2
3,hol3421,2,3
4,svr1234,3,1

資産タイプ表:
1、デスクトップ
2、ラップトップ
3、サーバー

assetstatus テーブル:
1,配備済み
2、在庫
3、出荷
4

2 に答える 2

53

このタイプの変換はピボットと呼ばれます。使用しているデータベースを指定しなかったため、SQL Server と MySQL について回答します。


SQL Server: SQL Server 2005+ を使用している場合は、PIVOT関数を実装できます。

列に変換したい既知の数の値がある場合は、クエリをハードコーディングできます。

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;

SQL Fiddle with Demoを参照してください。

ただし、値の数が不明な場合はstatus、実行時に動的 SQL を使用して列のリストを生成する必要があります。

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)

デモで SQL Fiddle を参照してください

これは、case 式を含む集計関数を使用して記述することもできます。

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

デモで SQL Fiddle を参照してください


MySQL:このデータベースにはピボット関数がないため、集計関数とCASE式を使用する必要があります。また、ウィンドウ機能がないため、クエリを次のように少し変更する必要があります。

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;

デモで SQL Fiddle を参照してください

次に、MySQL で動的なソリューションが必要な場合は、準備済みステートメントを使用して、実行する SQL 文字列を生成する必要があります。

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;

SQL Fiddle with Demoを参照してください。

結果は、両方のデータベースのすべてのクエリで同じです。

| TYPENAME | TOTAL | DEPLOYED | INVENTORY | SHIPPED |
-----------------------------------------------------
|  Desktop |     2 |        1 |         1 |       0 |
|   Laptop |     1 |        0 |         0 |       1 |
|   Server |     1 |        1 |         0 |       0 |
于 2013-03-30T03:00:48.097 に答える