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

Respuesta
1

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

1 respuesta más de otro experto

Respuesta
1

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:

http://www.tek-tips.com/viewthread.cfm?qid=738210 

Añade tu respuesta

Haz clic para o

Más respuestas relacionadas