SQL-通过查询重新排列表

SQL-通过查询重新排列表,sql,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 (e

我继承了一张设计拙劣的桌子。 它看起来像:

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) 用户字段值 ------------------- 我叫亚伦 1封电子邮件aaron@company.com 1部电话800-555-4545 我叫迈克 2电子邮件mike@group.org 2电话777-123-4567 (等等,等等) 我希望通过查询以更合理的格式提取这些数据:

User Name Email Phone ------------------------------------------- 1 Aaron aaron@company.com 800-555-4545 2 Mike mike@group.org 777-123-4567 用户名电子邮件电话 ------------------------------------------- 1亚伦aaron@company.com 800-555-4545 2麦克mike@group.org 777-123-4567 我是一个SQL新手,但已经尝试了几个查询,其中包括Group By的变体, 一切都没有任何进展,甚至接近成功


有没有SQL技术可以让这变得简单?

我相信这将构建您所寻找的结果集。从那里,您可以创建视图或使用数据填充新表

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')

您可以使用自联接:

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

我测试了这个查询,它运行正常。

在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()
代替,效果相同。

这不是一个“设计糟糕的表”;但实际上是一个实体属性值(EAV)表。不幸的是,关系数据库是实现此类表的糟糕平台,并且否定了RDBMS的大部分优点。使用错误的铲子钉入螺钉的常见情况

但我认为这是可行的(基于答案,我认为这是行不通的(编辑:现在可以了))

编辑:从其他答案(左连接和on子句上的字段名)中获得了一些细节,现在有人知道如何将剩余的放在更高的位置吗?(但不是在第一次连接打开时,这太难看了),当然这并不重要,因为查询优化器会将其丑化回来。

的一个变体,我投它一票

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'

如果不是所有属性都保证存在,则使用
左联接。在
(用户,字段)
上的复合索引可能会对此有所帮助。

在我的工作中,不幸的是,我们有这样的数据库设计。但是这种设计比传统的数据库设计更适合我们,因为我们必须存储不同的记录,并提供我们所需要的灵活性。我们使用的数据库存储了数百万条记录

这将是使用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

最好的方法取决于您使用的数据库系统,所以您可能应该提到这一点。这是一个MySQL数据库,通过phpMyAdmin访问。我希望能够用简单、通用的SQL语法来完成它。@Javier,谢谢,我已经发现了我的错误并修复了它。我不知道我第一次编辑是怎么想的。实体属性值模型可能是最常用的术语。@Marcus:EAV table!这就是我想要的术语,谢谢@多尔夫:这是一个可爱的形象,但我不能因此而受到赞扬。我第一次看到它的是罗伯特·伊鲁萨林斯基,《卢阿语言》的主要作者……我又错了。引用自Django的主要作者之一Russell Keith Magee。请注意,与join解决方案相比,这只需要对整个数据集进行一次传递,因此它应该更高效,而且性能不会随着添加更多字段而下降。这可能是更繁琐的方法,但非常简单,让我看看整个中间步骤的进度,对于初学者来说并不难。好办法!
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