2009-02-09 49 views
17

我想通过指定innertable.id = outertable.id来为内部查询提供WHERE条件。但是,MySQL(5.0.45)在'where子句'“中报告”未知列'outertable.id'“。这种类型的查询可能吗?JOIN语法中的MySQL相关子查询

内部查询使用GROUP BY将行转移到列。这可以完全在外部查询中执行,但由于额外的连接可能会导致额外的开销。

或者,我可以在内部查询中省去WHERE条件,而是指定一个ON outertable.id = innerquery.id,但它会取出整个内部查询行集再次连接到外部,这是低效的。

实际的SQL如下所示:

select t.ticketid, u.userid, t.fullname, u.loginapi_userid, t.email, tp.subject, tp.contents, a.PhoneNumber, a.Location, a.Extension, a.BusinessUnit, a.Department 
from swtickets t 
inner join swticketposts tp on t.ticketid = tp.ticketid 
inner join swusers u on t.userid = u.userid 
left join 
    (
    select 
    cfv.typeid, 
    min(case cfv.customfieldid when 1 then cfv.fieldvalue end) as 'PhoneNumber', 
    min(case cfv.customfieldid when 3 then cfv.fieldvalue end) as 'Location', 
    min(case cfv.customfieldid when 5 then cfv.fieldvalue end) as 'Extension', 
    min(case cfv.customfieldid when 8 then cfv.fieldvalue end) as 'BusinessUnit', 
    min(case cfv.customfieldid when 9 then cfv.fieldvalue end) as 'Department' 
    from swcustomfieldvalues cfv 
    where cfv.typeid = t.ticketid 
    group by cfv.typeid 
) as a on 1 = 1 
where t.ticketid = 2458; 
+2

我原来的问题是,“这种类型的查询可能吗?” (相对于MySQL 5.0)。 更改模式或在应用程序代码上进行分析不属于问题主题。 – 2009-02-10 15:31:48

回答

29

您的问题的答案是否定的,不可能像您所做的那样引用相关名称。派生表由内部查询在外部查询开始评估连接之前生成。因此,相关名称如t,tpu不适用于内部查询。

为了解决这个问题,我建议在内部查询中使用相同的常量整数值,然后使用实际条件而不是1=1在外部查询中连接派生表。

SELECT t.ticketid, u.userid, t.fullname, u.loginapi_userid, t.email, 
    tp.subject, tp.contents, a.PhoneNumber, a.Location, a.Extension, 
    a.BusinessUnit, a.Department 
FROM swtickets t 
INNER JOIN swticketposts tp ON (t.ticketid = tp.ticketid) 
INNER JOIN swusers u ON (t.userid = u.userid) 
LEFT OUTER JOIN (
    SELECT cfv.typeid, 
    MIN(CASE cfv.customfieldid WHEN 1 THEN cfv.fieldvalue END) AS 'PhoneNumber', 
    MIN(CASE cfv.customfieldid WHEN 3 THEN cfv.fieldvalue END) AS 'Location', 
    MIN(CASE cfv.customfieldid WHEN 5 THEN cfv.fieldvalue END) AS 'Extension', 
    MIN(CASE cfv.customfieldid WHEN 8 THEN cfv.fieldvalue END) AS 'BusinessUnit', 
    MIN(CASE cfv.customfieldid WHEN 9 THEN cfv.fieldvalue END) AS 'Department' 
    FROM swcustomfieldvalues cfv 
    WHERE cfv.typeid = 2458 
    GROUP BY cfv.typeid 
) AS a ON (a.typeid = t.ticketid) 
WHERE t.ticketid = 2458; 
0

我的建议将是你效率的理由排除了什么。例如。删除where子句并使用连接(按照t.ticketid = a.ticketid)

您是否能够通过一些具体示例证明您对低效率的看法?我知道你在说什么,但是无论你在外部查询中使用每一行的方法是否被加入到内部查询中的每一行中,所以根据执行计划,它可能不像你怀疑的那样低效。

0

我想象的问题是'cfv.typeid = t.ticketid'呢?我的想法是,尽管MySQL支持相关的子查询,但你试图做的事似乎可能会失败,因为“内部”查询并不真正在查询的其余部分“内部”在WHERE子句中。但是看起来你可以从子查询中取出where子句,并在a.typeid = t.ticketid上创建连接条件。

+0

对不起,这是查询的另一个变体剩余的。它与产生的实际错误没有任何关系,所以我从上面的问题中删除了它。 – 2009-02-09 23:13:18

1

我会写多个连接。当你说它“可能会招致额外的开销”时,告诉我你没有测试它是肯定的。如果你有不错的索引,联接应该是非常平凡的。

这也显示了通用的“容纳所有”表格设计模式的一个缺陷。

+1

确实。该设计被称为实体属性值。它以多种方式打破标准化,而且很难使用。 – 2009-02-10 02:57:09

+0

在内部查询(cfv)中使用“WHERE cfv.typeid = 2458”会导致在cfv上进行令人讨厌的表扫描,因为缺少索引,但是,忽略此情况会导致更糟糕的情况,从而导致“Using temporary; Using filesort “除了派生查询上的附加表扫描。 – 2009-02-10 15:28:13

2

您正在使用Entity-Attribute-Value设计,如果您尝试生成传统结果集,最终无法使其具有可伸缩性。不要试图在一个查询中做到这一点。

相反,先查询您的规范化表:

SELECT t.ticketid, u.userid, t.fullname, u.loginapi_userid, t.email, 
    tp.subject, tp.contents 
FROM swtickets t 
INNER JOIN swticketposts tp ON (t.ticketid = tp.ticketid) 
INNER JOIN swusers u ON (t.userid = u.userid) 
WHERE t.ticketid = 2458; 

然后查询您的自定义字段,对结果集的多个行的结果:

SELECT cfv.customfieldid, cfv.fieldvalue 
FROM swcustomfieldvalues cfv 
WHERE cfv.typeid = 2458; 

你会得到多行结果集,每个自定义字段一行:

+---------------+--------------+ 
| customfieldid | fieldvalue | 
+---------------+--------------+ 
|    1 | 415-555-1234 | 
|    3 | Third office | 
|    5 | 123   | 
|    8 | Support  | 
|    9 | Engineering | 
+---------------+--------------+ 

然后您需要编写应用程序以循环方式将结果集字段映射到应用程序对象字段的代码。

以这种方式使用实体属性值表在性能和代码维护方面更具可扩展性。