如何检索存储在多行中的“动态”属性作为普通记录?

时间:2012-04-02 06:19:18

标签: mysql sql foreign-keys relational

我有一个基于关系MySQL数据库的系统,允许人们存储“潜在客户”的详细信息。此外,人们可以创建自己的列来存储数据,然后在添加新帐户时可以在其下添加数据。表结构如下所示:

  

LEADS -   ID,   电子邮件,   USER_ID

     

属性 -   ID,   attr_name,   USER_ID

     

ATTR_VALUES -   lead_id,   attr_id,   值,   USER_ID

显然,在这些表中,“user_id”指的是“用户”表,其中只包含可以登录系统的人员。

我正在编写一个函数来输出引导细节,目前我只是将基本的引导细节作为查询,然后拉出与该引导关联的每个属性值(连接属性表以获取名称)然后在PHP中加入数组。这有点乱,我想知道是否有办法在一个SQL查询中执行此操作。我已经阅读了一些关于“数据透视表”的内容,但我很难理解它是如何工作的。

非常感谢任何帮助。谢谢!

4 个答案:

答案 0 :(得分:1)

您可以在单个查询中进行透视,如下所示:

select l.id lead_id,
       l.email,
       group_concat(distinct case when a.attr_name = 'Home Phone' then v.value end) HomePhone,
       ...
from leads l
left join attr_values v on l.id = v.lead_id
left join attributes a on v.attr_id = a.id
group by l.id

您需要为要显示的每个属性添加单独的group_concat派生字段。

答案 1 :(得分:0)

我会看看这个link。这解释了枢轴的基本原理:

  

“数据透视表”或“交叉表报表”SQL特性函数:执行   它没有“if”,“case”或“GROUP_CONCAT”。是的,有用   这......“if”语句在使用时有时会引起问题   组合。简单的秘密,这也是他们几乎工作的原因   所有数据库,都是以下函数:sign(x)返回-1,0,+ 1   对于值x&lt; 0,x = 0,x> 0分别为abs(sign(x))返回0   if x = 0 else,1 if x&gt; 0或x <0 0 1-abs(符号(x))补码   上面,因为只有当x = 0

时才返回1

它还解释了一种更简单的旋转考试方式。也许这可以为它提供一些启示?

答案 2 :(得分:0)

您可能希望从mysql中获取一个sql值(在您的情况下为attr_name)一列。这个原则称为pivot table(有时也是交叉表或交叉表查询),mysql不支持。不是因为mysql不够,而是因为数据透视操作不是数据库操作 - 结果不是普通的数据库表,并且设计用于进一步的数据库操作。 透视操作演示的唯一目的 - 这就是它属于表示层而不是数据库的原因。

因此,尝试从mysql获取数据透视表的每个解决方案都将是hacky。我建议的是以正常格式从数据库中获取数据,只需执行以下操作:

select *
from attr_values join attributes using on attr_id = attributes.id
    join leads on leads.id = lead_id

然后以表示语言(PHP,JSP,Python或其他任何使用的方式)转换数据库输出。

答案 3 :(得分:0)

我会小心地假设枢轴将实现您的简化目标。只有当attr_name一致时,Pivot才会起作用。由于您将用户标识绑定到它,我认为它不会。此外,您将为一个attr_name设置多个值。我担心数据透视表不会产生您正在寻找的结果。

我建议您将事务和报表分开。有一个ETL例程将通过转换来清除(即使attr_name和attr_value)一致。这将使您的报告更有意义。

总之,对于最终用户的即时输出,PHP是您可以做的最好的。对于报告,在尝试报告之前,首先将EAV转换为行/列。