SQL - 通过查询重新排列表

时间:2010-05-04 22:49:28

标签: sql

我有一个设计糟糕的表,我继承了。 它看起来像:

    User  Field   Value
    -------------------
    1      name   Aaron
    1      email  aaron@company.com
    1      phone  800-555-4545
    2      name   Mike
    2      email  mike@group.org
    2      phone  777-123-4567
    (etc, etc)

我希望通过更合理的格式的查询提取这些数据:

User  Name   Email              Phone
-------------------------------------------
1     Aaron  aaron@company.com  800-555-4545
2     Mike   mike@group.org     777-123-4567

我是一名SQL新手,但尝试过多次使用Group By的变体查询, 一切都没有取得成功。

是否有一种SQL技术可以轻松实现这一目标?

6 个答案:

答案 0 :(得分: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 Joins,以及ON子句中的字段名称),现在是否有人知道如何将剩余的WHERE放高一点? (但不是在第一个JOIN的ON上,那太难看了),当然这并不重要,因为查询优化器无论如何都会使它变得丑陋。

答案 1 :(得分: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

我测试了这个查询,它确实有效。

答案 2 :(得分: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

答案 3 :(得分: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')

答案 4 :(得分: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()代替相同的效果。

答案 5 :(得分: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)的综合指数可能对此有利。