2009-02-09 6 views
17

Me gustaría proporcionar una condición WHERE en una consulta interna especificando innertable.id = outertable.id. Sin embargo, MySQL (5.0.45) informa "Columna desconocida 'outertable.id' en 'where clause'". ¿Este tipo de consulta es posible?Subconsulta correlacionada de MySQL en la sintaxis JOIN

La consulta interna pivota filas a columnas usando un GROUP BY. Esto podría realizarse completamente en la consulta externa, pero posiblemente incurriría en gastos adicionales debido a las combinaciones adicionales.

Como alternativa, puedo dejar la condición WHERE en la consulta interna y en su lugar especificar un ON outertable.id = innerquery.id, pero luego buscará todo el conjunto de filas de consulta interna para unir de nuevo el exterior, que es ineficaz.

El SQL real aparece a continuación:

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

Mi pregunta original es: "¿Es posible este tipo de consulta?" (en relación con MySQL 5.0). Cambiar el esquema o seguir el código de la aplicación está fuera del tema de la pregunta. –

Respuesta

29

La respuesta a su pregunta es no, no es posible hacer referencia a nombres de correlación mientras lo hace. La tabla derivada es producida por su consulta interna antes de que la consulta externa comience a evaluar las uniones.Por lo tanto, los nombres de correlación como t, tp y u no están disponibles para la consulta interna.

Para resolver esto, recomendaría usar el mismo valor entero constante en la consulta interna, y luego unirme a la tabla derivada en la consulta externa usando una condición real en lugar de 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

Mi sugerencia iba a ser lo que descartado por razones de eficiencia. P.ej. omitiendo la cláusula where y usando una combinación (según t.ticketid = a.ticketid)

¿Ha podido demostrar su opinión sobre la ineficiencia mediante algunos ejemplos concretos? Sé lo que dices, pero cualquiera que sea el método que uses en cada fila de la consulta externa se está uniendo a cada fila en la consulta interna, por lo que dependiendo del plan de ejecución puede que no sea tan ineficiente como sospechas.

0

Imagino que el problema es 'cfv.typeid = t.ticketid', ¿entonces? Mi opinión al respecto sería que, aunque MySQL admite subconsultas correlacionadas, lo que está intentando hacer parece que podría fallar en una unión porque la consulta 'interna' no está realmente 'dentro' del resto de la consulta como si fuera en una cláusula WHERE. Pero parece que podría sacar la cláusula where de la subconsulta y hacer que su condición de unión sea a.typeid = t.ticketid.

+0

Lo siento, eso fue lo que quedó de otra variación de la consulta. No tiene nada que ver con el error real que se está produciendo, por lo que lo he eliminado de la pregunta anterior. –

1

Lo escribiría con varias combinaciones. Cuando dice que "posiblemente incurriría en gastos generales adicionales", me dice que no lo ha probado para estar seguro. Si tiene índices decentes, las uniones deberían ser bastante triviales.

Esto también muestra uno de los inconvenientes del patrón genérico de diseño de mesa "mantener todo".

+1

De hecho. El diseño se llama Entity-Attribute-Value. Rompe la normalización de múltiples maneras, y es muy difícil de usar. –

+0

El uso de "WHERE cfv.typeid = 2458" en la consulta interna (cfv) provoca un análisis desagradable de la tabla en cfv debido a la simple falta de índice, sin embargo, omitir esta condición empeora las cosas, causando un "Uso temporal; "además de una exploración de tabla adicional en la consulta derivada. –

+0

No estoy seguro de lo que quiere decir con "consulta interna". Habría 5 nuevas uniones internas, así que tal vez eso es lo que quieres decir. Espero que tu tabla de CFV tenga un índice en typeid. Probablemente tendré un índice agrupado en typeid y customfield en ese orden. –

2

Está utilizando el diseño Entity-Attribute-Value, y finalmente no hay forma de hacerlo escalable si intenta generar conjuntos de resultados convencionales. No intente hacer esto en una consulta.

En su lugar, consultar las tablas normalizadas primera:

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; 

luego volver a consultar sus campos personalizados, con el resultado de varias filas del conjunto de resultados:

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

Usted obtendrá múltiples filas en el conjunto de resultados, una fila para cada campo personalizado:

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

a continuación, deberá escribir aplicaciones código para asignar los campos del conjunto de resultados a los campos del objeto de la aplicación, en un bucle.

El uso de una tabla Entity-Attribute-Value de esta manera es más escalable tanto en términos de rendimiento como de mantenimiento del código.

+0

Esta sugerencia está logrando una consulta similar a la pregunta original (cambie "donde cfv.typeid = t.ticketid" a "donde cfv.typeid = 2458"); en cambio, depende del código fuera de la base de datos para realizar el pivote. –

+0

Sí, exactamente. En el caso de EAV, no hay forma de hacerlo eficiente en una consulta. Deberías hacer el pivote en el código de la aplicación. –

Cuestiones relacionadas