我有一个设计糟糕的表,我继承了。 它看起来像:
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技术可以轻松实现这一目标?
答案 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)
的综合指数可能对此有利。