6

開発援助プロジェクトのために、私はニカラグアの小さな町の水ネットワーク管理を改善するのを手伝っています。

約150世帯があり、毎月、メーターをチェックし、消費水量(今月からの読み取り値から先月からの読み取り値を差し引いたもの)に応じて世帯に課金します。今日はすべて紙で行われているので、計算エラーを避けるために管理をデジタル化したいと思います。

私はMSAccessテーブルを念頭に置いています-例:

*HousholdID*  *Date*     *Meter*
0             1/1/2013   100
1             1/1/2013   130
0             1/2/2013   120
1             1/2/2013   140
...

このデータから、消費水量(1世帯の2か月間のメーター差)を計算するクエリを作成したいと思います。

*HouseholdID*  *Date*     *Consumption*
0              1/2/2013   20
1              1/2/2013   10
...

どうか、この問題にどのようにアプローチしますか?

4

5 に答える 5

4

このクエリは、月が欠落している場合でも、前の日付のすべての日付を返します。

SELECT TabPrev.*, Tab.Meter as PrevMeter, TabPrev.Meter-Tab.Meter as Diff
FROM (
  SELECT
    Tab.HousholdID,
    Tab.Data,
    Max(Tab_1.Data) AS PrevData,
    Tab.Meter
  FROM
    Tab INNER JOIN Tab AS Tab_1 ON Tab.HousholdID = Tab_1.HousholdID
                                 AND Tab.Data > Tab_1.Data
  GROUP BY Tab.HousholdID, Tab.Data, Tab.Meter) As TabPrev
  INNER JOIN Tab
  ON TabPrev.HousholdID = Tab.HousholdID
     AND TabPrev.PrevData=Tab.Data

結果は次のとおりです。

HousholdID  Data        PrevData    Meter  PrevMeter  Diff
----------------------------------------------------------
0           01/02/2013  01/01/2013  120    100        20
1           01/02/2013  01/01/2012  140    130        10

上記のクエリは、すべてのデルタ、すべての世帯、毎月(またはすべての間隔)を返します。最後のデルタに関心がある場合は、次のクエリを使用できます。

SELECT
  MaxTab.*,
  TabCurr.Meter as CurrMeter,
  TabPrev.Meter as PrevMeter,
  TabCurr.Meter-TabPrev.Meter as Diff
FROM ((
  SELECT
    Tab.HousholdID,
    Max(Tab.Data) AS CurrData,
    Max(Tab_1.Data) AS PrevData
  FROM
    Tab INNER JOIN Tab AS Tab_1
        ON Tab.HousholdID = Tab_1.HousholdID
           AND Tab.Data > Tab_1.Data
  GROUP BY Tab.HousholdID) As MaxTab
  INNER JOIN Tab TabPrev
  ON TabPrev.HousholdID = MaxTab.HousholdID
     AND TabPrev.Data=MaxTab.PrevData)
  INNER JOIN Tab TabCurr
  ON TabCurr.HousholdID = MaxTab.HousholdID
     AND TabCurr.Data=MaxTab.CurrData

そして(あなたが何を求めているかに応じて)あなたは今月しかフィルタリングできませんでした:

WHERE
  DateSerial(Year(CurrData), Month(CurrData), 1)=
  DateSerial(Year(DATE()), Month(DATE()), 1)

このように、特定の世帯のチェックを見逃した場合、それは表示されません。または、テーブルに先月の存在を表示することに興味があるかもしれません(これは今月とは異なる場合があります)。

WHERE
  DateSerial(Year(CurrData), Month(CurrData), 1)=
  (SELECT MAX(DateSerial(Year(Data), Month(Data), 1))
  FROM Tab)

(ここでは、小切手が別の日に行われる可能性があるという事実を考慮しています)

于 2013-02-05T22:01:06.340 に答える
3

最善のアプローチは、相関サブクエリを使用して前の日付を取得し、元のテーブルに結合することだと思います。これにより、1か月以上または1か月未満のラグがある場合でも、前のレコードを確実に取得できます。

したがって、正しいクエリは次のようになります。

select t.*, tprev.date, tprev.meter
from (select t.*,
             (select top 1 date from t t2 where t2.date < t.date order by date desc
             ) prevDate
      from t
     ) join
     t tprev
     on tprev.date = t.prevdate

あなたが説明するような環境では、メーターを読み取る頻度について推測しないことが非常に重要です。それらは平均して月に一度読まれるかもしれませんが、常に例外があります。

于 2013-02-05T21:55:28.493 に答える
2

次のデータを使用したテスト:

HousholdID  Date        Meter
0           01/12/2012  100
1           01/12/2012  130
0           01/01/2013  120
1           01/01/2013  140
0           01/02/2013  120
1           01/02/2013  140

次のクエリ:

SELECT a.housholdid, 
   a.date, 
   b.date, 
   a.meter, 
   b.meter, 
   a.meter - b.meter AS Consumption
FROM   (SELECT * 
    FROM   water 
    WHERE  Month([date]) = Month(Date()) 
           AND Year([date])=year(Date())) a 
   LEFT JOIN (SELECT *
              FROM water
              WHERE DateSerial(Year([date]),Month([date]),Day([date]))
               =DateSerial(Year(Date()),Month(Date())-1,Day([date])) ) b 
   ON a.housholdid = b.housholdid 

上記のクエリは、今月のレコードを選択し、Month([date]) = Month(Date())それらを先月のレコードと比較します([date]) = Month(Date()) - 1)

フィールド名としてDateを使用しないでください。

次の結果を返します。

housholdid  a.date      b.date      a.meter b.meter Consumption
0           01/02/2013  01/01/2013  120     100     20
1           01/02/2013  01/01/2013  140     130     10
于 2013-02-05T21:48:03.903 に答える
1

試す

select  t.householdID
       , max(s.theDate) as billingMonth
       , max(s.meter)-max(t.meter) as waterUsed
from    myTbl t join (
    select  householdID, max(theDate) as theDate, max(meter) as meter
    from    myTbl 
    group by householdID ) s 
        on t.householdID = s.householdID and t.theDate <> s.theDate
group by t.householdID

これはSQLで機能し、アクセスについてはよくわかりません

于 2013-02-05T21:56:21.997 に答える
0

特定のSQLダイアレクトでLAG()関数を使用できます。これは、結合よりもはるかに高速で読みやすいことがわかりました。

出典: http: //blog.jooq.org/2015/05/12/use-this-neat-window-function-trick-to-calculate-time-differences-in-a-time-series/

于 2016-02-23T22:03:43.137 に答える