子查询的更好方法

时间:2012-05-08 06:32:41

标签: mysql sql subquery

我有一个数据库,其中article表与自身有多对多关系(通过article_rel),articlestypes。父母的类型为1234,而儿童可以是几种类型之一。

我试图找到那些父母:没有孩子;或者,如果他们有孩子,最近的儿童文章不属于某种类型。

以下对第二部分的效果相当不错,但未涉及第一部分。我所做的每次尝试都拉出子查询,以便我可以引用它返回的值(添加“或为空”)失败。我一般也想知道是否有更好的方式来写这样的东西。

SELECT 
 CONCAT('http://www.sitename.com/', n.id, '.html') as URL,
 n.added,
 u.email,
 n.body
 #c.body
 FROM
     warehouse.article n 
 inner join site.user u on n.user_id = u.id
 inner join warehouse.article_param np on np.id = n.id and np.param_name = 'ready' and np.param_value = 'true'
 where
     n.type_id = 1234 
 and
     (select 
           c.type_id 
      from 
           warehouse.article c, 
           warehouse.article_rel r
      where
           r.child_nid = c.id
           and r.parent_nid = n.id
      order by 
           c.added desc 
      limit 1)
      not in (2245,5443)
 order by 
      n.updated desc

3 个答案:

答案 0 :(得分:1)

您应该能够使用MAX(已添加)来查找最新添加的孩子。派生表x查找父n.id的最新添加子日期(如果该部分对您没有意义,请参阅this)。然后找到有关最新添加的孩子的数据。我使用左连接来获取n.id的最新添加的子项,因为如果没有子项,那么它将在子项的位置留下null,为您提供所有没有子项的文章。

SELECT n.added, CONCAT('http://www.sitename.com/', n.id, '.html') as URL,
u.email, n.body #c.body
FROM warehouse.article n 
inner join site.user u on n.user_id = u.id
inner join warehouse.article_param np on np.id = n.id and np.param_name = 'ready' and np.param_value = 'true'
left join (SELECT r.parent_nid, MAX(added) as latest
              FROM warehouse.article c
              INNER JOIN warehouse.article_rel r on c.id = r.child_nid
              GROUP BY r.parent_nid) as x on x.parent_nid = n.id
left join warehouse.article t on t.added = x.latest
where n.type_id = 1234 and (t.type_id is null or t.type_id not in (2245,5443))
order by n.updated desc

如果有多篇文章可能具有完全相同的添加日期,那么您必须使用派生表来检查父项:

left join (SELECT c.type_id, c.id, c.added, r.parent_nid
           FROM warehouse.article c
           INNER JOIN warehouse.article_rel r on c.id = r.child_nid)
           as t on t.parent_nid = n.id and t.added = x.latest

答案 1 :(得分:0)

SELECT 
n.added,
CONCAT('http://www.sitename.com/', n.id, '.html') as URL,
u.email,
n.body
#c.body
FROM
    warehouse.article n 
inner join site.user u on n.user_id = u.id
inner join warehouse.article_param np on np.id = n.id and np.param_name = 'ready' and np.param_value = 'true'
left join 
     (
           select r.parent_nid, c.type_id 
           from warehouse.article c
           left join warehouse.article_rel r on r.child_nid = c.id and r.parent_nid = n.id     
           order by c.added desc 
           limit 1
      ) child_type
      on child_parent_nid = n.id
where
    n.type_id = 1234 and (child_type.type_id not in (2245,5443) or child_type.type_id is null)
order by 
    n.updated desc

只在我的脑海中测试,不确定它是否100%正确。任何更正都非常受欢迎。 :)

答案 2 :(得分:0)

第一个查询将获取没有孩子的父母,而第二个查询将获得最近的子文章不属于某一类型的父母。 UNION本身将为您提供DISTINCT结果集。

有很多嵌套选择,但不要担心它们都在你已加载的主结果集上应用过滤器,因此它不会影响性能,你可以在Db控制台上执行查询时测试它。

SELECT
 CONCAT('http://www.sitename.com/', n.id, '.html') AS URL,
 n.added,
 u.email,
 n.body
 FROM
 warehouse.article n
 JOIN site.user u ON n.user_id = u.id
 JOIN warehouse.article_param np ON np.id = n.id AND np.param_name = 'ready' AND <br/> np.param_value = 'true'
 LEFT JOIN warehouse.article_rel r ON r.parent_nid = n.id
 WHERE
 n.type_id = 1234  AND r.id IS NULL

 UNION

 SELECT URL,added,email,body FROM
 (SELECT * FROM
(SELECT

 CONCAT('http://www.sitename.com/', n.id, '.html') AS URL,
 n.added,
 u.email,
 n.body,
 nr.type_id
 FROM
 warehouse.article n
 JOIN site.user u ON n.user_id = u.id
 JOIN warehouse.article_param np ON np.id = n.id AND np.param_name = 'ready' AND <br/> np.param_value = 'true'
 JOIN warehouse.article_rel r ON r.parent_nid = n.id
 JOIN warehouse.article nr ON r.child_nid=nr.id
 WHERE
 n.type_id = 1234
 ORDER BY n.id DESC
 ) AS tbl1
GROUP BY id
Where  type_id NOT IN (2245,5443)