2012-05-08 11 views
6

Tengo una base de datos donde la tabla article tiene una relación de varios a sí misma (a través de article_rel) y articles tiene types. Los padres tienen un tipo de 1234, mientras que los niños pueden ser de varios tipos.Una mejor forma de subconsultar

Estoy tratando de encontrar a los padres que: no tienen hijos; o, si tienen hijos, el artículo infantil más reciente no pertenece a un determinado conjunto de tipos.

Lo siguiente funciona razonablemente bien para la segunda parte, pero no aborda la primera parte. Cada intento que hice para sacar la subconsulta para poder hacer referencia al valor que devuelve (para agregar "o es nulo") ha fallado. También me pregunto en general si hay una mejor manera de escribir algo como esto.

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 

Respuesta

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 

Sólo prueba en mi mente, no estoy seguro que es 100% correcto o no. Cualquier corrección es muy bienvenida. :)

0

La primera consulta obtendrá los padres que no tienen hijos, mientras que Second Query obtendrá al padre cuyo artículo hijo más reciente no pertenezca a un determinado grupo de tipos. UNION mismo le proporcionará el conjunto de resultados DISTINCT.

Hay tantas selecciones anidadas, pero no se preocupe, todas ellas están aplicando filtros en su conjunto de resultados principal ya cargado para que no afecte el rendimiento, puede probarlo mientras ejecuta la consulta en la consola 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) 
1

Debería poder usar MAX (agregado) para buscar solo los niños más recientes. La tabla derivada x encuentra la fecha del último hijo añadido para el n.id padre (consulte this si esa parte no tiene sentido para usted). Luego t encuentra los datos sobre ese último niño agregado. Utilicé la combinación de la izquierda para obtener el hijo de n.id de última generación porque, si no hay un hijo, dejará un valor nulo en el lugar del niño y todos los artículos que no tienen hijos.

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 

Si existe la posibilidad de que exista más de un artículo con la misma fecha exacta añadido, a continuación, usted tiene que utilizar una tabla derivada de t para comprobar la paternidad:

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 
Cuestiones relacionadas