我需要知道如何创建交叉表查询

2024-04-12

我想动态生成状态列。

有三张表,资产、资产类型、资产状态



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,1,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服务器:如果您使用的是 SQL Server 2005+,您可以实施PIVOT功能。

如果您有已知数量的想要转换为列的值,那么您可以对查询进行硬编码。

select typename, total, Deployed, Inventory, 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, Inventory, shipped)
) piv;

See SQL 摆弄演示 http://www.sqlfiddle.com/#!3/d7915/5.

但如果你有未知数量的status值,那么您将需要使用动态 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)') 
        ,1,1,'')

set @query = 'SELECT typename, total,' + @cols + ' 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
            ) x
            pivot 
            (
                count(statusname)
                for statusname in (' + @cols + ')
            ) p '

execute(@query)

See SQL 摆弄演示 http://www.sqlfiddle.com/#!3/d7915/7

这也可以使用带有 case 表达式的聚合函数来编写:

select typename,
  total,
  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,
    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
group by typename, total

See SQL 摆弄演示 http://www.sqlfiddle.com/#!3/d7915/10


MySQL:该数据库没有pivot函数,因此您必须使用聚合函数和CASE表达。它也没有窗口函数,因此您必须将查询稍微更改为以下内容:

select typename,
  total,
  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 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;

See SQL 摆弄演示 http://www.sqlfiddle.com/#!2/9f4cd/7

那么如果你需要 MySQL 中的动态解决方案,则必须使用准备好的语句来生成要执行的 sql 字符串:

SET @sql = NULL;
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'sum(CASE WHEN statusname = ''',
      statusname,
      ''' THEN 1 else 0 END) AS `',
      statusname, '`'
    )
  ) INTO @sql
FROM assetstatus;

SET @sql 
  = CONCAT('SELECT typename,
              total, ', @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;

See SQL 摆弄演示 http://www.sqlfiddle.com/#!2/9f4cd/6.

两个数据库中的所有查询的结果相同:

| TYPENAME | TOTAL | DEPLOYED | INVENTORY | SHIPPED |
-----------------------------------------------------
|  Desktop |     2 |        1 |         1 |       0 |
|   Laptop |     1 |        0 |         0 |       1 |
|   Server |     1 |        1 |         0 |       0 |
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我需要知道如何创建交叉表查询 的相关文章

  • MYSQL 查询返回“资源 id#12”而不是它应返回的数值

    不知道为什么 但这返回了错误的值 我正在取回此资源 ID 12 而不是我正在寻找的数值 1 执行此操作的代码是 type SELECT account type from user attribs WHERE username userna
  • 使用 to_char 格式化间隔

    以下 SQL 命令 select TO CHAR NVL arg1 arg2 TO DSINTERVAL 0 00 00 00 from table1 生成格式为 000000000 00 03 01 954000 的结果 是否可以在 to
  • 如何在TOAD的DataGrid中显示sys_refcursor数据

    请我需要帮助 我搜索了很多并且变得更加困惑 我使用 Toad 9 7 25 并且我做了这个程序 在一个包中 PROCEDURE ReportaCC pfcorte IN DATE lcursor IN OUT SYS REFCURSOR I
  • SQL Server 2008 R2 的 Try_Convert

    我正在使用 SQL Server 2008 R2 并且有一个VARCHAR我想要转换为的列DECIMAL 28 10 using CONVERT 但其中许多行的格式错误 因此无法将它们解析为数字 在这种情况下 我只想通过将结果设置为 0 或
  • MySQL 按主键排序

    某些 SQL 服务器允许使用通用语句 例如ORDER BY PRIMARY KEY 我不相信这适用于 MySQL 是否有任何此类解决方法可以允许跨多个表自动选择 或者是否需要查找查询来确定主键 我一直在研究的解决方法包括调用SHOW COL
  • 使用 SQL Filestream 时出现 OutOfMemoryException

    我正在尝试将大约 600 MB 的 zip 文件上传到 SQL 2008 FILESTREAM 表 但出现 OutOfMemoryException 我正在使用 SqlFileStream 类上传文件 如本教程中所述 http www ag
  • 使用按位函数查询 BIT 字段时,MySQL 不使用索引

    我的 MySQL 表中有一个 BIT 类型的字段 我想使用位值存储记录的状态 例如 1 status1 2 status2 4 status3 8 status4 每条记录可以同时具有多种状态 对于 status1 和 status3 该值
  • 创建表作为 select 删除 postgresql 中的非空约束

    在 postgres sql 中 创建表时 select 删除了表上的非空约束 例如 对此没有单一命令的解决方案 要基于现有表 包括所有约束 创建表 请使用 create table B like a including constrain
  • 如何查找 PostgreSQL 数据库的上次更新时间?

    我正在使用一个批量更新的 postgreSQL 数据库 我需要知道数据库 或数据库中的表 上次更新或修改的时间 两者都可以 我看到 postgreSQL 论坛上有人建议使用日志记录并查询日志 这对我不起作用 因为我无法控制客户端代码库 你可
  • 限制 SQL Server 连接到特定 IP 地址

    我想将 SQL Server 实例的连接限制为特定 IP 地址 我想阻止来自除特定列表之外的任何 IP 地址的任何连接 这是可以在 SQL Server 实例或数据库中配置的东西吗 听起来像是你会使用Windows防火墙 http tech
  • 如何有效地从 DB2 表中删除所有行

    我有一个大约有 50 万行的表 我想删除所有行 如果我做简单的delete from tbl 事务日志已满 我不关心这种情况下的事务 无论如何我都不想回滚 我可以删除许多事务中的行 但是有更好的方法吗 如何有效地从 DB2 中的表中删除所有
  • 使用Powershell访问远程Oracle数据库

    我需要能够连接到我的网络上基于 Windows 7 的 Oracle 服务器 32 位 Oracle XE 我需要连接的机器运行 Windows 7 64 位 两台机器上都安装了 Powershell 我已在 64 位计算机上安装了 Ora
  • SQL参数化查询不显示结果

    我的 DataAcess 类中有以下函数 但它没有显示任何结果 我的代码如下 public List
  • SPARK SQL - 当时的情况

    我是 SPARK SQL 的新手 SPARK SQL 中是否有相当于 CASE WHEN CONDITION THEN 0 ELSE 1 END 的内容 select case when 1 1 then 1 else 0 end from
  • 连接两个表的查询的 SQL Server“FOR XML”输出

    我是 SQL Server 中 FOR XML 功能的新手 我正在使用 SQL Server 2012 我有两个表 Word 和 Word Expansion 样本数据 表 字 WordOID Word 1 PIPE 2 WIRE 表 Wo
  • 复选框上的数据绑定

    我目前正在将数据从 SQL 数据库之一提取到我的应用程序中 我可以让它适用于我的文本框和其他项目 但是 我似乎无法让它适用于复选框 这是我正在使用的代码 DataTable dt new DataTable dt using SqlConn
  • 查找 PostgreSQL 中所有范围集合的所有交集

    我正在寻找一种有效的方法来查找时间戳范围集之间的所有交集 它需要与 PostgreSQL 9 2 配合使用 假设这些范围代表一个人可以见面的时间 每个人都可以有一个或多个空闲时间范围 我想找到all可以召开会议的时间段 即所有人都有空的时间
  • 更改迁移中的自动​​增量值(PostgreSQL 和 SQLite3)

    我有一个托管在 Heroku 上的项目 想要更改表的自动增量起始值 我在本地使用 SQLite3 Heroku 使用 PostgreSQL 这是我在迁移中所拥有的 class CreateMytable lt ActiveRecord Mi
  • 在sqlite SQL语句中与order by子句结合使用limit

    下面的两条 SQL 语句总是会产生相同的结果集吗 1 SELECT FROM MyTable where Status 0 order by StartTime asc limit 10 2 SELECT FROM SELECT FROM
  • 如何从 PostgreSQL 中的时间戳列值提取一天中的时间(或小时)?

    我正在尝试从 PostgreSQL 中的 时间戳 列中提取一天中的时间 这是我的做法 但是 太糟糕了 知道如何做得更好吗 SELECT date part hour date demande text hours date part min

随机推荐