SQL 将列名更改为单列值的查询

SQL query to change column names to single column value

我正在使用 SQL 服务器。不确定是什么版本,但它仍然受支持。 我有一个 table,其中有 3 个我感兴趣的列。我需要更改 'hardware' 列中的列名,并包含每个列的计数。现在我有以下内容:

SELECT 
    COUNT(a.EAMacBook13) AS 'MacBook13', 
    COUNT(a.EAMacBook16) AS 'MacBook16', 
    COUNT(a.EAStandLaptop) AS 'StandLaptop' 
FROM 
    Employee AS e, EmpAttributes AS a 
WHERE 
    a.EAEmpID = e.EmpID AND e.EmpProjID = 1

我需要这样的东西:

这可能吗?

基本思想是逆轴和计数。如果您的数据库支持横向连接(又名 cross apply)和 values(),您可以:

select x.hardware, count(x.val) cnt
from employee as e
inner join empattributes as ea on ea.eaempid = e.empid 
cross join lateral (values 
    ('EAMacBook13', ea.EAMacBook13), 
    ('EAMacBook16', ea.EAMacBook16), 
    ('EAStandLaptop', ea.EAStandLaptop)
) x(hardware, val)
where e.empprojid = 1
group by x.hardware

有不同的语法可用于横向联接,具体取决于您的数据库。某些数据库使用 cross apply 而不是 cross join lateral

values() 也不是所有地方都支持。例如,在 Oracle 中,您可以将横向连接表述为:

cross apply (
    select 'EAMacBook13' as hardware, EAMacBook13 as val from dual
    union all select 'EAMacBook16', EAMacBook16 from dual
    union all select 'EAStandLaptop', EAStandLaptop from dual
) x(hardware)

如果其中 none 可用,那么我们可以回退到 union all:

select x.hardware, count(x.val) cnt
from employee as e
inner join (
    select eaempid, 'EAMacBook13' as hardware, EAMacBook13 as value from empattributes 
    union all select eaempid, 'EAMacBook16', EAMacBook16 from empattributes 
    union all select eaempid, 'EAStandLaptop', EAStandLaptop from empattributes 
) x on x.eaempid = e.empid 
where e.empprojid = 1
group by x.hardware

你可以用一个简单的 union all 来完成:

SELECT 'MacBook13' "Hardware", Count(a.EAMacBook13) "Count"
FROM Employee as e, EmpAttributes as a WHERE a.EAEmpID = e.EmpID and e.EmpProjID = 1
union all 
SELECT 'MacBook16' "Hardware", Count(a.EAMacBook16)  "Count"
FROM Employee as e, EmpAttributes as a WHERE a.EAEmpID = e.EmpID and e.EmpProjID = 1
union all 
SELECT 'StandLaptop' "Hardware", Count(a.EAStandLaptop)  "Count"
FROM Employee as e, EmpAttributes as a WHERE a.EAEmpID = e.EmpID and e.EmpProjID = 1

根据您的 RDBMS,您可能可以访问 UNPIVOT,这将减少编写。

您也可以使用 CTE,这样(如果您的 RDBMS 支持实现它们)您可以减少工作量:

with cte as (
  SELECT Count(a.EAMacBook13) as EAMacBook13, Count(a.EAMacBook16) as EAMacBook16, Count(a.EAStandLaptop) as EAStandLaptop
  FROM Employee as e, EmpAttributes as a WHERE a.EAEmpID = e.EmpID and e.EmpProjID = 1
)
SELECT 'MacBook13' "Hardware", EAMacBook13 "Count"
FROM  cte
union all 
SELECT 'MacBook16' "Hardware", MacBook16 "Count"
FROM cte
union all 
SELECT 'StandLaptop' "Hardware", StandLaptop "Count"
FROM cte

您必须列出可能的硬件值,除非您使用某种程度的动态 SQL。

一个选项是使用 Dynamic Unpivot。首先用当前查询创建一个 table :

SELECT a.EAMacBook13, a.EAMacBook16, a.EAStandLaptop
  INTO tab
  FROM Employee AS e 
  JOIN EmpAttributes AS a 
    ON a.EAEmpID = e.EmpID
 WHERE e.EmpProjID = 1

然后使用 information_schema.columns :

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

SET  @query = 
    (SELECT STRING_AGG(CONCAT('SELECT ''',SUBSTRING(column_name,3,LEN(column_name)),''' AS Hardware, 
            COUNT(',column_name,') AS Count FROM tab '),' UNION ALL ')
       FROM information_schema.columns
      WHERE table_name = 'tab');

EXEC sp_executesql @query;

Demo