如何基于连接的表值选择“虚拟”列/值?

4

简短版:

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

详细版:

我正在使用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

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

取出'myfakecolumn'并尝试应用此逻辑。[https://dev59.com/2m7Xa4cB1Zd3GeqPvfDt] - RazorSky
2个回答

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;

请查看这里的fiddle 链接

我仔细考虑了一下,可以使用两个查询,一个查询收集所有可能的元键,然后使用PHP构建第二个查询,就像您的示例#1一样。但是,我刚刚尝试了#2并创建了一个新行,它似乎正如我一开始想要的那样工作。尽管有点难以阅读;)。相对于选项#2,选项#1是否会有重大好处?我怀疑#2将进行许多SELECT查询,但是这里不需要性能-此脚本不会经常使用。 - Radley Sustaire
我无法在MySQL 5.1.54上使用HeidiSQL(应用程序并不重要)使第二个选项起作用。不需要调试它,因为最终我选择了选项#1,并使用了上一个评论中的想法。实际上,存储这些字段的插件(用于WordPress)具有包含所有字段名称的全局变量,因此最终我甚至不需要额外的查询,并且不必担心所有不必要的字段 - 只需使用当前可用的即可。最终,我认为这是最好的选择。感谢您提供的示例查询! - Radley Sustaire

2

有这么多术语需要学习,难怪我在尝试寻找类似问题时遇到了很多麻烦!我会对此进行一些研究,谢谢!也许可以通过执行单独的查询来查找每个元键,然后使用PHP将其格式化为“硬编码”布局的方式来解决这个问题,因为这可能是不可能的。 - Radley Sustaire

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接