MS Access - Помощь в рефакторинге запросов - PullRequest
0 голосов
/ 01 сентября 2009

У меня есть страница на одном из веб-сайтов моего клиента, которая генерирует обширный отчет, извлекающий данные из многочисленных таблиц в базе данных веб-сайта MS Access. Одной из неудачных архитектурных проблем веб-сайта является наличие двух почти идентичных таблиц, которые представляют один и тот же «тип» данных, но одна является «старой» версией, а другая - «новой» версией. Когда отчет сгенерирован, мне нужно выполнить несколько совокупных операций над двумя похожими таблицами. Первоначальный запрос объединил эти таблицы с остальными данными и вызвал соответствующие агрегатные функции для объединенных таблиц. Вскоре я понял, что объединение не будет работать, потому что две таблицы не обязательно имеют одинаковое количество строк, в результате чего агрегатная функция неправильно группирует строки из обеих таблиц ...

Если бы это был MSSQL или MySQL, я бы, вероятно, создал бы VIEW, содержащий составные данные из обеих таблиц, но, к сожалению, я застрял в MS Access, где таких "новых" концепций не существует ... Решение, к которому я смог прийти работает, но должен быть одним из самых уродливых SQL, которые я когда-либо видел. По сути, я создаю SQL-запрос, включающий все соответствующие столбцы из нескольких соединенных таблиц и одной из двух похожих таблиц. Затем я создаю второй SQL-запрос, содержащий все те же поля, и присоединяюсь к другой подобной таблице. Наконец, я UNION запрашиваю два запроса и заключаю их в подзапрос в предложении FROM внешнего запроса.

Конечным результатом является массивный запрос с кучей повторяющихся выборок, которые я включил только из-за необходимости агрегировать данные из двух похожих таблиц. Я действительно хотел бы преобразовать запрос в нечто менее ужасное, но я не уверен, с чего начать ... Любой совет?

SELECT contractid,
    pholderid,
    policyholdername,
    policyholdercity,
    policyholderstate,
    vehicleyear,
    vehiclemake,
    vehiclemodel,
    Iif(claimmileage > vehiclemileage, claimmileage, vehiclemileage)                       AS mileage,
    clientname,
    contracttype,
    contractmonths,
    wholesaleprice,
    begindate,
    cancelleddate,
    cancelledalphatotal,
    paiddate,
    voided,
    Sum(claimscost)                                                                        AS totalclaimscost,
    Sum(claimscount)                                                                       AS totalclaimscount,
    DateAdd('m', contractmonths, begindate)                                                AS expirationdate,
    Iif(paiddate IS NOT NULL AND contractmonths > 0,
       Iif(voided = true,
           Iif(cancelleddate IS NOT NULL,
               Iif(((cancelleddate - begindate) / (364.25 / 12)) >= contractmonths,
                   1,
                   ((cancelleddate - begindate) / (364.25 / 12)) / contractmonths),
               Iif(((Date() - begindate) / (364.25 / 12)) >= (contractmonths),
                   1,
                   ((Date() - begindate) / (364.25 / 12)) / contractmonths)),
           ((Date() - begindate) / (364.25 / 12)) / contractmonths),
       0)                                                                                   AS earnedfactor,
    (earnedfactor * wholesaleprice)                                                         AS earnedpremium,
    Iif(voided = true, 0, (wholesaleprice - earnedpremium))                                 AS unearnedpremium,
    Iif(voided = true AND cancelledalphatotal IS NOT NULL,  cancelledalphatotal, 0)         AS refund,
    Iif(earnedpremium > 0,totalclaimscost / earnedpremium, 0)                               AS lossratio
   FROM     (SELECT contracts.id                     AS contractid,
          policyholders.id                 AS pholderid,
          policyholders.firstname
            + ' '
            + policyholders.lastname       AS policyholdername,
          policyholders.city               AS policyholdercity,
          policyholders.state              AS policyholderstate,
          vehicles.yr                      AS vehicleyear,
          vehicles.make                    AS vehiclemake,
          vehicles.model                   AS vehiclemodel,
          vehicles.mileage                 AS vehiclemileage,
          clients.coname                   AS clientname,
          contracttypes.name               AS contracttype,
          coverageavailable.contractmonths AS contractmonths,
          contracts.contractwholesalecost  AS wholesaleprice,
          contracts.begindate              AS begindate,
          contracts.cancelledon            AS cancelleddate,
          contracts.cancelledalphatotal    AS cancelledalphatotal,
          contracts.paidon                 AS paiddate,
          contracts.voided                 AS voided,
          Sum(Iif(claims.totalrepaircost IS NULL,0,claims.totalrepaircost))                              AS claimscost,
          Count(claims.id)                    AS claimscount,
          Max(Iif(claims.currentmileage IS NULL,0,claims.currentmileage))                              AS claimmileage
   FROM   claims
          RIGHT JOIN (coverageavailable
                      INNER JOIN ((((policyholders
                                     INNER JOIN clients
                                       ON policyholders.clientid = clients.id)
                                    INNER JOIN contracts
                                      ON policyholders.id = contracts.policyholderid)
                                   INNER JOIN vehicles
                                     ON contracts.vehicleid = vehicles.id)
                                  INNER JOIN contracttypes
                                    ON contracts.contracttypeid = contracttypes.id)
                        ON coverageavailable.id = contracts.termid)
            ON claims.policyholderid = policyholders.id
   WHERE  contractmonths > 0
          AND contracts.begindate IS NOT NULL
          AND contracttypes.id <> 3
   GROUP BY contracts.id,
     policyholders.id,
     policyholders.firstname,
     policyholders.lastname,
     policyholders.city,
     policyholders.state,
     vehicles.yr,
     vehicles.make,
     vehicles.model,
     vehicles.mileage,
     clients.coname,
     contracttypes.name,
     coverageavailable.contractmonths,
     contracts.contractwholesalecost,
     contracts.begindate,
     contracts.cancelledon,
     contracts.paidon,
     contracts.voided,
     contracts.cancelledalphatotal
       UNION
       SELECT contracts.id                     AS contractid,
          policyholders.id                 AS pholderid,
          policyholders.firstname
            + ' '
            + policyholders.lastname       AS policyholdername,
          policyholders.city               AS policyholdercity,
          policyholders.state              AS policyholderstate,
          vehicles.yr                      AS vehicleyear,
          vehicles.make                    AS vehiclemake,
          vehicles.model                   AS vehiclemodel,
          vehicles.mileage                 AS vehiclemileage,
          clients.coname                   AS clientname,
          contracttypes.name               AS contracttype,
          coverageavailable.contractmonths AS contractmonths,
          contracts.contractwholesalecost  AS wholesaleprice,
          contracts.begindate              AS begindate,
          contracts.cancelledon            AS cancelleddate,
          contracts.cancelledalphatotal    AS cancelledalphatotal,
          contracts.paidon                 AS paiddate,
          contracts.voided                 AS voided,
          Sum(Iif(claim.inspector1paidout IS NULL,0,claim.inspector1paidout))
                   + Sum(Iif(claim.inspector2paidout IS NULL,0,claim.inspector2paidout))
                   + Sum(Iif(claim.mechanicpaidout IS NULL,0,claim.mechanicpaidout))
                   + Sum(Iif(claim.partdealerpaidout IS NULL,0,claim.partdealerpaidout))                              AS claimscost,
          Count(claim.id)                    AS claimscount,
          Max(Iif(claim.mileage IS NULL,0,claim.mileage))                              AS claimmileage
   FROM   claim
          RIGHT JOIN (coverageavailable
                      INNER JOIN ((((policyholders
                                     INNER JOIN clients
                                       ON policyholders.clientid = clients.id)
                                    INNER JOIN contracts
                                      ON policyholders.id = contracts.policyholderid)
                                   INNER JOIN vehicles
                                     ON contracts.vehicleid = vehicles.id)
                                  INNER JOIN contracttypes
                                    ON contracts.contracttypeid = contracttypes.id)
                        ON coverageavailable.id = contracts.termid)
            ON claim.contractid = contracts.id
   WHERE  contractmonths > 0
          AND contracts.begindate IS NOT NULL
          AND contracttypes.id <> 3
   GROUP BY contracts.id,
     policyholders.id,
     policyholders.firstname,
     policyholders.lastname,
     policyholders.city,
     policyholders.state,
     vehicles.yr,
     vehicles.make,
     vehicles.model,
     vehicles.mileage,
     clients.coname,
     contracttypes.name,
     coverageavailable.contractmonths,
     contracts.contractwholesalecost,
     contracts.begindate,
     contracts.cancelledon,
     contracts.paidon,
     contracts.voided,
     contracts.cancelledalphatotal)
GROUP BY contractid,
        pholderid,
        policyholdername,
        policyholdercity,
        policyholderstate,
        vehicleyear,
        vehiclemake,
        vehiclemodel,
        vehiclemileage,
        clientname,
        contracttype,
        contractmonths,
        wholesaleprice,
        begindate,
        cancelleddate,
        cancelledalphatotal,
        paiddate,
        voided,
        Iif(claimmileage > vehiclemileage, claimmileage, vehiclemileage)
ORDER BY clientname,
        begindate DESC

Надеюсь, все это имеет хоть какой-то смысл ...

1 Ответ

3 голосов
/ 01 сентября 2009

QueryDef в Access, похож на VIEW в других RDBMS.
Исходя из первого взгляда, лучше получить UNION-часть запроса в querydef.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...