Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Conexión con bases de datos (https://www.clubdelphi.com/foros/forumdisplay.php?f=2)
-   -   ¿se puede hacer esto en una instrucción sql? (https://www.clubdelphi.com/foros/showthread.php?t=92330)

identsoft 02-10-2017 13:03:30

¿se puede hacer esto en una instrucción sql?
 
Un saludo para todos.
necesito seleccionar una serie de registros con tres campos: NOMBRE, FECHA VENCIMIENTO, IMPORTE)de una tabla (firebird) que cumplan dos condiciones:
1.- que los registros seleccionados estén entre un rango de fechas (FECHA VENCIMIENTO, es fácil)
2.- que la suma del campo IMPORTE de los registros seleccionados, no supere un importe determinado (vendrá de un tedit).

¿Es posible hacerlo con una instrucción sql o tendré que recorrer la tabla?
Estoy utilizando firebird y dbexpres.
Gracias por adelantado.

mamcx 02-10-2017 14:21:43

Claro, para filtrar un agregado como SUM utiliza la clausula HAVING:

https://www.w3schools.com/sql/sql_having.asp

identsoft 02-10-2017 16:42:49

Y como seria? porque esto me da error:
Código SQL [-]
SELECT  NOMBRE, FECHAVTO,  IMPORTE 
FROM VTOSCOBR 
where FECHAVTO between '2017-04-28' and '2017-05-01' 
group by FECHAVTO 
having (sum(importe) < 1000)

Invalid token.
Dynamic SQL Error.
SQL error code = -104.
Invalid expression in the select list (not contained in either an aggregate function or the GROUP BY clause).

lo estoy probando con IBEXPERT antes de hacerlo con DELPHI

oscarac 02-10-2017 17:05:47

Código SQL [-]
SELECT  NOMBRE, FECHAVTO,  IMPORTE 
FROM VTOSCOBR 
where FECHAVTO between '2017-04-28' and '2017-05-01' 
group by FECHAVTO 
having (sum(importe) < 1000)


te falta agregar el campo Nombre en el group

Group by nombre, fechavto

nincillo 02-10-2017 17:20:06

Cita:

Empezado por identsoft (Mensaje 521430)
Y como seria? porque esto me da error:
Código SQL [-]
SELECT  NOMBRE, FECHAVTO,  IMPORTE 
FROM VTOSCOBR 
where FECHAVTO between '2017-04-28' and '2017-05-01' 
group by FECHAVTO 
having (sum(importe) < 1000)

Invalid token.
Dynamic SQL Error.
SQL error code = -104.
Invalid expression in the select list (not contained in either an aggregate function or the GROUP BY clause).

lo estoy probando con IBEXPERT antes de hacerlo con DELPHI

¿Qué es lo que quieres que te salga como resultado del sql?

* ¿Una fila por cada uno de los recibos del cliente ?
* ¿Una única fila con la suma total de los recibos de cada cliente por día?


Porque dependiendo de lo que necesites realmente, el sql cambiará un poco.

oscarac 02-10-2017 17:29:26

Cita:

Empezado por nincillo (Mensaje 521433)
¿Qué es lo que quieres que te salga como resultado del sql?

* ¿Una fila por cada uno de los recibos del cliente ?
* ¿Una única fila con la suma total de los recibos de cada cliente por día?


Porque dependiendo de lo que necesites realmente, el sql cambiará un poco.

si, tiene toda la razon, si involucras la fecha de vencimiento en la consulta te saldran tantos registros como fechas existan
plantea mejor tu consulta, si puedes pon un ejemplo con datos y los resultados que buscas

identsoft 02-10-2017 17:52:58

Efectivamente, quiero que me salga una linea (registro) por cada fecha de vencimiento (con su nombre, su fecha de vencimiento y su importe) pero hasta que la suma de los importes seleccionados sea menor o igual que una cantidad determinada (en delphi vendrá de un tedit).

ejemplo: Suma de importes : 100€

CLIENTE FECHA IMPORTE
cliente 1 21-09-2017 40
cliente 2 22-09-2017 30
cliente 3 23-09-2017 20

cliente 4 23-09-2017 30
cliente 5 23-09-2017 20

El sql debe seleccionar cliente1,cliente2 y cliente3, porque si seleccionamos cliente 4, ya sobrepasamos el importe máximo que tenemos que seleccionar

Perdón si no he sabido expresarme mejor. Y sobretodo gracias por vuestro tiempo.

oscarac 02-10-2017 17:54:50

Cliente 1, 2 y 3 es el mismo cliente?

identsoft 02-10-2017 17:59:06

Normalmente no, pero en algún caso excepcional pudiera darse el caso.

oscarac 02-10-2017 18:02:06

ah ya
entonces tu quieres una relacion de los n primeros clientes cuya suma de importes por fecha de vencimiento sea menor a X (tu edit)

identsoft 02-10-2017 18:06:58

Eso es lo que necesito.

nincillo 02-10-2017 19:13:22

Cita:

Empezado por identsoft (Mensaje 521439)
Eso es lo que necesito.

Entonces creo que lo que necesitas es algo así:

Código:

SELECT  NOMBRE, FECHAVTO,  SUM(IMPORTE) AS Total
FROM VTOSCOBR
where FECHAVTO between '2017-04-28' and '2017-05-01'
group by NOMBRE, FECHAVTO
having (sum(importe) < 1000)
--ORDER by LO QUE QUIERAS.....


identsoft 02-10-2017 19:39:37

No es eso lo que busco.
Lo que intento sacar es todos los vencimientos comprendidos entre dos fecha (independientemente de si es el mismo cliente o es la misma fecha) pero (y aquí viene la cuestión) que la suma de lo que voy seleccionando( el importe total , no la suma del importe por cliente ) no supere el importe que le diga.

En forma de bucle seria:
leo registro 1 ; sumimporte = sumimporte + importe
si sumimporte > importeseleccionado salgo del bucle
si no
leo registro2 sumimporte = sumimporte + importe
si sumimporte > importeseleccionado salgo del bucle
sino
leo registro3......

algo así pero en forma de sql

gracias nincillo

nincillo 02-10-2017 20:03:38

Me temo que eso para un sql "normal" es bastante complicado.

Creo que tendrías que hacerlo utilizando algún cursor o algo así.

mamcx 02-10-2017 20:18:35

Es posible con Sql normal, pero todo depende del motor y su version. En el caso de Firebird, desde la version 3:

https://www.firebirdsql.org/file/com...3windowing.pdf

nincillo 02-10-2017 20:29:33

Cita:

Empezado por mamcx (Mensaje 521443)
Es posible con Sql normal, pero todo depende del motor y su version. En el caso de Firebird, desde la version 3:

https://www.firebirdsql.org/file/com...3windowing.pdf

Menudo pedazo de manual interesante...
Pero no son horas para digerir algo tan "denso".

Me lo apunto para mañana, pero me implicaría cambiar a la versión 3, que hasta ahora no había pasado de la 2.5 por temor a incompatibilidades.

mamcx 02-10-2017 20:47:52

Pero las funciones windows LO VALEN. Son geniales y resuelven un montón de escenarios.

P.D: Y si uno tiene la opción, es bueno siempre ir actualizando el motor a lo ultimo. No solo porque por lo general mejoran desempeño y resuelven bugs, sino porque el SQL se ha ido actualizando!

A proposito, asi es como quedaria:

Código SQL [-]
-- Puse los datos en memoria pa testear
WITH datos AS (
SELECT 'cliente 1' as cliente, '21-09-2017' as fecha, 40 AS importe
UNION ALL
SELECT 'cliente 2', '22-09-2017', 30
UNION ALL
SELECT 'cliente 3', '23-09-2017', 20
UNION ALL
SELECT 'cliente 4', '23-09-2017', 30
UNION ALL
SELECT 'cliente 5', '23-09-2017', 20
)

SELECT * FROM (
   -- Aqui es la magia. Usando la funcion WINDOW SUM que recorre (como un FOR) ordenado por cliente. Es importante tener en cuenta el orden. Esto acumula la suma
    SELECT *, SUM(importe) OVER (ORDER BY cliente) AS acumulado FROM datos
) reporte
-- Y por ultimo se filtra
WHERE acumulado < 100

Casimiro Notevi 02-10-2017 21:31:07

Cita:

Empezado por mamcx (Mensaje 521443)
Es posible con Sql normal, pero todo depende del motor y su version. En el caso de Firebird, desde la version 3:
https://www.firebirdsql.org/file/com...3windowing.pdf

Vaya, más cosas para estudiar :)

identsoft 03-10-2017 09:35:56

Genial!!
El problema es que trabajo con firebird 2.5
Hay que estudiar la posibilidad del cambio.


La franja horaria es GMT +2. Ahora son las 12:39:46.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi