数据库自带的行转列函数有哪些呢?这里要介绍PIVOT 和 UNPIVOT 函数了。这两个函数为我们提供了便捷的方式来实现数据表的行列转换。PIVOT 用于旋转数据,将行转为列,UNPIVOT 是其逆操作,将列转为行。
下面是一些示例:
PIVOT 示例:
SELECT * FROM ( SELECT year, month, qty FROM Sales)PIVOT (SUM(qty) FOR month IN ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
在这个例子中,我们将“月份”列中的每个月份转换为了各自的列,并将每个月的销售量总和填充到相应的列中。
UNPIVOT 示例:
SELECT * FROM ( SELECT year, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec FROM Sales) UNPIVOT (qty FOR month IN (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec))
在这个例子中,我们将每个月的列转换为了一个“月份”列,并将相应的销售量总和填充到新的“qty”列中。
目前,Oracle和SQL Server数据库系统都支持 PIVOT 和 UNPIVOT 函数。MySQL和PostgreSQL并不直接支持,但可以通过其他SQL语句实现类似的效果(如上篇文章介绍的方法)。
那如果要转为列的行,它的内容和个数不确定,该怎么办?比如上面示例中的月份不是固定的12个月。
我首先想到的是利用SQL的子查询,比如:
SELECT ...FROM ...PIVOT (SUM(value) FOR column IN (SELECT DISTINCT column FROM ...))
但以上查询在SQL Server中是无效的,这是因为SQL Server和Oracle在编译查询时需要知道所有的列名,而子查询返回的结果直到运行时才知道。
解决此问题的一种常见方法是使用动态SQL,即使用SQL编写并执行SQL语句。这样,你可以先运行一个查询来获取所有唯一的列或行名,然后将这些名字拼接到你的PIVOT或UNPIVOT查询中,最后执行这个查询。
假设我们有一个名为sales的表,其中包含以下数据:
Product | Year | Sale
--------------------------
ProductA | 2019 | 100
ProductA | 2020 | 150
ProductB | 2019 | 200
ProductB | 2020 | 220
ProductC | 2019 | 300
ProductC | 2020 | 350
我们希望按产品进行行列转换,得到以下结果:
Year | ProductA | ProductB | ProductC
--------------------------------------
2019 | 100 | 200 | 300
2020 | 150 | 220 | 350
如果产品的类别是固定的,我们可以使用静态SQL来实现。例如,在SQL Server中,我们可以使用PIVOT操作符:
SELECT Year, [ProductA], [ProductB], [ProductC] FROM (SELECT Product, Year, Sale FROM sales) AS SourceTable PIVOT (SUM(Sale) FOR Product IN ([ProductA], [ProductB], [ProductC])) AS PivotTable;
但是,如果产品的类别是动态的,我们需要使用动态SQL。在SQL Server中,我们可以使用以下方法:
DECLARE @columns NVARCHAR(MAX), @sql NVARCHAR(MAX);
SET @columns = STUFF((
SELECT ',' + QUOTENAME(Product)
FROM sales
GROUP BY Product
ORDER BY Product
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 1, '');
SET @sql = N'SELECT Year, ' + @columns + '
FROM (
SELECT Product, Year, Sale
FROM sales
) AS SourceTable
PIVOT (
SUM(Sale)
FOR Product IN (' + @columns + ')
) AS PivotTable;';
EXEC sp_executesql @sql;
这个例子首先构造了一个包含所有产品的列名的字符串(@columns),然后使用这个字符串来构造PIVOT查询的SQL语句(@sql),最后执行这个SQL语句。
该文章在 2024/2/6 18:47:06 编辑过