05.02.2009 18:48
Цитата:
Andrew_Konev те же остатки по поставщикам - вообще нереально посчитать по другому на базе, которую 4 года "портили". особенно, если базу обрезать.

сложнее с товарами, по которым текущий расчетный остаток не совпадает с реальным (пересорты, к примеру): излишек по пересорту полезет привязываться к старым приходам и будет портить картинку. недостача по пересорту - вообще никуда не привяжется и занизит задолженность перед поставщиком
Все верно, но нужно искать компромисс.
Если предположить, что пересорт возможен только на взаимозаменяемых товарах, то сумма по группе должна быть относительно точной.

Раз была затронута тема с поставщиками, то еще один запросик попытки вычислить остатки по магазинам в закупочных ценах по поставщикам и поставкам (относительно точно и быстро). За основу был взят запрос в начале темы. Специально не группировал, чтоб было видно привязку к партиям по датам.

Код:
SELECT   z.LOCATION, z.article, z.createdat, NVL (z.clientindex, -1) clientindex, z.goods, 
         CASE
            WHEN z.quantity IS NULL
               THEN z.goods
            WHEN z.goods2 - z.quantity >= z.goods
               THEN NULL
            WHEN z.goods2 - z.quantity < z.goods AND z.goods >= z.goods2
               THEN z.quantity
            WHEN z.goods2 - z.quantity < z.goods AND z.goods < z.goods2
               THEN z.quantity - (z.goods2 - z.goods)
         END quantity,
         (CASE
             WHEN z.quantity IS NULL
                THEN z.goods * z.itemprice
             WHEN z.goods2 - z.quantity >= z.goods
                THEN NULL
             WHEN z.goods2 - z.quantity < z.goods AND z.goods >= z.goods2
                THEN z.quantity * z.itemprice
             WHEN z.goods2 - z.quantity < z.goods AND z.goods < z.goods2
                THEN (z.quantity - (z.goods2 - z.goods)) * z.itemprice
          END
         ) totalprice
    FROM (SELECT g.LOCATION, g.article, s.clientindex, s.createdat, g.goods,
                 CASE
                    WHEN COUNT (s.quantity) OVER (PARTITION BY g.LOCATION, g.article) = 1
                       THEN g.goods
                    ELSE s.quantity
                 END quantity, NVL (s.totalprice / s.quantity,
                                    NVL ((SELECT p.price
                                            FROM smprices p
                                           WHERE p.storeloc = g.LOCATION AND p.article = g.article AND p.pricetype = 6), 0)) itemprice,
                 CASE
                    WHEN COUNT (s.quantity) OVER (PARTITION BY g.LOCATION, g.article) = 1
                       THEN g.goods
                    ELSE SUM (s.quantity) OVER (PARTITION BY g.LOCATION, g.article ORDER BY s.createdat DESC)
                 END goods2
            FROM (SELECT storeloc LOCATION, article, quantity goods
                    FROM smgoods g
                   WHERE g.quantity > 0 AND EXISTS (SELECT /*+ INDEX (C)*/
                                                           1
                                                      FROM smcard c
                                                     WHERE c.datatype = 0 AND c.article = g.article)) g,
                 (SELECT   /*+ INDEX(D)*/
                           d.locationto LOCATION, d.clientindex, d.createdat, s.article, SUM (s.quantity) quantity, SUM (s.totalprice) totalprice
                      FROM smdocuments d, smspec s
                     WHERE d.doctype = 'WI' AND d.createdat > SYSDATE - 90 AND d.docstate = 3 AND d.opcode != 9 AND s.doctype = d.doctype AND s.docid = d.ID
                  GROUP BY d.locationto, d.clientindex, d.createdat, s.article) s
           WHERE g.LOCATION = s.LOCATION(+) AND g.article = s.article(+)
          UNION ALL
          SELECT g.LOCATION, g.article, NULL clientindex, NULL createdat, g.goods, NULL quantity,
                 NVL ((SELECT p.price
                         FROM smprices p
                        WHERE p.storeloc = g.LOCATION AND p.article = g.article AND p.pricetype = 6), 0) totalprice, NULL goods2
            FROM (SELECT storeloc LOCATION, article, quantity goods
                    FROM smgoods g
                   WHERE g.quantity < 0 AND EXISTS (SELECT /*+ INDEX (C)*/
                                                           1
                                                      FROM smcard c
                                                     WHERE c.datatype = 0 AND c.article = g.article)) g) z
   WHERE z.quantity IS NULL OR z.goods2 - z.quantity < z.goods
Чем меньше магазинов - тем быстрее отработает (сейчас по всем)
Чем больше период (сейчас 90 дней) - тем больше точность данных привязки к партиям.
Отрицательные остатки изначально к поставщикам не привязываем и используем pricetype = 6, это же относится и к положительным если не обнаружено ни одной поставки (если и это невозможно то цена 0). Если были поставки которых не достаточно для перекрытия остатка, то не перекрытый приходами остаток будет привязан к цене и соотв. поставщику самой ранней по дате.