2009-09-01 79 views
0

我在客戶的一個網站上有一個頁面,它生成一個廣泛的報告,從整個網站的MS Access數據庫中的大量表格中提取數據。該網站的一個不幸的架構問題是存在兩個幾乎相同的表,它們代表相同的「類型」數據,但其中一個是「舊」版本,另一個是「新」版本。生成報告時,我需要對兩個相似的表執行一些聚合操作。初始查詢將這些表連接到其餘數據,並在連接的表上調用適當的聚合函數。不久,我意識到一個連接將無法正常工作,因爲這兩個表不一定有相同的行數,從而導致聚合函數不正確地將這兩行中的行分組...MS Access - 查詢重構幫助

這是MSSQL還是MySQL我可能創建一個包含來自兩個表的複合數據的VIEW,但不幸的是我被困在MS Access中,這些「新穎」的概念不存在......我能夠提出的解決方案的工作,但必須是一些我見過的最醜陋的SQL。基本上,我創建了一個SQL查詢,其中包括來自多個連接表的所有適當列和兩個相似表中的一個。然後,我創建了第二個包含所有相同字段的SQL查詢並加入其他類似的表。最後,我將這兩個查詢包裝到外部查詢的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 

希望一切,使得至少某種意義上...

回答

3

的QueryDef在Access中,類似於其他RDBMS的視圖。
基於第一眼,最好在querydef中獲取查詢的UNION部分。

+0

...如果記錄在兩個數據集之間是唯一的,則可以使用UNION ALL加快速度(沒有ALL的UNION將取消延遲,並且即使在沒有重複時也會減慢速度)。 –

+0

@David:謝謝你的建議。您似乎非常擅長Access(特定)。 – shahkalpesh