如何根据连接表值选择“假”列/值?

Posted

技术标签:

【中文标题】如何根据连接表值选择“假”列/值?【英文标题】:How do I SELECT a "fake" column/value based on joined table values? 【发布时间】:2013-08-08 00:17:11 【问题描述】:

短版:

我需要自定义查询结果,使用一个值作为列名,另一个值作为列的值。它还需要是自动的(不是硬编码,数百个可能的“元键”)。

加长版:

我正在使用 Wordpress 的“用户元”结构,其中单个用户有一个用户 ID,另一个表包含与该用户相关的“元数据”。

这个元数据是任意的,只有四列:

meta_idpost_idmeta_keymeta_value

我想为某个用户执行 SQL 查询,并格式化结果,以便所有元数据都像行一样被格式化,其中 meta_key 是列名,meta_value 是列的值。


示例数据库:

-- wp_users
* ID    | username | email
35      | radgh    | radgh@example.org

-- wp_usermeta
* meta_id | user_id | meta_key   | meta_value
1         | 35      | first-name | Radley
2         | 35      | last-name  | Sustaire
3         | 35      | newsletter | on

我的查询(我需要弄清楚 (???) 部分,它将生成元键/值对作为假列)

 SELECT 
    `users`.ID as 'user_id',
    `users`.username as 'username',
    `users`.email as 'email',
    (???)

 FROM `wp_users` `users`
     INNER JOIN `wp_usermeta` `meta`
     ON `users`.ID = `meta`.user_id

 WHERE `wp_users`.ID = 35

期望的结果:

* user_id | username | email             | first-name | last-name | newsletter
35        | radgh    | radgh@example.org | Radley     | Sustaire  | on

在这个similar question 中,所选答案使用硬编码字段。我想自动执行此操作。 :)

【问题讨论】:

采用“myfakecolumn”并尝试应用此逻辑。 [***.com/questions/15091330/…[1]:***.com/questions/15091330/… 【参考方案1】:

它被称为Entity–attribute–value model。 mysql 中通过简单/复杂查询的动态列(元数据)的解决方案是 AFAIK 无法实现的(就像缺少 PIVOT MySQL 等其他强大功能一样)。我认为唯一的方法是静态定义或MySQL function,它从元表中获取可能的属性并构建正确的查询。

请看What is best performance for Retrieving MySQL EAV results as Relational Table

还可以阅读堆栈上的 EAV 设计(优点/缺点)Entity-Attribute-Value Table Design

【讨论】:

这么多行话要学,难怪我在寻找类似问题时遇到这么多麻烦!我会研究一下这个,谢谢!由于这可能是不可能的,也许做一个单独的查询只是为了找到每个元键,然后使用 php 将其格式化为“硬编码”布局。【参考方案2】:

MySQL 没有枢轴功能。如果您已经知道 meta_key 的所有可能值,则可以使用这样的硬编码查询:

SELECT
  wp_users.*,
  MAX(CASE WHEN `meta_key`='first-name' THEN meta_value END) AS `first-name`,
  MAX(CASE WHEN `meta_key`='last-name' THEN meta_value END) AS `last-name`,
  ....
FROM
  wp_users INNER JOIN wp_usermeta
  ON wp_users.ID=wp_usermeta.user_id
GROUP BY
  wp_users.ID, wp_users.username, wp_users.email;

或者您可以使用准备好的语句动态创建 SQL 查询,如下所示:

SELECT
  CONCAT(
    'SELECT wp_users.*,',
    GROUP_CONCAT(
      CONCAT(
        'MAX(CASE WHEN `meta_key`=\'',
        meta_key,
        '\' THEN meta_value END) AS `',
        meta_key,
        '`')),
    ' FROM wp_users INNER JOIN wp_usermeta ON wp_users.ID=wp_usermeta.user_id',
    ' GROUP BY wp_users.ID, wp_users.username, wp_users.email')
FROM
  (SELECT DISTINCT meta_key FROM wp_usermeta) s
INTO @sql;

PREPARE stmt FROM @sql;
EXECUTE stmt;

请看小提琴here。

【讨论】:

我想了想,可以使用两个查询,一个收集所有可能的元键,然后使用 PHP 构建第二个查询,如示例 #1。但是,我刚刚使用 #2 并创建了一个新行,它似乎就像我想开始的那样工作。虽然有点难读;)。选项#1 与#2 相比会有很大的好处吗?我怀疑 #2 会进行许多 SELECT 查询,但这里不需要性能 - 这个脚本不会经常使用。 我无法在 MySQL 5.1.54 上获得第二个选项来使用 HeidiSQL(不是应用程序很重要)。不过,无需调试它,因为我最终选择了选项#1,使用了我上次评论中的想法。事实上,存储这些字段的插件(用于 wordpress)有一个包含所有字段名称的全局变量,所以最后我什至不需要额外的查询,也不必担心所有不必要的字段 -只有当前可用的。最后,我认为无论如何这是最好的选择。感谢您提供示例查询!

以上是关于如何根据连接表值选择“假”列/值?的主要内容,如果未能解决你的问题,请参考以下文章

如何根据多个最大列值选择一行?

选择与表值函数连接中的 Oracle 标量函数

从表值函数中选择?

如何根据数据表角度中的 JSON 动态填充表值?

从另一个表中选择列中的相似值并在主表中使用另一个表值

在连接中使用表值函数