Tengo una tabla de pedidos
Column | Type | Modifiers
------------+-----------------------------+-----------------------------------------------------
id | integer | not null default nextval('orders_id_seq'::regclass)
client_id | integer | not null
start_date | date | not null
end_date | date |
order_type | character varying | not null
Los datos tienen órdenes permanentes no superpuestas para un client_id y, ocasionalmente, una orden temporal que anula la orden permanente en su start_date cuando tienen un client_id coincidente. Existen restricciones a nivel de aplicación que evitan que se superpongan órdenes del mismo tipo.
id | client_id | start_date | end_date | order_type
----+-----------+------------+------------+------------
17 | 11 | 2014-02-05 | | standing
18 | 15 | 2014-07-16 | 2015-07-19 | standing
19 | 16 | 2015-04-01 | | standing
20 | 16 | 2015-07-18 | 2015-07-18 | temporary
Por ejemplo, en el 2015-07-18
cliente 16 tiene la orden # 20, ya que es una orden activa porque anula la orden permanente # 19. Con un poco de alboroto, encontré una forma eficiente de consultar los ID de pedidos activos en una fecha.
SELECT id from (
SELECT
id,
first_value(id) OVER (PARTITION BY client_id ORDER BY order_type DESC) active_order_id
FROM orders
WHERE start_date <= ? and (end_date is null OR end_date >= ?)
) active_orders
WHERE id = active_order_id
Si consulta esto 2015-07-18
como marcadores de posición, obtendrá
id
----
17
18
20
El plan de consulta en esta consulta en comparación con algunas de mis otras ideas (como las subconsultas que cuentan el número de pedidos temporales para un cliente en una fecha) es bastante pequeño y estoy bastante contento con él. (el diseño de la mesa, no me entusiasma)
Ahora, necesito un para encontrar todas las órdenes activas para un rango de fechas unidas con las fechas en que están activas. Por ejemplo, con el rango de fechas de 2015-07-18
a 2015-07-19
me gustaría el siguiente resultado.
active_date | id
------------+----
2015-07-18 | 17
2015-07-18 | 18
2015-07-18 | 20
2015-07-19 | 17
2015-07-19 | 18
2015-07-19 | 19
La orden 20 anula la orden 19 en 2015-07-18
pero no en 2015-07-19
.
Descubrí generate_series()
que puedo generar un rango de fechas, pero no tengo ni idea de cómo unir eso con esto para obtener una tabla de fechas y órdenes de identificación. Mi presentimiento es una unión cruzada, pero no puedo entender cómo hacer que eso funcione en esta circunstancia.
Gracias
ACTUALIZACIÓN Se agregó un violín sql .
fuente
Respuestas:
Usaría en
select distinct on
lugar de la función de ventana, luego solo uniría los días.http://sqlfiddle.com/#!15/5a420/16/0
Puedo elaborar más si algo no está claro.
fuente
distinct on
está aún más optimizado que la consulta de ventana. Por cierto, debo mencionar que este es un problema común "top-in-group" en SQL: stackoverflow.com/questions/3800551/…Escriba una función que tome una sola fecha como parámetro y devuelva una lista de fechas + id que tienen un orden.
Luego, use la serie generate_series como sugirió y llame a la función durante el intervalo de fechas.
Esta es una estrategia común cuando se trata de condiciones complejas en SQL.
He incluido un código a continuación, pero la respuesta de SQL anterior es mucho más simple.
Aquí está la función:
Y como llamarlo:
SQLFiddle
fuente