Pregunta

Necesito un consejo para hacer frente a una consulta. Puedo manejar esto de una aplicación front-end, sin embargo, debido al diseño, tengo que inplement esto en el back-end. Tengo el siguiente


CREATE TABLE [dbo].[openitems](
    [id] [varchar](8) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [type] [char](5) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [date] [smalldatetime] NULL,
    [amount] [decimal](9, 2) NULL,
    [daysOpen] [smallint] NULL,
    [balance] [decimal](9, 2) NULL
) ON [PRIMARY]




insert into openitems values('A12399','INV','2008-12-05',491.96,123)

insert into openitems values('A12399','INV','2008-12-12',4911.37,116)

insert into openitems values('A12399','INV','2008-12-05',3457.69,109)

La tabla anterior tiene todas las facturas abiertas por un cliente. Necesito solicitar un pago de estas facturas a partir de la factura más antigua (columna daysOpen en la tabla). Así que si tengo un pago de $ 550.00, lo primero que voy a aplicarlo a la factura con 123 daysOld, eso es 491,96 $ - $ 500 (lo que deja $ 8,04 a aplicar a la siguiente factura ... y así sucesivamente), a continuación, actualizar ese registro (balance columna de la tabla) a 0,00 y pasar a la siguiente y aplicar el restante. Eso sería 4,911.37 $ - $ 8.04, lo que dejaría $ 4.903,33. Dado que no hay ningún saldo disponible para ser aplicado, el bucle termina.

La columna de equilibrio debe ser ahora

0
4903.33
3457.69

Nota: Necesito hacer esto para todos los clientes en una tabla (alrededor de 10.000). Un cliente tiene un promedio de aproximadamente 20 facturas abierta.

Gracias

¿Fue útil?

Solución

Tenga en cuenta lo siguiente:

un pago o bien se aplica en su totalidad a una balanza, se aplica en parte a un equilibrio, o la paga de un equilibrio.

Ahora, imaginemos que podemos encontrar, por cualquier balance, el importe acumulado de las facturas hasta la fecha. En lugar de imaginar que, vamos a hacerlo:

create view cumulative_balance as
select a.*, 
  (select sum( balance ) 
  from openitems b 
  where b.id = a.id and b.type = a.type and a.daysOpen >= a.daysOpen)
  as cumulative_balance
from openitems a;

Ahora podemos encontrar la primera saldo acumulado inferior o igual al pago, por cualquier ID y el tipo y la tienda que, y daysOpen, y el balance acumulado en las variables del servidor.

A continuación, actualizamos todos openItems con ese id y tipo, donde daysOpen <= el valor que obtuvimos, ajustar todos los saldos en cero.

A continuación, nos encontramos con el primer balance no nula de que la identificación y el tipo y establezca su valor sea su equilibrio - (pago - el saldo acumulado que nos guardaron). si hay un exceso de pago, este equilibrio será correctamente negativo.

Con la consulta correcta, usted será capaz de hacer las operaciones de búsqueda y la primera actualización en un comunicado.

Hay dos problemas. Una de ellas es que no se puede determinar, de dos o más alances con el mismo ID y el tipo y daysOpen, que debe ser pagado primero. Adición de un único ID a su mesa serviría como un juego de desempate para esos casos.

En segundo lugar está la necesidad de ahorrar el importe acumulado de utilizarlo en la consulta para la segunda actualización. Si ha diseñado su mesa correctamente, con una columna para INVOICE_AMOUNT que no fue actualizado por los pagos, y una columna de pago que era, esto resolvería el problema.

Una mejor refactorización sería tener dos tablas, una para las facturas y otra para el pago:. A continuación, un punto de vista podría simplemente hacer todo el trabajo, mediante la comparación de los saldos acumulados de pagos acumulados, produciendo una lista de los saldos pendientes de pago o pagos en exceso

De hecho, he diseñado sólo un sistema de este tipo para una empresa importante garantía de hipoteca con las iniciales FM. Fue un poco más complicado que lo que tiene, en la que los saldos fueron calculados a partir de una serie de fórmulas de cantidades y porcentajes, y múltiples pagadores (en realidad, aseguradoras, esto fue para hipotecas que habían entrado en default) tuvo que ser facturado en una orden prescrito de acuerdo con otras normas, por hipoteca defauted.

Todo esto se hizo en las vistas, con un corto (línea 100 o así) procedimiento que esencialmente hice lo que he descrito anteriormente almacenada: se utiliza una vista que ordenó la facturación de facturas por estas normas, los pagos aplicado (en el vista), el cálculo de lo que los pagos adicionales a facturar en qué fecha a qué aseguradora. El procedimiento almacenado entonces facturas justo generados para la fecha actual (que podría ser establecer la fecha actual, utilizando de nuevo una vista, a cualquier fecha para propósitos de prueba).

(La ironía es que hubiera tomado el trabajo onteh promesa de que tendría que escribir en C ++, el único C ++ que escribí utilizado la API de Oracle y Sybase C para transferir datos desde el sistema de Oracle para el Sybase uno.)

Otros consejos

Esto debería hacerlo. He declarado una variable local, pero se puede hacer que un parámetro de un procedimiento almacenado. También he añadido un invoice_id a la mesa para identificar de forma única las facturas desde la fecha de identificación y no parecen ser único.

DECLARE
    @paid_amount DECIMAL(9, 2)

SET @paid_amount = 500

UPDATE
    OI
SET
    balance =
            CASE
                WHEN @paid_amount - SQ.running_total > balance THEN 0
                ELSE balance - (@paid_amount - SQ.running_total)
            END
FROM
    dbo.OpenItems OI
INNER JOIN (
    SELECT
        I1.id,
        I1.invoice_id,
        I1.date,
        ISNULL(SUM(I2.amount), 0) AS running_total
    FROM
        OpenItems I1
    LEFT OUTER JOIN OpenItems I2 ON
        I2.id = I1.id AND
        I2.type = 'INV' AND
        I2.daysopen > I1.daysopen
    GROUP BY
        I1.id,
        I1.invoice_id,
        I1.date
) AS SQ ON
    SQ.id = OI.id AND
    SQ.invoice_id = OI.invoice_id
WHERE
    @paid_amount > SQ.running_total

A menos que este es un esfuerzo de una sola vez ...

Parece que esta es la lógica de los negocios y las pertenece en su capa de negocio de la aplicación.

Usted tendría que usar un par de cursores y dos bucles anidados. (Esto puede ser un poco lento)

Uno de leer todos los pagos - Asumo Cliente, Importe

A continuación, para cada cliente crear otro cursor para las partidas abiertas.

El primer bucle leerá los pagos hasta que esté hecho

Dentro de ese bucle de abrir un nuevo cursor de partidas abiertas de los clientes ordenados por antiguos primero.

bucle a través de cada elemento abierto y aplicar los pagos como usted la describe

A continuación, obtener el próximo pago.

Repetir hasta que no haya más pagos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top