5

我有一个UTENSILS包含 3 列的表格,如下所示:

CLASS_NAME   RANGE    COUNT
---------------------------
pens         0-0.5     200
pencil       0-0.5      50
pens         0.5-1.0   300 
pencil       0.5-1.0    40
pens         1.0-1.5   150
pencil       1.0-1.5    45 

我想要一个显示上表结果的查询,如下所示:

RANGE      Pens        Pencils
------------------------------
0-0.5       200          50
0.5-1.0     300          40
1.0-1.5     150          45

有什么想法吗?提前致谢!

4

3 回答 3

3

您正在尝试做的事情被称为PIVOT. 这是您将数据从行转换为列的时候。某些数据库具有PIVOT您可以利用的功能,但您没有指定哪个 RDBMS。

如果您没有PIVOT函数,则可以使用聚合函数和CASE语句来复制该功能:

select `range`,
  sum(case when class_name = 'pens' then `count` end) pens,
  sum(case when class_name = 'pencil' then `count` end) pencils
from yourtable
group by `range`

请参阅带有演示的 SQL Fiddle

range注意:反引号适用于 MySQL,如果 SQL Server 则在and周围使用方括号count。这些用于转义保留字。

如果您在具有PIVOT功能的 RDBMS 中工作,则可以使用以下内容:

select *
from
(
  select class_name, [range], [count]
  from yourtable
) src
pivot
(
  sum([count])
  for class_name in ([pens], [pencil])
) piv

请参阅带有演示的 SQL Fiddle

两者都会产生相同的结果:

|   RANGE | PENS | PENCIL |
---------------------------
|   0-0.5 |  200 |     50 |
| 0.5-1.0 |  300 |     40 |
| 1.0-1.5 |  150 |     45 |

如果您有已知数量的 值,上述方法将非常有用class_name,如果您没有,则根据您的 RDBMS,有一些方法可以生成此查询的动态版本。

在 SQL Server 中,动态版本将类似于:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(CLASS_NAME) 
                    from yourtable
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT [range], ' + @cols + ' from 
             (
                select CLASS_NAME, [RANGE], [COUNT]
                from yourtable
            ) x
            pivot 
            (
                sum([COUNT])
                for CLASS_NAME in (' + @cols + ')
            ) p '

execute(@query)

请参阅带有演示的 SQL Fiddle

于 2012-11-30T11:04:20.627 回答
0

此数据透视查询可用于所有主要的 DBMS。诀窍是获取错误的列名“范围”和“计数”引用属性。

SQL Server(下)使用[],MySQL 使用反引号(`),Oracle 使用双引号,SQLite 可以使用上述任何一种。

  select [range],
         sum(case when class_name='pens' then [count] else 0 end) Pens,
         sum(case when class_name='pencil' then [count] else 0 end) Pencils
    from tbl
group by [range]
order by [range];
于 2012-11-30T11:05:03.497 回答
0

这是枢轴的动态版本:

IF OBJECT_ID('tempdb..#T') IS NOT NULL
    DROP TABLE #T

CREATE TABLE #T(
    [CLASS_NAME] VARCHAR(20) NOT NULL
    , [range] VARCHAR(10) NOT NULL
    , [count] INT NOT NULL
)

INSERT INTO #T([CLASS_NAME], [range], [count]) VALUES ('pens', '0-0.5', '200')
INSERT INTO #T([CLASS_NAME], [range], [count]) VALUES ('pencil', '0-0.5', '50')
INSERT INTO #T([CLASS_NAME], [range], [count]) VALUES ('pens', '0.5-1.0', '300')
INSERT INTO #T([CLASS_NAME], [range], [count]) VALUES ('pencil', '0.5-1.0', '40')
INSERT INTO #T([CLASS_NAME], [range], [count]) VALUES ('pens', '1.0-1.5', '150')
INSERT INTO #T([CLASS_NAME], [range], [count]) VALUES ('pencil', '1.0-1.5', '45')

DECLARE @PivotColumnHeaders VARCHAR(MAX)

SELECT  @PivotColumnHeaders = STUFF((
        --SELECT DISTINCT TOP 100 PERCENT
        SELECT DISTINCT '],[' + [CLASS_NAME]
        FROM #T
        ORDER BY '],[' + [CLASS_NAME]
        FOR XML PATH('')
    ), 1, 2, '') + ']';

DECLARE @PivotTableSQL NVARCHAR(MAX)
SET @PivotTableSQL = N'
  SELECT *
  FROM (
    SELECT *
    FROM #T
  ) AS PivotData
  PIVOT (
    SUM([count])
    FOR [CLASS_NAME] IN (
      ' + @PivotColumnHeaders + '
    )
  ) AS PivotTable
'

EXECUTE(@PivotTableSQL)
于 2012-11-30T11:19:54.400 回答