2013-07-18 57 views
2
CREATE TABLE Attributes (
    id  VARCHAR(40), 
    type VARCHAR(16), 
    data VARCHAR(2048), 
    PRIMARY KEY(id,type) 
);

这是我试图运行的查询的一般格式。一般的想法是,'对象'具有唯一的id,然后像JavaScript对象那样具有键/值对。如何减少此查询中连接表的数量?

SELECT a1.id, a1.data, a2.data, a3.data, a4.data, a6.data 
    FROM Attributes a1, Attributes a2, Attributes a3, Attributes a4, Attributes a5 
    LEFT JOIN Attributes a6 ON (a6.id=a5.id AND a6.type = 'Foreign Id') 
     WHERE a1.id=a2.id 
      AND a1.id=a3.id 
      AND a1.id=a4.id 
      AND a1.id=a5.id 
      AND a1.type = 'First Name' 
      AND a2.type = 'Middle Name' 
      AND a3.type = 'Last Name' 
      AND a4.type = 'Timestamp' 
      AND a5.type = 'Count' 
      AND a5.data = 'MY_ID' 

在此查询中'Foreign Id'是一个可选属性。问题是我得到

SELECT将检查超过MAX_JOIN_SIZE行;检查你的 WHERE并使用SET SQL_BIG_SELECTS = 1或SET MAX_JOIN_SIZE =#如果 SELECT没问题。

我意识到我可以这么说,但警告让我担心这个查询的效率非常低。有没有更好的方式来制定查询?

回答

5

由于主键键是ID, Type你可以使用集合功能,并确保查询仍然是确定的,降低了查询0加入:

SELECT a.ID, 
     MAX(CASE WHEN a.type = 'First Name' THEN a.Data END) AS FirstName, 
     MAX(CASE WHEN a.type = 'Last Name' THEN a.Data END) AS LastName, 
     MAX(CASE WHEN a.type = 'Timestamp' THEN a.Data END) AS `Timestamp`, 
     MAX(CASE WHEN a.type = 'Count' THEN a.Data END) AS `Count`, 
     MAX(CASE WHEN a.type = 'MY_ID' THEN a.Data END) AS MY_ID, 
     MAX(CASE WHEN a.Type = 'Foreign Id' THEN a.Data END) AS ForeignId 
FROM Attributes a 
GROUP BY a.ID; 

值得注意的是,虽然该实体 - 属性 - 值模型是一个SQL反模式,你可能会更好地规范化你的数据以将属性存储为列,而不必使用上述查询将行转换为列。

编辑

要添加基于属性过滤器中使用的HAVING条款:

SELECT a.ID, 
     MAX(CASE WHEN a.type = 'First Name' THEN a.Data END) AS FirstName, 
     MAX(CASE WHEN a.type = 'Last Name' THEN a.Data END) AS LastName, 
     MAX(CASE WHEN a.type = 'Timestamp' THEN a.Data END) AS `Timestamp`, 
     MAX(CASE WHEN a.type = 'Count' THEN a.Data END) AS `Count`, 
     MAX(CASE WHEN a.type = 'MY_ID' THEN a.Data END) AS MY_ID, 
     MAX(CASE WHEN a.Type = 'Foreign Id' THEN a.Data END) AS ForeignId 
FROM Attributes a 
GROUP BY a.ID 
HAVING MAX(CASE WHEN a.type = 'MY_ID' THEN a.Data END) = 1; 
+0

哈哈,真棒,谢谢! – chacham15

+0

+1,只是在列中存储属性将是* normalization *,而不是* denormalization *。 EAV反模式甚至不是关系;它不能以任何正常形式。 –

+0

在我的情况下,我没有选择,但为了知道更好的是不是EAV NOSQL的一般前提? – chacham15

0

你的属性表是窄的,但有很多行。你要么做一堆自我加入,要么用group by a.id查询并使用聚合函数。后一种方法消除了连接,但仍然遇到很多行。

我认为一个更好的选择是使你的数据模型稍微规格化。这将涉及创建一个包含'First Name'列,'Middle Name'列等的表。然后,与ID关联的各种属性都在同一行上。你最终得到一个更宽的表格,但行数少得多,而且没有连接。