mysql - 将字段值传递给子查询

时间:2013-11-11 16:26:19

标签: mysql

在这种情况下,我通过子查询加入并希望将deptid传递给已连接的子查询,但我得到'D is not defined'错误消息。

SELECT * 
    FROM(   
        SELECT D.name AS deptname,D.id AS deptid,WT.sortposition AS deptsortposition 
        FROM departments D JOIN web_taxonomy WT ON (WT.deptid=D.id AND WT.classid=0) 
        WHERE D.web=1
        ORDER BY sortposition
    ) AS D
    LEFT JOIN (
        SELECT C.name AS classname,C. id AS classid,C.department,WT.sortposition AS classsortposition,WT.deptid
        FROM classes C
        JOIN web_taxonomy WT ON (WT.classid=C.id AND WT.subclassid=0 AND WT.deptid=D.deptid) 
        WHERE web=1 ORDER BY classsortposition  
    ) AS C ON (C.department=D.deptid)

任何方式传递引用类似于我在上面的强标签中包含的内容?

编辑:我犯了一个错误,最初离开了工作查询,只是添加了我想要运行的部分。基本上我想通过仅获取与D子查询表中找到的共享相同deptid的行来最小化连接子查询的大小。

2 个答案:

答案 0 :(得分:10)

您在别名的子查询中不能使用别名“D”。

这应该可行(在第一个子查询中只使用X而不是D - 不是严格必要但有助于提高可读性 - 并将对D的引用移到第二个子查询之外):

SELECT * 
    FROM(   
        SELECT 
           X.name AS deptname
           , X.id AS deptid
           , WT.sortposition AS deptsortposition 
        FROM departments X 
        JOIN web_taxonomy WT ON (WT.deptid=X.id AND WT.classid=0) 
        WHERE X.web=1
        ORDER BY sortposition
    ) AS D  -- this is available to objects referencing this alias
    LEFT JOIN (
        SELECT 
           C.name AS classname
           , C. id AS classid
           , C.department
           , WT.sortposition AS classsortposition
           , WT.deptid
        FROM classes C JOIN web_taxonomy WT 
        ON WT.classid=C.id AND WT.subclassid=0
        WHERE web=1 ORDER BY classsortposition  
    ) AS C ON C.department=D.deptid AND C.deptid = D.deptid -- i.e. here

答案 1 :(得分:6)

我认为你根本不需要做子查询:

SELECT D.name AS deptname, D.id AS deptid, WT1.sortposition AS deptsortposition,
  C.name AS classname, C.id AS classid, C.department, 
  WT2.sortposition AS classsortposition, WT2.deptid
FROM departments AS D
JOIN web_taxonomy AS WT1 ON (WT1.deptid=D.id AND WT1.classid=0)
LEFT OUTER JOIN web_taxonomy AS WT2 ON (WT2.deptid=D.id AND WT2.subclassid=0)
LEFT OUTER JOIN classes AS C ON (C.id=WT2.classid AND C.department=WT2.deptid);

WT1的加入应该受益于索引:

ALTER TABLE web_taxonomy
  ADD KEY wt_dept_class (deptid, classid),
  ADD KEY wt_dept_subclass (deptid, subclassid);

类的连接使用该表的PRIMARY键索引。

以下是此查询的EXPLAIN输出:

+----+-------------+-------+--------+--------------------------+---------------+---------+------------------+------+-----------------------+
| id | select_type | table | type   | possible_keys            | key           | key_len | ref              | rows | Extra                 |
+----+-------------+-------+--------+--------------------------+---------------+---------+------------------+------+-----------------------+
|  1 | SIMPLE      | D     | ALL    | PRIMARY,id               | NULL          | NULL    | NULL             |    1 | NULL                  |
|  1 | SIMPLE      | WT1   | ref    | dept_class,dept_subclass | dept_class    | 10      | test.D.id,const  |    1 | Using index condition |
|  1 | SIMPLE      | WT2   | ref    | dept_class,dept_subclass | dept_subclass | 10      | test.D.id,const  |    1 | Using where           |
|  1 | SIMPLE      | C     | eq_ref | PRIMARY,id               | PRIMARY       | 8       | test.WT2.classid |    1 | Using where           |
+----+-------------+-------+--------+--------------------------+---------------+---------+------------------+------+-----------------------+

说实话,我必须稍微编辑一下EXPLAIN报告来显示结果。我测试了零行的表,因此优化器错误地选择了WT2的dept_class索引。如果您使用真实数据进行测试,我认为它会正确选择dept_subclass索引。


我尝试了你的查询,通过一个小修改来解决D.deptid上的错误:

SELECT *
FROM(
  SELECT D.name AS deptname,D.id AS deptid,WT.sortposition AS deptsortposition
  FROM departments D JOIN web_taxonomy WT ON (WT.deptid=D.id AND WT.classid=0)
  WHERE D.web=1
  ORDER BY sortposition
) AS D
LEFT JOIN (
  SELECT C.name AS classname,C. id AS classid,C.department,WT.sortposition AS classsortposition,WT.deptid
  FROM classes C
  JOIN web_taxonomy WT ON (WT.classid=C.id AND WT.subclassid=0 AND WT.deptid=C.department)
  WHERE web=1 ORDER BY classsortposition
) AS C ON (C.department=D.deptid);

EXPLAIN报告:

+----+-------------+------------+------+--------------------------+------------+---------+-----------------------------+------+----------------------------------------------------+
| id | select_type | table      | type | possible_keys            | key        | key_len | ref                         | rows | Extra                                              |
+----+-------------+------------+------+--------------------------+------------+---------+-----------------------------+------+----------------------------------------------------+
|  1 | PRIMARY     | <derived2> | ALL  | NULL                     | NULL       | NULL    | NULL                        |    2 | NULL                                               |
|  1 | PRIMARY     | <derived3> | ALL  | NULL                     | NULL       | NULL    | NULL                        |    2 | Using where; Using join buffer (Block Nested Loop) |
|  3 | DERIVED     | C          | ALL  | PRIMARY,id               | NULL       | NULL    | NULL                        |    1 | Using where; Using temporary; Using filesort       |
|  3 | DERIVED     | WT         | ref  | dept_class,dept_subclass | dept_class | 10      | test.C.department,test.C.id |    1 | Using index condition; Using where                 |
|  2 | DERIVED     | D          | ALL  | PRIMARY,id               | NULL       | NULL    | NULL                        |    1 | Using where; Using temporary; Using filesort       |
|  2 | DERIVED     | WT         | ref  | dept_class,dept_subclass | dept_class | 10      | test.D.id,const             |    1 | Using index condition                              |
+----+-------------+------------+------+--------------------------+------------+---------+-----------------------------+------+----------------------------------------------------+

呸!它为部门和类运行一个表扫描(这是类型列中的ALL),它为每个子查询创建一个临时表,然后将它们连接到而不用任何好处索引(这是Using join buffer的含义)。这不是一个有趣的优化计划。

通常,排序应该是SQL查询的最后一部分。不要尝试对子查询结果进行排序以解决优化器问题。如果可能,您希望索引可以辅助连接,但是连接的最佳索引的顺序不一定是您希望返回最终结果的顺序。所以让优化器完成其工作以进行连接,然后对最终结果进行排序。

SELECT D.name AS deptname, D.id AS deptid, WT1.sortposition AS deptsortposition,
  C.name AS classname, C.id AS classid, C.department,
  WT2.sortposition AS classsortposition, WT2.deptid
FROM departments AS D
JOIN web_taxonomy AS WT1 ON (WT1.deptid=D.id AND WT1.classid=0)
LEFT OUTER JOIN web_taxonomy AS WT2 ON (WT2.deptid=D.id AND WT2.subclassid=0)
LEFT OUTER JOIN classes AS C ON (C.id=WT2.classid AND C.department=WT2.deptid)
ORDER BY deptsortposition, classsortposition;

这仍然使用一个临时表&amp; filesort,但不是两个。它避免了连接缓冲区;每个联接都是索引辅助的。

+----+-------------+-------+--------+--------------------------+---------------+---------+------------------+------+---------------------------------+
| id | select_type | table | type   | possible_keys            | key           | key_len | ref              | rows | Extra                           |
+----+-------------+-------+--------+--------------------------+---------------+---------+------------------+------+---------------------------------+
|  1 | SIMPLE      | D     | ALL    | PRIMARY,id               | NULL          | NULL    | NULL             |    1 | Using temporary; Using filesort |
|  1 | SIMPLE      | WT1   | ref    | dept_class,dept_subclass | dept_class    | 10      | test.D.id,const  |    1 | Using where; Using index        |
|  1 | SIMPLE      | WT2   | ref    | dept_subclass            | dept_subclass | 10      | test.D.id,const  |    1 | Using where                     |
|  1 | SIMPLE      | C     | eq_ref | PRIMARY,id               | PRIMARY       | 8       | test.WT2.classid |    1 | Using where                     |
+----+-------------+-------+--------+--------------------------+---------------+---------+------------------+------+---------------------------------+