2010-06-22 46 views
4

首先,我对查询多个表格感到抱歉,所以如果这是一个愚蠢的问题,我们很抱歉,但我们都有开始某处!MySQL查询 - 基于两个因素加入数据,然后根据数值自定义数据排序方式

我做了一张照片应该使这个更容易理解:

http://www.mediumsliced.co.uk/temp/mysqlhelp.jpg

我的第一台wp_user有几个专栏 - 我想从3列这是ID USER_EMAIL和user_nicename值。
我的第二张表wp_usermeta有3列存储用户的元数据。这些列是user_id,meta_key和meta_value。此表中的user_id值始终对应于wp_user中的匹配ID值(请参见图片)。

我想加入meta_key字段中的数据以及它的meta_value。到目前为止,我有这样的:

SELECT wp_users.ID, wp_users.user_login, wp_users.user_nicename, wp_users.user_email, 
     wp_usermeta.user_id, wp_usermeta.meta_key, wp_usermeta.meta_value 
FROM wp_users, wp_usermeta 
WHERE (wp_users.ID = wp_usermeta.user_id); 

这显示我需要的所有信息,但是我有问题的是,其实我是想显示来自meta_key作为单独的列中的数据和正确的行中的元键meta_value为那个用户根据他们的ID。我还需要排除任何没有wp_user_level为0的用户。(希望我的照片更清晰)

很明显,我有很多需要了解的MySql,但如果有人能指导我到最后的结果我会很感激,如果你能解释这个查询,以便我可以从中学习,而不是仅仅复制和粘贴它,那更是如此。

非常感谢,如果您需要更多信息或需要我澄清任何问题,随时提问!

克雷格

+0

EAV表格设计非常差,很难有效地查询和表现不佳的表演者。建议您完成这项工作来定义您需要的列并将其重新分配到标准化的标签。 – HLGEM 2010-06-22 14:43:59

+0

@HLGEM,我认为他必须忍受它 - > http://codex.wordpress.org/Database_Description#Table:_wp_usermeta – Unreason 2010-06-22 14:49:00

+0

@Unreason - 奖金功能:数据库中似乎没有任何东西可以防止有两个meta_key具有相同的meta_key,但具有不同的值。 – Thomas 2010-06-22 14:59:36

回答

2

继续你的榜样

SELECT 
    wp_users.ID, 
    wp_users.user_login, 
    wp_users.user_nicename, 
    wp_users.user_email, 
    wp_usermeta.user_id, 
    wp_usermeta.meta_key, 
    wp_usermeta.meta_value 
FROM 
    wp_users, wp_usermeta 
WHERE 
    (wp_users.ID = wp_usermeta.user_id) AND (wp_usermeta.wp_user_level = 0); 

应该给你你需要什么。 注:

  • 格式的SQL
  • ,而不是一个WHERE上ID = user_ID的条件下,它可能是一个连接

这样的:

SELECT 
    ... 
FROM 
    wp_users INNER JOIN 
    wp_usermeta ON wp_users.id = wp_usermeta.user_id 
WHERE 
    wp_usermeta.wp_user_level = 0 

编辑:由于对于元数据和元属性,您必须多次加入meta_table,因为会有属性

例如要得到

SELECT 
    wp_users.ID, 
    wp_users.user_login, 
    wp_users.user_nicename, 
    wp_users.user_email, 
    m1.meta_value as first_name 
    m2.meta_value as last_name 
    m3.meta_value as address 
    m4.meta_value as dob 
FROM 
    wp_users 
    INNER JOIN wp_usermeta m ON wp_users.id = m.user_id AND m.meta_key = "wp_user_level" AND m.meta_value = 0 
    LEFT JOIN wp_usermeta m1 ON wp_users.id = m1.user_id AND m1.meta_key = "first_name" 
    LEFT JOIN wp_usermeta m2 ON wp_users.id = m2.user_id AND m1.meta_key = "last_name" 
    LEFT JOIN wp_usermeta m3 ON wp_users.id = m3.user_id AND m1.meta_key = "address" 
    LEFT JOIN wp_usermeta m4 ON wp_users.id = m4.user_id AND m1.meta_key = "dob"  

正如你可以看到EAV方法,虽然它允许用户界面元素的伟大重用,数据库的实际结构(更慢,更复杂的查询,有限不做奇迹完整性验证以及在此类结构上运行的最终代码更复杂)。

如果可能的话,正确的方法是在应用程序级别处理“聚合”。

+0

非常感谢您的快速回答不合理的,但问题是,wp_user_level实际上是一个值,而不是已有的专栏。 wp_user_level是列wp_usermeta.meta_key中的一个值,因此我需要首先将该值和wp_usermeta.meta_vale中的相应值(它们不是列的值)作为目标值。所以我用你提供的代码得到一个未知的列错误。如果你看到wp_user_level在我提供的图片中可能更有意义,那么对于格式不佳的用户来说也很抱歉! – Craig 2010-06-22 14:42:03

+0

@Craig,我看到关于wp_user_level ...编辑...第二个应该给你你需要的,我也会在第一个查询中修复它。 – Unreason 2010-06-22 14:45:06

+0

辉煌,再次感谢您的快速回复,一旦我确定我明白这里发生了什么,我会试试这个。你们让我意识到,我不能只知道这个领域的基础知识!你解决这些事情的速度是不真实的! – Craig 2010-06-22 15:03:09

1

假设所有密钥都存在于wp_usermeta中,您可以简单地加入表格几次。如果值可能丢失,请使用Left Join

Select 
    u.ID, 
    u.user_login, 
    u.user_nicename, 
    u.user_email, 
    m_first_name.meta_value As first_name, 
    m_last_name.meta_value As last_name, 
    m_address.meta_value As address, 
    m_dob.meta_value  As dob 
From wp_users u 
Join wp_usermeta m_first_name On ( m_first_name.user_id = u.id 
            And m_first_name.meta_key = 'first_name') 
Join wp_usermeta m_last_name On ( m_last_name.user_id = u.id 
            And m_last_name.meta_key = 'last_name') 
Join wp_usermeta m_address On ( m_address.user_id  = u.id 
            And m_address.meta_key  = 'address') 
Join wp_usermeta m_dob  On ( m_dob.user_id   = u.id 
            And m_dob.meta_key   = 'dob') 
Join wp_usermeta m_user_level On ( m_user_level.user_id = u.id 
            And m_user_level .meta_key = 'm_user_level') 
Where m_user_level.meta_value = '0'; 
+0

如果查询预先不知道的EAV表,如果该值存在,则需要将其加入。 – HLGEM 2010-06-22 14:47:43

+0

@HLGEM:对,我试图在查询前的文字中说明这一点。 – 2010-06-22 14:51:48

+0

+1,我在我的答案中编辑了最后一个版本 - 基本上是一样的。另一种方法是使用'id IN(SELECT user_id FROM wp_usermeta WHERE meta_key =“wp_user_level”AND meta_value ='0')''。 此外,在查询中最后一个连接表的键上有一些复制/粘贴假象 - m_dob?.meta_key ='m?_user_level' – Unreason 2010-06-22 14:55:18

0

对于每个你想要从中取出的值,你必须单独离开连接到元表。这就是为什么EAV表格是关系数据库的反模式的原因之一。

还请学会做显式连接。隐式连接会给你带来麻烦,因为当事情变得复杂时,它们可能会导致意外的交叉连接(并且你只会用设计这么差的方式编写复杂的查询)。当你需要连接左连接时它们也很糟糕(就像你需要做inthis设计不好,你不要;知道如果这个人有每个attriubute一个vlue

+0

我明白这种获取数据的方法并不是最好的,事实上它很糟糕。唯一的问题是保持现在所有数据的依赖性很多。因为这是我使用数据的一个补充,并且它没有想到从第一阶段我意识到它需要一些看。这是一个很少使用的查询,所以与重建插件和迁移数据的潜在时间相比,服务器负载表示这对我来说是最好的选择。非常感谢你的评论,你让我做了一些认真的咖啡燃料阅读! – Craig 2010-06-22 15:06:53

3
Select wp_users.ID 
    , wp_users.user_login 
    , wp_users.user_email 
    , wp_users.user_nicename 
    , Min(Case When wp_usermeta.meta_key = 'first_name' Then wp_usermeta.meta_value End) As first_name 
    , Min(Case When wp_usermeta.meta_key = 'last_name' Then wp_usermeta.meta_value End) As last_name 
    , Min(Case When wp_usermeta.meta_key = 'address' Then wp_usermeta.meta_value End) As address 
    , Min(Case When wp_usermeta.meta_key = 'dob' Then wp_usermeta.meta_value End) As dob 
From wp_user 
    Join wp_usermeta 
     On wp_usermeta.user_id = wp_user.ID 
Where Exists (
       Select 1 
       From wp_usermeta As Meta1 
       Where Meta1.user_id = wp_user.id 
        And Meta1.meta_key = 'wp_user_level' 
        And Meta1.meta_value = '0' 
       ) 
     And wp_usermeta.meta_key In('first_name','last_name','address','dob')     
Group By wp_users.ID 
    , wp_users.user_login 
    , wp_users.user_email 
    , wp_users.user_nicename 

首先,正如其他人所说,原因之一是该查询是如此繁琐写的是。你必须使用EAV结构,“meta”表的概念对关系设计来说真的是一种讽刺,其次,为了从EAV中获取信息,你必须创建所谓的交叉表查询,在你的查询中你想要的列。一般来说,关系数据库不是专门用于动态列生成的例如我在解决方案中所做的并且是EAV所需的。

+0

+1对于不同的方法,如果OP做了性能比较 – Unreason 2010-06-22 14:59:32

+0

'+ 1',我会期望它的性能比多外连接解决方​​案更好,但是性能必须经过测试。 – 2010-06-22 15:05:11

+0

@Peter Lang,@Unreason - 很难说如果它表现更好。我猜想这取决于需要多少外连接以及表中存在多少数据。 TBH,与外部连接方法唯一的区别在于它依赖于user_id + meta_key是唯一的,这似乎并没有被强制执行。如果您为同一个user_id获得两个相同的meta_key值,则外部联接会在输出中为您提供重复的行。当然,那就是说,我的解决方案会随意选择两者中的“最小”值。 – Thomas 2010-06-22 15:09:15