【问题标题】:MySQL - SubQuery within a SelectMySQL - 选择中的子查询
【发布时间】:2013-07-10 19:43:33
【问题描述】:

我不确定这是否可能,而且确实很难描述。

我想以这种方式返回SELECT 查询:

标识符 |姓名 |电子邮件 |狗名 |鱼名 -------------------------------------------------- ----- 44 |约翰 | john@email.com |邋遢 | 56 |简 |简@email.com | |河豚 72 |乔 |乔@email.com |火花 |鳃

有 3 个表: tbl_option_fields tbl_person tbl_person_optionals

第一个表简单地定义了无限的可选字段。以下是列:

选择 |选择题 ------------------ 1 |狗名 2 |鱼名 3 |电子邮件

第二张表只是我为人们保存数据的地方:

标识符 |姓名 --------------- 44 |约翰 56 |简 72 |乔

最后一张表让我存储 pID 存在的任何可选数据

身份证 |标识符 |选择 |选择值 ---------------------------------- 1 | 44 | 1 |邋遢 2 | 56 | 2 |河豚 3 | 72 | 1 |活泼的 4 | 72 | 2 |鳃 5 | 72 | 3 | joe@email.com 6 | 56 | 3 | jane@email.com 7 | 44 | 3 | john@email.com

SELECT 语句的结果需要在结果的头部显示opttitle。 我不擅长子查询,这可能是个笨蛋。

这是我的尝试:

SELECT p.*, opt.optval
FROM `tbl_person` p
LEFT OUTER JOIN `tbl_person_optionals` opt ON p.pID = opt.pID 
WHERE 1 

这个查询导致重复的结果,我相信我明白为什么。

标识符 |姓名 |选择值 ----------------------------------------- 44 |约翰 | john@email.com 44 |约翰 |邋遢 56 |简 | jane@email.com 56 |简 |河豚 72 |乔 | joe@email.com 72 |乔 |活泼的 72 |乔 |鳃

希望我解释说我想水平显示可选字段,而不是在行中显示新记录。 这个可以吗?

【问题讨论】:

  • 您正在寻找的是一个数据透视查询,但 mysql 不直接支持它们。有一些变通方法,但它们会造成难看的语法,并且当您在透视结果中添加/想要更多列时,它们不会自动扩展。
  • 这可能就是我需要听到的。谢谢!

标签: mysql subquery pivot-table entity-attribute-value


【解决方案1】:

您基本上想要的是一个数据透视表。这可以在 MySQL 中完成,例如 this article describes in full, glorious detail

但是,为了使用当前表格设计来归档您想要的内容,您必须为表格tbl_option_fields 中的每个 选项添加SELECT-operator。只有几个选项,这是可以管理的,但是您拥有的选项越多,您的语句就会变得越混乱(并且最终执行速度会变慢)。

另一个缺点是每次出现新选项时都必须调整您的陈述。

基本上要么你必须忍受它,要么调整你的桌子设计。可能还有更多选择,但我想归结为这两个。

【讨论】:

    【解决方案2】:

    这里有一个解决方案:

    SELECT p.pID, p.Name, 
      MAX(IF(opt.optid=3, opt.optval, NULL)) AS `Email`,
      MAX(IF(opt.optid=1, opt.optval, NULL)) AS `Dog Name`,
      MAX(IF(opt.optid=2, opt.optval, NULL)) AS `Fish Name`
    FROM `tbl_person` p
    LEFT OUTER JOIN `tbl_person_optionals` opt ON p.pID = opt.pID 
    GROUP BY p.pID;
    

    在编写此查询之前您必须知道所有 optid 及其列标签。这适用于 MySQL,但也适用于支持本机 PIVOT 命令的 RDBMS 品牌(例如 Microsoft SQL Server)。 SQL 要求您在开始检查数据之前定义查询的列;查询无法“添加”更多列,因为它发现了不同的数据值。

    所以你应该查询你的第一个定义可选字段的表,并使用结果来动态编写上面的 SQL 查询。

    另一种方法是按照您在示例中显示的那样逐行获取可选字段,然后编写应用程序代码来获取所有行并将它们重新排列为每人一行。

    无论哪种方式:任何动态数据透视查询都需要您在查询之前或查询之后编写更多应用程序代码。

    【讨论】:

      【解决方案3】:

      您可以通过将表格连接在一起并汇总结果来做到这一点:

      select po.pid, p.name,
             MAX(case when o.optId = 'Email' then po.optval end) as Email,
             MAX(case when o.optId = 'Dog Name' then po.optval end) as DogName,
             MAX(case when o.optId = 'Fish Name' then po.optval end) as FishName
      from tbl_person_optionals po join
           tbl_person p
           on p.pId = p.pId join
           tbl_optionfields o
           on p.optid = o.optid
      group by po.pid, p.name;
      

      这假设您知道列中的内容。 Select 语句只能返回一组固定的列,因此如果您想为 tbl_optionfields 中的每个值返回一个单独的列,则需要动态 SQL(即使用准备语句)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-06-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多