Consulta SQL Error SQL: Invalid use of subqery
Estoy realizando la siguiente consulta con una subconsulta en visual fox 8 y muestra el error: SQL: Invalid use of subqery
Cct0004: Tiene la descripcion de las cuentas (campo desc) y se relaciona con la tabla cct0020 a través del campo ccta.
Ccy0020: Tiene al campo cuentas (campo fcta) y el campo montos (campo impo) y lo que quiero es sumar este campo (impo) en a la subconsulta y que se almacene en la variable ene (as ene).
SELECT cct0020.periodo,cct0004.ccta,cct0004.desc,cct0020.fcta,;
(select sum(cct0020.impo) FROM cct0020,cct0004;
WHERE cct0004.ccta=cct0020.ccta AND cct0020.periodo="201401") as ene;
FROM cct0004,cct0020 WHERE cct0004.ccta=cct0020;
INTO CURSOR ss readwrite
2 respuestas

Espero poder ayudarte.
El where en una consulta y debes usarlo solo para filtrar datos. Para hacer lo que necesitas podes hacerlo con un left join.
Para esto no vas a trabajar en la tabla de la cabecera, sino que lo vas a hacer en la de las cuentas, donde está tu importe. Algo así:
Select cct0020.periodo, sum(cct0020.impo) ene
from cct0020
group by ccta0020.ccta
where cct0020.periodo='201401'
Ahora, para traer ademas los datos de la descripción sería algo así la relación.
Select cct0020.periodo, sum(cct0020.impo) ene, cct0004.ccta, cct0004.desc
from cct0020
LEFT JOIN CCT0004 ON CCT0004.CCTA=CCT0020.CCTA
group by cct0020.ccta
where cct0020.periodo='201401'
La clausula left join hace la relacion.
Y después como está relacionada solo tienes que traer los datos de la otra tabla.
Por ultimo verificá que existen indices por ccta para ambas tablas así te funciona más rápido.
Otro consejo es que no uses literales, por ejemplo "201401"
Sino que utilices variables. Por ejemplo
mPeriodo="201401"
...where ccta0020.periodo=?mPeriodo
(fijate el uso del =? Para hacer referencia a una variable.)

Muchas gracias por tu tiempo, de acuerdo a tus alcances tuve que modificar mi consulta agregando una tabla mas. La consulta es esta:
Select cct0020.periodo, cct0020.ccta,cct0004.desc,cct0020.fcta,fcon0015.desc descrip,;
sum(cct0020.impo) ene;
from cct0020;
LEFT JOIN fcon0015 ON fcon0015.ccta=cct0020.fcta;
left JOIN cct0004 ON cct0004.ccta=cct0020.ccta;
group by cct0020.periodo,cct0020.ccta,cct0004.desc,cct0020.fcta, fcon0015.desc;
where cct0020.periodo='201401'
El Campo cct0020.ccta es el centro de costo que puede tener varias cuentas contables asociadas a este mismo centro de costo, estas cuentas contables se almacenan en el campo cct0020.fcta. El resultado de esta consulta es la siguiente:
periodo ccta desc fcta descrip ene
201401 93133301 Dpto. OPeraciones 621100001 remun. 2,000
201401 93133301 Dpto. OPeraciones 622100004 asign. 1,500
201401 93133301 Dpto. OPeraciones 621100005 alime. 3,200
201401 93133301 Dpto. OPeraciones 621100006 movil. 3,200
Existen 20 centros de costos que tambien tienen asignados sus cuentas contables.
Pregunta.
1. Como podria añadi otras columnas feb, mar, abr, may ... dic para que me sume por cada mes de un determinado año.
2. Si puedo enviar a otra consulta solo 6 centros de costos con sus respectivas cuentas contables, para luego poder exportarlo a excel.

.
Lo que hago yo es procesarlo después, ya en el fox. Al ejecutar una consulta como la propones lo que pasa es que se suman registros. Tantos registros como coincidencias.
.
Como regla se trata siempre de evitar la adición de columnas, o sea, expandir una tabla para la derecha. Por ejemplo hacer: cliente, mes1, mes2, mes3... estaría mal. Salvo que esas columnas fueran fijas. Por ejemplo últimos 12 periodos. Como podría ser: cliente, 201401, 201402.. 201412..
En este ultimo caso siempre son doce campos los de tu tabla. Esos campos son siempre 12 pero no quiere decir que sean fijos. Por ejemplo podrías armarte las variables de cada periodo. Algo así:
.
mPeriodo01='201311'
mPeriodo02='201312'
mPeriodo03='201401'
.
De esta manera tienes los valores que mostrás en cada campo. Después te quedaría solamente hacer la consulta y cambiarle el texto al header de la columna del grid para que el usuario sepa cual es.
.
Para ejecutar la consulta con esta variante podrías hacer algo así:
.
select cct0020.ccta, sum(if(ccta002.periodo=?mPeriodo01,ccta002.imp,0)) columna01, sum(if(ccta02.periodo=?mPeriodo02,ccta002.imp,0)cct0020) columna02
from cct0020
group by cct0020.ccta
.
Te lo explico:
Ccta002.periodo=? MPeriodo01 compara que el periodo sea el que contiene la variable mPeriodo01 (en este caso 201311)
.
Al ponerlo adentro de un if (fíjate que en fox es iif y en sql if) lo que pasa es que si el valor de respuesta es verdadero devuelve el importe, sino cero.
.
if(ccta02.periodo=?mPeriodo02,ccta002.imp,0) y esta función la ponemos dentro de un sum() para que vaya sumando.
.
Para lo otro, es decir para filtrar por determinados centros de costo lo que yo hago es tener una tabla en sql con ese filtro, relacionarla y filtrar. Eso seria lo optimo. También podría ser un literal que lo vayas armando.
.
Si tienes una tabla para filtrar en la base de datos sería algo así:
.
Suponte que tienes una tabla en la base de datos que es para filtrado con esta estructura.
.
Ccta, usuario, seleccionado
.
Después en tu programa tienes un usuario: por ejemplo mUsuario=1
.
Cuando marcas o desmarcas alguno de los centros de costos en el valid del control que marca (puede ser en el checkBox) enviarías a sql lo siguiente
mUsuario=1 &&(el valor que corresponda)
mCta=93133301
mSeleccionado=.t. &&(seleccionado)
update filtro set seleccionado=?mValor where usuario=?mUsuario and cta=?mCta
.
Después en tu consulta faltaría agregarle el left joind y la codicion.
.
left join filtro on ccta0020.ccta=filtro.cta
.
y en el where faltaria agregarle
.
and filtro.seleccionado and filtro.usuario=?mUsuario
Espero haberte podido ayudar. Tu consulta es algo que se hace en modo experto por lo cual es un poco difícil de explicar. Te recomiendo que practiques con el sql, hagas consultas desde el sql y veas los resultados, después, cuando es lo que esperas recién copies tu consulta y la pases a fox adentro de un text to..
Muchas gracias. Estamos en contacto
Christian, Keystone

Muchas gracias por darte un tiempo para contestar, he generado un cursor gracias a tus alcances desde esta consulta:
Select cct0020.ccta,cct0004.desc,cct0020.fcta,fcon0015.desc descrip,;
sum(iif(cct0020.periodo=m_ene,cct0020.impo,0.00)) ene,;
sum(iif(cct0020.periodo=m_feb,cct0020.impo,0.00)) feb,;
sum(iif(cct0020.periodo=m_mar,cct0020.impo,0.00)) mar,;
sum(iif(cct0020.periodo=m_abr,cct0020.impo,0.00)) abr,;
sum(iif(cct0020.periodo=m_may,cct0020.impo,0.00)) may,;
sum(iif(cct0020.periodo=m_jun,cct0020.impo,0.00)) jun,;
sum(iif(cct0020.periodo=m_jul,cct0020.impo,0.00)) jul,;
sum(iif(cct0020.periodo=m_ago,cct0020.impo,0.00)) ago,;
sum(iif(cct0020.periodo=m_set,cct0020.impo,0.00)) seti,;
sum(iif(cct0020.periodo=m_oct,cct0020.impo,0.00)) oct,;
sum(iif(cct0020.periodo=m_abr,cct0020.impo,0.00)) nov,;
sum(iif(cct0020.periodo=m_abr,cct0020.impo,0.00)) dic;
from cct0020;
LEFT JOIN fcon0015 ON fcon0015.ccta=cct0020.fcta;
left JOIN cct0004 ON cct0004.ccta=cct0020.ccta;
group by cct0020.ccta,cct0004.desc,cct0020.fcta, fcon0015.desc;
ORDER BY cct0020.ccta;
into cursor salida
Y el resultado es:
ccta desc fcta descrip ene feb mar ....... dic
93133301 Dpto. OPeraciones 622100001 remun. 2,000 5,000
93133301 Dpto. OPeraciones 622100004 asign. 1,500 4,000
93133301 Dpto. OPeraciones 621100005 alime. 3,200 1,500
93133301 Dpto. OPeraciones 621100006 movil. 3,200 2,00
Yo le estoy agrupando por ccta y fcta, pero habrá una forma de agrupar el campo fcta para que me sume los 3 primeros digitos de cada fcta, osea todos los que comienzan con 622, 621, etc. Gracias de antemano.

Ante todo veo algunos errores en tu consulta.
.
El group by se usa casi siempre con claves, no con descripciones. En tu consulta haces group by por el código y por la descripción lo que estaría de más porque las descripciones siempre están asociadas a una sola clave.
.
Te deberia quedar asi: group by ccta0020. Ccta, cct0020. Fcta
.
Y con eso debería funcionar. Por otro lado fíjate en las dos ultimas líneas que creo que tienes un error por copiar y pegar. Creo que las variables deberían ser m_nov y m_dic.
.
Con respecto a tu consulta lo que tienes que hacer es agrupar por una función. Cuando haces el select pones:
.
select left(cct0020.fcta,3) abrevia, .... group by ccta0020.ccta, abrevia
Te recomiendo que cambias tus datos, son complicados, el cerebro funciona mucho. Me cuesta mucho referenciar las tablas y campos, están excesivamente complicados.
.
Debería ser algo como cuentas. Codigo, asientos. Cuenta, asientos. Importe, clientes. Codigo, clientes. Nombre... y así. Cosas que se entiendan mejor. La estructura de nombres codificados de esta manera se hacía cuando los sistemas como unix no permitían nombres largos. Se solía usar codCli para un código de clientes. Ahora es más facil; te recomiendo que uses esa facilidad. Clientes. Código (la tabla clientes, el campo codigo) y así.
Muchas gracias por tu consulta.
Si necesitas otras referencias por favor cerrá esta consulta y realiza una nueva así suman.
Christian, Keystone
www.keystone.com.ar
- Compartir respuesta


El error no apunta a esto, ¿pero puedes revisar la última condición en el último WHERE? Parece que te falte especificar el campo ccta que validas de la tabla cct0020
FROM cct0004,cct0020 WHERE cct0004.ccta=cct0020;
INTO CURSOR ss readwrite

Hola gracias por contestar bueno si le puse el campo ccta a la tabla cct0020. Pero me sigue mostrando el mismo error.
SELECT cct0020.periodo,cct0004.ccta,cct0004.desc,cct0020.fcta,;
(select sum(cct0020.impo) FROM cct0020,cct0004;
WHERE cct0004.ccta=cct0020.ccta AND cct0020.periodo="201401")as ene;
FROM cct0004,cct0020 WHERE cct0004.ccta=cct0020.ccta;
INTO CURSOR ss readwrite

No estoy muy puesto en SQL con Visual Fox Pro pero por lo que he leído (ahora mismo) no permite subqueries en el select, sino a partir del Where.
Las alternativas que veo es que concatenes las queries o que que ejecutes la query simple antes y almacenes el valor independientemente (ya que va a ser el mismo para todos los registros).
Aquí explican un caso parecido al tuyo:
- Compartir respuesta
