2010-06-22 43 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