sql – 我需要知道如何创建交叉表查询
发布时间:2020-12-12 06:51:41 所属栏目:MsSql教程 来源:网络整理
导读:我需要帮助创建以下结果。我想到了一个sql pivot,但我不知道如何使用它。看了几个例子,无法想出解决方案。关于如何实现这一目标的任何其他想法也是受欢迎的。必须动态生成状态列。 有三个表,资产,资产类型,assetstatus Table: assetsassetid intassettag
我需要帮助创建以下结果。我想到了一个sql pivot,但我不知道如何使用它。看了几个例子,无法想出解决方案。关于如何实现这一目标的任何其他想法也是受欢迎的。必须动态生成状态列。
有三个表,资产,资产类型,assetstatus Table: assets assetid int assettag varchar(25) assettype int assetstatus int Table: assettypes id int typename varchar(20) (ex: Desktop,Laptop,Server,etc.) Table: assetstatus id int statusname varchar(20) (ex: Deployed,Inventory,Shipped,etc.) 期望的结果: AssetType Total Deployed Inventory Shipped ... ----------------------------------------------------------- Desktop 100 75 20 5 ... Laptop 75 56 19 1 ... Server 60 50 10 0 ... 一些数据: assets table: 1,hol1234,1,1 2,hol1233,2 3,hol3421,2,3 4,svr1234,3,1 assettypes table: 1,Desktop 2,Laptop 3,Server assetstatus table: 1,Deployed 2,Inventory 3,Shipped 解决方法这种类型的转换称为枢轴。您没有指定您正在使用的数据库,因此我将为SQL Server和MySQL提供答案。SQL Server:如果您使用的是SQL Server 2005,则可以实现PIVOT功能。 如果您要将已知数量的值转换为列,则可以对查询进行硬编码。 select typename,total,Deployed,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,shipped) ) piv; 见SQL Fiddle with Demo。 但是,如果您具有未知数量的状态值,则需要使用动态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)'),'') set @query = 'SELECT typename,' + @cols + ' from ( select count(*) over(partition by t.typename) total,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 with Demo 这也可以使用带有case表达式的聚合函数编写: select typename,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,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 with Demo MySQL:这个数据库没有pivot函数,所以你必须使用aggregate函数和CASE表达式。它也没有窗口函数,因此您必须稍微更改查询到以下内容: select typename,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 with Demo 然后,如果您需要MySQL中的动态解决方案,则必须使用预准备语句来生成要执行的sql字符串: SET @sql = NULL; SELECT GROUP_CONCAT(DISTINCT CONCAT( 'sum(CASE WHEN statusname = ''',statusname,''' THEN 1 else 0 END) AS `','`' ) ) INTO @sql FROM assetstatus; SET @sql = CONCAT('SELECT typename,',@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 | (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |