从4行1列并分成9列的数据中,MySQL的正确方法是什么?

问题描述 投票:0回答:1

我已经研究并尝试了数天的SQL查询,以查找将起作用的“事物”。我有一个表apj32_facileforms_subrecords,它使用7列。我要显示的所有数据都在1列中-“值”。 “记录”显示条目的编号。 “标题”是我希望出现在标题行中的内容,但它不如“值”重要,要根据“记录”号显示在1行中。我已经尝试了很多CONCAT和各种Pivot查询,但是似乎并没有比“接近”最终结果做更多​​的事情。这是桌子的屏幕截图:enter image description here

输出“应该”是线性的,因此1行包含9列:项目;邮政编码;名字;姓;地址;市;电话;电子邮件;交易(按该顺序)。 9列中的值来自“值”,因为它们与“记录”数字有关。

[我知道有很多类似的示例,但是我发现什么都没有涵盖将“ value”和CONCAT中的所有值都移到1行。

这将获取我想要的所有数据-从record的位置选择valueapj32_facileforms_subrecordsrecord IN(recordvalue))ORDER BYrecord但是这些值仍然在多行中。我可以使用该查询来获取值,但仍然不知所措,无法将它们放入1行。我将继续处理该查询,看看能否在这里的一位专家向我展示这样做之前弄清楚它。任何帮助,将不胜感激。

mysql rows
1个回答
0
投票

使用SQL将EAV模型表示形式展平为关系表示形式可能会有些费解,并且效率不高。

两种常用的方法是条件聚合和SELECT列表中的相关子查询。两种方法都要求仔细索引,以针对大型集合提供合适的性能。


相关子查询示例

这是相关子查询方法的示例,为某些记录获取“ zipcode”属性的一个值

 SELECT r.id 
      , ( SELECT v1.value
            FROM `apj32_facileforms_subrecords` v1
           WHERE v1.record = r.id 
             AND v1.name   = 'zipcode'
           ORDER BY v1.value LIMIT 0,1
        ) AS `Zipcode`
   FROM ( SELECT 1 AS id ) r

此外,我们重复相关的子查询,更改属性标识符(用'firstname'代替'zipcode'。看起来我们也可以按元素引用它,例如v2.element = 2

 SELECT r.id
      , ( SELECT v1.value
            FROM `apj32_facileforms_subrecords` v1
           WHERE v1.record = r.id 
             AND v1.name   = 'zipcode'
           ORDER BY v1.value LIMIT 0,1
        ) AS `Zipcode`

      , ( SELECT v2.value
            FROM `apj32_facileforms_subrecords` v2
           WHERE v2.record = r.id 
             AND v2.name   = 'firstname'
           ORDER BY v2.value LIMIT 0,1
        ) AS `First Name`  

      , ( SELECT v3.value
            FROM `apj32_facileforms_subrecords` v3
           WHERE v3.record = r.id 
             AND v3.name   = 'lastname'
           ORDER BY v3.value LIMIT 0,1
        ) AS `Last Name`

   FROM ( SELECT 1 AS id UNION ALL SELECT 2 ) r

返回类似

id  Zipcode  First Name  Last Name
--  -------  ----------  ---------
 1  98228    David       Bacon
 2  98228    David       Bacon 

条件聚合方法示例

[我们可以使用GROUP BY将每个实体的多行折叠为一行,并在表达式中使用条件测试以通过聚合函数“挑选”属性值。

 SELECT r.id
      , MIN(IF(v.name  = 'zipcode'   ,v.value,NULL)) AS `Zip Code`
      , MIN(IF(v.name  = 'firstname' ,v.value,NULL)) AS `First Name`
      , MIN(IF(v.name  = 'lastname'  ,v.value,NULL)) AS `Last Name`
   FROM ( SELECT 1 AS id UNION ALL SELECT 2 ) r
   LEFT
   JOIN `apj32_facileforms_subrecords` v
     ON v.record = r.id
  GROUP
     BY r.id

[为了获得更多可移植的语法,我们可以使用更多的ANSI标准IF()表达式替换MySQL CASE函数,例如

      , MIN(CASE v.name WHEN 'zipcode'   THEN v.value END) AS `Zip Code`

请注意,MySQL不支持SQL Server PIVOT语法,Oracle MODEL语法或Postgres CROSSTABFILTER语法。

将这两种方法扩展为动态方法,以返回具有可变列数和多种列名的结果集……这在单个SQL语句的上下文中是不可能的。我们可以分别执行SQL语句以检索信息,这将使我们能够动态构造上面显示的形式的SQL语句,并返回一组明确的列。


上面概述的方法返回了更传统的关系模型,(每个列都有一个值)。

非关系大量的属性和值合并为单个字符串

如果我们有一些特殊的定界符,可以使用GROUP_CONCAT函数将数据的表示形式凑在一起

作为基本示例:

 SELECT r.id
      , GROUP_CONCAT(v.title,'=',v.value ORDER BY v.name) AS vals
   FROM ( SELECT 1 AS id ) r
   LEFT
   JOIN `apj32_facileforms_subrecords` v
     ON v.record = r.id
    AND v.name in ('zipcode','firstname','lastname')
  GROUP
     BY r.id

要返回两列,类似

 id   vals
 --   --------------------------------------------------- 
  1   First Name=David,Last Name=Bacon,Zip Code=98228

我们需要注意,从GROUP_CONCAT返回的字节数限制为group_concat_max_len个字节。在这里,我们刚刚压缩了气球,将问题移至以后的处理过程中,以分析结果字符串。如果我们在值中出现任何等号或逗号,将使解析结果字符串变得一团糟。因此,我们将必须适当地转义数据中出现的所有定界符,以便GROUP_CONCAT表达式会涉及更多内容。

© www.soinside.com 2019 - 2024. All rights reserved.