PDA

Ver la Versión Completa : Ayuda con SQL de manejo de fechas


apicito
20-03-2013, 09:54:40
Tengo una consulta del tipo:

SQL.Clear;
SQL.Add('select * from FRAS');
SQL.Add('where ');
SQL.Add(' cast(FRAS_CONF1_DATA as date) > '+#39+FormatDateTime('mm/dd/yyyy',now()-30)+#39);
SQL.Add('or cast(FRAS_CONF2_DATA as date) > '+#39+FormatDateTime('mm/dd/yyyy',now()-30)+#39);
SQL.Add('or cast(FRAS_CONF3_DATA as date) > '+#39+FormatDateTime('mm/dd/yyyy',now()-30)+#39);
SQL.Add('order by FRAS_CONF1_DATA, FRAS_CONF2_DATA, FRAS_CONF3_DATA');

donde FRAS_CONF1_DATA,FRAS_CONF2_DATA,FRAS_CONF3_DATA son timestamp.
Lo que necesito es ordenar la consulta por estos 3 campos pero teniendo en cuenta que dependiendo del registro cualquiera de ellos puede ser el más antiguo.
Alguien puede echarme una mano con esto?.
Gracias de antemano.
Un saludo.

ozsWizzard
20-03-2013, 10:15:30
No entiendo que quieres hacer.

¿Según el registro ordenar por un campo distinto o qué?

apicito
20-03-2013, 10:24:22
Haber si soy capaz de explicarlo bien...
Estos tres campos de fecha guardan el momento en que una factura fue conformada (dada como conforme) o no. Cada factura puede asignarse hasta un máximo de tres personas para que den la conformidad en cascada, es decir, si se asigna a dos personas la primera (FRAS_CONF1_DATA) no puede conformar hasta que está conformada por la segunda (FRAS_CONF2_DATA).
Lo que necesito es recuperar las conformaciones producidas en los últimos 30 días, que es lo que hace el sql que puse en el anterior post, y después ordenar el resultado para que las que tuvieron un evento más reciente aparezcan arriba.
Espero que ahora está más claro.
Un saludo.

ozsWizzard
20-03-2013, 10:53:43
Sigo sin entenderte del todo, no sé si me he aclarado o me he confundido más.

Suponiendo que sea lo que yo he entendido. Tienes tres campo "fecha" y te interesa ordenar por la fecha (cualquiera de las tres) más baja


q.SQL.Add('SELECT [campos], FECHA');
q.SQL.Add('FROM (');
q.SQL.Add(' SELECT [campos], FRAS_CONF1_DATA AS FECHA');
q.SQL.Add(' FROM FRAS');
q.SQL.Add(' WHERE FRAS_CONF1_DATA < FRAS_CONF2_DATA');
q.SQL.Add(' AND FRAS_CONF1_DATA < FRAS_CONF3_DATA');
q.SQL.Add(' UNION');
q.SQL.Add(' SELECT [campos], FRAS_CONF2_DATA as fecha');
q.SQL.Add(' FROM FRAS');
q.SQL.Add(' WHERE FRAS_CONF2_DATA < FRAS_CONF1_DATA');
q.SQL.Add(' AND FRAS_CONF2_DATA < FRAS_CONF3_DATA');
q.SQL.Add(' UNION');
q.SQL.Add(' SELECT [campos], FRAS_CONF3_DATA as fecha');
q.SQL.Add(' FROM FRAS');
q.SQL.Add(' WHERE FRAS_CONF3_DATA < FRAS_CONF1_DATA');
q.SQL.Add(' AND FRAS_CONF3_DATA < FRAS_CONF3_DATA');
q.SQL.Add(' UNION');
q.SQL.Add(' SELECT [campos], FRAS_CONF1_DATA as fecha');
q.SQL.Add(' FROM FRAS');
q.SQL.Add(' WHERE FRAS_CONF1_DATA = FRAS_CONF2_DATA');
q.SQL.Add(' AND FRAS_CONF1_DATA < FRAS_CONF3_DATA');
q.SQL.Add(' UNION');
q.SQL.Add(' SELECT [campos], FRAS_CONF1_DATA as fecha');
q.SQL.Add(' FROM FRAS');
q.SQL.Add(' WHERE FRAS_CONF1_DATA = FRAS_CONF3_DATA');
q.SQL.Add(' AND FRAS_CONF1_DATA < FRAS_CONF2_DATA');
q.SQL.Add(' UNION');
q.SQL.Add(' SELECT [campos], FRAS_CONF2_DATA as fecha');
q.SQL.Add(' FROM FRAS');
q.SQL.Add(' WHERE FRAS_CONF2_DATA = FRAS_CONF3_DATA');
q.SQL.Add(' AND FRAS_CONF2_DATA < FRAS_CONF1_DATA');
q.SQL.Add(')');
q.SQL.Add('CAST(FECHA AS DATE) > ' +#39 + FormatDateTime('mm/dd/yyyy',now()-30)+#39);
q.SQL.Add('ORDER BY FECHA');
//[campo] = Lista de campos

Neftali [Germán.Estévez]
20-03-2013, 12:06:28
No se si te he entendido bien....

¿Quieres ordenar la consulta de forma que te ordene los registros, pero no por un campo, sino por el valor más antiguo (o nuevo) que exista en cualquiera de esos tres?
¿Es decir que el valor de ordenación sea el más antiguo/nuevo de los tres campos?

Si es así, yo crearía un campo FECHA_CONF_CAL (que se calcule y mantenga por trigger) que almacene y que mantenga el más antiguo o más nuevo de los tres.
Después sólo debes usar ese campo para las ordenaciones.

apicito
20-03-2013, 12:27:51
Si es así, yo crearía un campo FECHA_CONF_CAL (que se calcule y mantenga por trigger) que almacene y que mantenga el más antiguo o más nuevo de los tres.
Gracias por la respuesta.
Ya había pensado en esto pero pretendía hacerlo sin modificar la base de datos por lo que implicaría a efectos de actualización de todos mis clientes.
Estoy probando la solución de ozsWizzard. Ya no me da errores, pero tampoco me devuelve ningún registro. En algún sitio me estoy equivocando. Ya os diré.
Otra solución en la que habia pensado era en la de utilizar algo como un campo calculado en el que almacenar el valor más reciente de los tres. Pero no sabría como hacerlo.
Sigo con la solución de ozsWizzard.
Por cierto, si, has entendido perfectamente mi problema.Saludos.

Neftali [Germán.Estévez]
20-03-2013, 13:05:10
¿Qué problema hay en cambiar la Base de Datos si es necesario?
En general los UNION son todo lo contrario a "eficientes" y me parece una solución no-directa para un problema bastante sencillo.

apicito
20-03-2013, 13:28:33
El problema es la intendencia que me requiere este tipo de cambios...

ozsWizzard
20-03-2013, 13:35:03
Por partes

Seguramente no te salgan datos por culpa de que no me he molestado en tener en consideración las fechas nulas. Tendrías que ajustar los "where"s individuales para que las fechas nulas las tome como "fechas 0".

Neftalí tiene razón, y dado que tendrás que distribuir un ejecutable, siempre puedes crear el campo, si no existe, al iniciar el programa. (Y rellenarlo, para ello seguro que sirve la select que he puesto yo, sin el where final y teniendo en cuenta la posibilidad de los nulos, de esta forma la select solamente la usas una vez, para cargar los datos en el campo [que otra forma sí que no sé])


Edito y añado:
Yo tengo esto mismo en un programa, justo después de establecer la conexión (lo que tengo justo después es la llamada al procedimiento, lógicamente)

//NO es igual que lo que tengo pero el efecto es el mismo
procedure TDataModule1.AñadirCampoX;
var
q: TSqlQuery;
begin
q := TsqlQuery.Create(Self);
try
q.SQLConnection := Conec; //así se llama la conexión
try
q.Sql.Add('select CampoX From Tabla1');
q.Open;
except
q.Sql.Add('ALTER TABLE Tabla1 ADD COLUMN CampoX tipo_dato');
q.ExecSQL;
end;
finally
q.Free;
end;
end;

En tu caso debes añadir como rellenar el campo después de crearlo.

Saludos

apicito
20-03-2013, 14:12:39
Al final lo he solucionado así:
SELECT distinct FRAS_CONF1_DATA AS FECHAR,
FRAS_CODIGO, FRAS_DATA, FRAS_NUMERO, ....
FROM FRAS
where
FRAS_CONF1_DATA > '02/18/2013'

union ALL

SELECT distinct FRAS_CONF2_DATA AS FECHAR,
FRAS_CODIGO, FRAS_DATA, FRAS_NUMERO, ....
FROM FRAS
where
FRAS_CONF2_DATA > '02/18/2013'

union ALL

SELECT distinct FRAS_CONF3_DATA AS FECHAR,
FRAS_CODIGO, FRAS_DATA, FRAS_NUMERO, ...
FROM FRAS
where
FRAS_CONF3_DATA > '02/18/2013'

ORDER BY 1,4
Gracias por vuestra ayuda.
un saludo.

apicito
20-03-2013, 14:19:23
En la solución anterior sobra el distinct, ya que no cumple ninguna función. El campo FECHAR es timestamp y por lo tanto siempre es distinto y hace que si esa factura la conformaron dos personas en el perído de consulta muestre dos registros.
Al principio pensé que era un problema, pero pensandolo bien, como el objetivo de esta consulta es mostrarle al encargado los eventos que se produjeron en un período, no está mal que pueda ver que recibió dos conformidades o rechazos.
Saludos.

Al González
20-03-2013, 19:40:32
No soy experto en SQL, pero usando una expresión Case en el Order By podría bastar. Hice esta pequeña prueba con una de mis tablas y funcionó:
Select ID, Fecha, FechaEjecucion From OrdenTrabajo
Order By
Case
When Fecha < FechaEjecucion Then Fecha
Else FechaEjecucion
End

Como FechaEjecucion puede ser Null, añadiendo "Nulls First", hacemos que la consulta traiga primero los registros que tienen vacío ese campo:

Select ID, Fecha, FechaEjecucion From OrdenTrabajo
Order By
Case
When Fecha < FechaEjecucion Then Fecha
Else FechaEjecucion
End Nulls First
En tu caso el Case involucraría tres campos. Sería un poco más grande, pero nada del otro mundo.

apicito
21-03-2013, 15:06:52
Con la solución que postee: "order by 1,4" ya funciona correctamente la ordenación. Ordena por el campo FECHAR y FRAS_NUMERO.
Realmente el único "fallo" que le encuentro es que no permite hacer distinc excluyendo FECHAR y que hace que puedan aparecer más de una linea de la misma factura si fue conformada por más de una persona en el período de la consulta.
Saludos.