2010-05-04 79 views
2

我有一個設計不佳的表格,我繼承了它。 它看起來像:SQL - 通過查詢重新排列表格

 
    User Field Value 
    ------------------- 
    1  name Aaron 
    1  email [email protected] 
    1  phone 800-555-4545 
    2  name Mike 
    2  email [email protected] 
    2  phone 777-123-4567 
    (etc, etc) 

我希望在更合理的格式來提取通過查詢此數據:

 
User Name Email    Phone 
------------------------------------------- 
1  Aaron [email protected] 800-555-4545 
2  Mike [email protected]  777-123-4567 

我是新手SQL,但是嘗試了好幾種查詢與變化Group By, 都沒有任何東西甚至接近成功。

有沒有一種SQL技術可以讓這個變得簡單?

+0

的最佳方法取決於你所使用的數據庫系統,所以你應該提到。 – 2010-05-04 22:54:02

+0

這是一個MySQL數據庫,通過phpMyAdmin訪問。我希望能夠用簡單,通用的SQL語法來完成它。 – abelenky 2010-05-04 22:55:27

回答

1

在我的工作中,我們很遺憾有這樣的數據庫設計。但是這種設計對於我們來說更適合於傳統的數據庫設計,因爲我們必須存儲不同的記錄,併爲我們提供了所需的靈活性。我們正在使用的數據庫存儲了數百萬條記錄。

這將是使用MSSQL在大型數據庫上運行查詢的最快方法。這節省了必須做很多連接,這可能是非常昂貴的。

DECLARE @Results TABLE 
(
    UserID INT 
    , Name VARCHAR(50) 
    , Email VARCHAR(50) 
    , Phone VARCHAR(50) 
) 

INSERT INTO @Results 
    SELECT DISTINCT User FROM UserValues 

UPDATE 
    R 
SET 
    R.Name = UV.Value 
FROM 
    @Results R 
INNER JOIN 
    UserValues UV 
    ON UV.User = R.UserID 
WHERE 
    UV.Field = 'name' 

UPDATE 
    R 
SET 
    R.Email = UV.Value 
FROM 
    @Results R 
INNER JOIN 
    UserValues UV 
    ON UV.User = R.UserID 
WHERE 
    UV.Field = 'Email' 

UPDATE 
    R 
SET 
    R.Phone = UV.Value 
FROM 
    @Results R 
INNER JOIN 
    UserValues UV 
    ON UV.User = R.UserID 
WHERE 
    UV.Field = 'Phone' 


SELECT * FROM @Results 
+0

這也許是更乏味的做法,但它很直接,讓我在整個中間步驟看到進步,對初學者來說並不困難。好解決方案! – abelenky 2010-05-05 20:26:31

0

我相信這會構建您正在尋找的結果集。從那裏,你可以創建一個視圖或使用數據來填充一個新表。

select user, name, email, phone from 
(select user, value as name from table where field='name') 
natural join 
(select user, value as email from table where field='email') 
natural join 
(select user, value as phone from table where field='phone') 
1

您可以使用自聯接:

SELECT User1.User, User1.Value as Name, User2.Value as Email, 
    User3.Value as Phone 
FROM Users User1 
JOIN Users User2 
    ON User2.User = User1.User 
JOIN Users User3 
    ON User3.User = User1.User 
WHERE User1.Field = 'name' AND User2.Field = 'email' AND User3.Field = 'phone' 
ORDER BY User1.User 

我測試此查詢,和它的作品。

0

在MySQL中,你可以做這樣的事情:

SELECT 
    id, 
    group_concat(CASE WHEN field='name' THEN value ELSE NULL END) AS name, 
    group_concat(CASE WHEN field='phone' THEN value ELSE NULL END) AS phone, 
    ... 
FROM test 
GROUP BY id 

聚合函數其實無所謂,只要你有每種類型的只有一個字段。您也可以使用min()max()來代替同樣的效果。

+0

請注意,與聯接解決方案相比,這隻需要在整個數據集上進行一次傳遞,因此它應該更加高效,而且在添加更多字段時性能不會下降。 – 2010-05-04 23:31:16

4

這不是一個'設計糟糕的桌子';但實際上是一個實體屬性值(EAV)表。不幸的是,關係數據庫是實現這樣的表的糟糕平臺,並且否定了RDBMS的大部分優點。使用錯誤的鏟子釘入螺釘的常見情況。

,但我認爲這會工作(基於Marcus Adams'答案,我不認爲會工作(編輯:現在它))

SELECT User1.Value AS name, User2.Value AS email, User3.Value AS phone 
FROM Users User1 
LEFT JOIN Users User2 
    ON User2.User = User1.User AND User2.Field='email' 
LEFT JOIN Users User3 
    ON User3.User = User1.User AND User3.Field='phone' 
WHERE User1.Field = 'name' 
ORDER BY User1.User 

編輯:得到了其他答案有些細微(LEFT加盟,以及ON子句中的字段名稱),現在是否有人知道如何將剩餘的WHERE更高一點? (但不在第一個JOIN的ON上,這太難看了),當然這並不重要,因爲查詢優化器無論如何都會使它無法正常工作。

+0

@Javier,謝謝,我真的發現了我的錯誤並修復了它。我不知道我第一次編輯時的想法。實體屬性值模型可能是最常用的術語。 – 2010-05-04 23:12:37

+1

+1爲「錯鐵錘錘螺釘」 – Dolph 2010-05-04 23:14:13

+0

@馬庫斯:EAV表!這是我期待的術語,謝謝! @Dolph:這是一個可愛的形象,但我不能讚揚它。我第一次看到它是Lua語言的主要作者Roberto Ierusalimschy。 – Javier 2010-05-05 01:11:41

0

Javier's answer的變體,它有我的投票。

SELECT 
    UserName.name, UserEmail.email, UserPhone.phone 
FROM 
    Users   AS UserName 
    INNER JOIN Users AS UserEmail ON UserName.User = UserEmail.User 
    AND UserName.field = 'name' AND UserEmail.field = 'email' 
    INNER JOIN Users AS UserPhone ON UserName.User = UserPhone.User 
    AND UserPhone.field = 'phone' 

如果不是所有屬性都保證存在,則使用LEFT JOINs。超過(User,Field)的綜合指數可能對此有利。