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;
我正在使用 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;