【问题标题】:How can I do Join two tables and do Pivot dynamically如何加入两个表并动态进行 Pivot
【发布时间】:2018-11-09 16:52:28
【问题描述】:

我有两张桌子,A 和 B

A(身份证,姓名)
B (a_id, 键, 值)

带有一些值的表格

**A table**

-----------------------------
   id        |      name
-----------------------------
    1        |      sorabh
    2        |      john
-----------------------------

**B table**

-------------------------------------------------
     a_id    |     key     |     value
-------------------------------------------------
      1      |    looks    |    handsome
      1      |    lazy     |    yes
      1      |    car      |    honda
      2      |    phone    |    948373221
      1      |    email    |    some@ccid.com
-------------------------------------------------

现在我想要实现的是跟随,单查询、内连接、交叉连接等。

SELECT * FROM A
CROSS JOIN B WHERE A.id=1

结果必须类似于

--------------------------------------------------------------------
  id   |   name   |    looks   |   lazy  |    car   |   email
--------------------------------------------------------------------
   1   |  sorabh  |   handsome |   yes   |  honda   | some@ccid.com 
--------------------------------------------------------------------

【问题讨论】:

  • 你需要使用pivot
  • 左连接。结果将是逐行的(列将是 id、name、a_id、key、value)。您的输出称为交叉表、数据透视表。如何做到这一点取决于您使用的后端。例如对于 postgreSQL 检查 tablefunc 扩展(这种类型的数据更适合 NoSQL)。
  • 考虑处理应用程序代码中的显示问题
  • 问题在于您的表 B 将具有动态值。因此,您提出的查询的结果集必须为每个 Id 的每个不同的“键”行值都有一个列。所以 ID 1 会有一个“电话”列,但是一个空值。随着数据库的增长,空值也会增长。

标签: mysql sql pivot-table


【解决方案1】:

假设table aid 列是primary key 列并且table b 具有a_idkey 列组合的复合唯一键,或者即使没有这样的约束也没有重复,相关子查询可用作:

select a.*,
       ( select value from b where b.a_id = a.id and b.key = 'looks' ) as looks,
       ( select value from b where b.a_id = a.id and b.key = 'lazy' ) as lazy,
       ( select value from b where b.a_id = a.id and b.key = 'car' ) as car,
       ( select value from b where b.a_id = a.id and b.key = 'email' ) as email
  from a
 where a.id = 1;

【讨论】:

  • 这将完全有效,但我想知道,在这里我们知道键和值是什么,但是在我们不知道外观、懒惰、汽车的单个查询中是否有可能,电子邮件等,可以是任何东西,可以是多个或单个与之相关的条目,在带有子语句的单个语句中查询,根据键添加列?
  • @sorabh86 我明白你的意思,我从来没有遇到过这样一种完全动态的方式,我相信没有,很遗憾。
【解决方案2】:

你可以尝试使用mysql动态pivot来让你期待。

使用条件聚合函数进行旋转

准备好您的 SQL 语句并用于动态执行您的 SQL EXECUTE stmt;

SET @sql = NULL;
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'max(case when `key`= ''',
      `key`,
      ''' then `value` end) AS ',
      `key`
    )
  ) INTO @sql
FROM A join B on a.id=b.a_id
WHERE b.a_id = 1;

SET @sql = CONCAT('select a.id,a.name, ', @sql, ' 
                   FROM A join B on a.id=b.a_id
                    WHERE b.a_id = 1
                    group by a.name');

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

sqlfiddle

结果

id  name    looks       laz   car   email
1   sorabh  handsome    yes   honda some@ccid.com

参考

Dynamic pivot tables

【讨论】:

    【解决方案3】:

    max() 的用例

    select a.name,
     max(case when key='looks' then value end)  as  looks, 
     max(case when key='lazy' then value end)  as  yes,  
     max(case when key='car' then value end)  as  car,  
     max(case when key='email' then value end)  as  email,        
    tablea a join tableb b on a.id=b.a_id
    group by a.name
    

    【讨论】:

    • 如果键和值是动态的怎么办,顺便说一句,它不起作用。无论如何,谢谢。
    【解决方案4】:

    试试这个

    WITH CTE_A AS (
       SELECT
          A.id,
          A.name,
          B.key,
          B.value
       FROM  A
        INNER JOIN B ON A.id = B.a_id
    )
    SELECT *
    FROM
       CTE_A
       PIVOT (max(value) FOR key IN (looks, lazy, car,phone,email)) P
    ;
    

    如果键和值是动态的,使用下面的

    DECLARE @colsToPivot AS NVARCHAR(MAX),
            @sqlStmt  AS NVARCHAR(MAX)
    select @colsToPivot = STUFF((SELECT distinct ',' + QUOTENAME(key) 
                        from B
                FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)') 
            ,1,1,'')
    
    
    set @sqlStmt = 'WITH CTE_A AS (
           SELECT
              A.id,
              A.name,
              B.key,
              B.value
           FROM  A
            INNER JOIN B ON A.id = B.a_id
        )
        SELECT *
        FROM
           CTE_A
           PIVOT (max(value) FOR key IN (' + @colsToPivot +')) P'
    
    execute(@sqlStmt)
    

    【讨论】:

      【解决方案5】:
      SELECT * FROM B LEFT JOIN A WHERE A.id=B.a_id AND A.id=1
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-28
        • 1970-01-01
        • 1970-01-01
        • 2014-02-14
        • 2020-02-15
        相关资源
        最近更新 更多