我已经研究并尝试了数天的SQL查询,以查找将起作用的“事物”。我有一个表apj32_facileforms_subrecords,它使用7列。我要显示的所有数据都在1列中-“值”。 “记录”显示条目的编号。 “标题”是我希望出现在标题行中的内容,但它不如“值”重要,要根据“记录”号显示在1行中。我已经尝试了很多CONCAT和各种Pivot查询,但是似乎并没有比“接近”最终结果做更多的事情。这是桌子的屏幕截图:
输出“应该”是线性的,因此1行包含9列:项目;邮政编码;名字;姓;地址;市;电话;电子邮件;交易(按该顺序)。 9列中的值来自“值”,因为它们与“记录”数字有关。
[我知道有很多类似的示例,但是我发现什么都没有涵盖将“ value”和CONCAT中的所有值都移到1行。
这将获取我想要的所有数据-从record
的位置选择value
,apj32_facileforms_subrecords
(record
IN(record
,value
))ORDER BYrecord
但是这些值仍然在多行中。我可以使用该查询来获取值,但仍然不知所措,无法将它们放入1行。我将继续处理该查询,看看能否在这里的一位专家向我展示这样做之前弄清楚它。任何帮助,将不胜感激。
使用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 CROSSTAB
或FILTER
语法。
将这两种方法扩展为动态方法,以返回具有可变列数和多种列名的结果集……这在单个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表达式会涉及更多内容。