2010-05-04 82 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)的综合指数可能对此有利。