1

私はこのように見えるテーブルを持っています:

+-----+-----------+------------+
| id  |     value |       date |
+-----+-----------+------------+
| id1 |      1499 | 2012-05-10 |
| id1 |      1509 | 2012-05-11 |
| id1 |      1511 | 2012-05-12 |
| id1 |      1515 | 2012-05-13 |
| id1 |      1522 | 2012-05-14 |
| id1 |      1525 | 2012-05-15 |
| id2 |      2222 | 2012-05-10 |
| id2 |      2223 | 2012-05-11 |
| id2 |      2238 | 2012-05-13 |
| id2 |      2330 | 2012-05-14 |
| id2 |      2340 | 2012-05-15 |
| id3 |      1001 | 2012-05-10 |
| id3 |      1020 | 2012-05-11 |
| id3 |      1089 | 2012-05-12 |
| id3 |      1107 | 2012-05-13 |
| id3 |      1234 | 2012-05-14 |
| id3 |      1556 | 2012-05-15 |
| ... |       ... |        ... |
| ... |       ... |        ... |
| ... |       ... |        ... |
+-----+-----------+------------+

value私がやりたいのは、日付ごとにこのテーブルのすべてのデータの列の合計を生成することです。1日につき1つのエントリがありidます。問題は、一部のIDがすべての日の値を持っていないことです。たとえば、id2は日付の値を持っていません:2012-05-11

私がやりたいのは、特定の日付に特定のIDの値がない場合、合計で計算される前の日付(特定の日付にはるかに近い)の値です。

たとえば、上記のデータのみがあるとします。このクエリから、特定の日付のすべての値の合計を取得できます。

SELECT SUM(value) FROM mytable WHERE date='2012-05-12';

結果は次のようになります:1511 + 1089 = 2600

しかし、私が欲しいのは、この計算を行うクエリを作成することです:1511 + 2223 + 1089 = 4823

欠落した値の代わりに、日付2012-05-11の2223が追加されるようにします。id2

| id2 |  2223 | 2012-05-11 |

SQLクエリを使用してこれを行う方法を知っていますか?またはスクリプトを介して?例:python ..


私は日付ごとに数千のIDを持っているので、可能であればクエリを少し速くしたいと思います。

4

3 に答える 3

7

テーブルの 4 つのコピーをそれ自体に結合する必要があるため、きれいではありません。これにより、あらゆる種類のパフォーマンス上の問題が発生する可能性があります (およびにインデックスを設定することを強くお勧めします)...しかし、これでうまくいきます。iddate

SELECT   y.report_date, SUM(x.value)
FROM     mytable AS x
  NATURAL JOIN (
    SELECT   a.id, b.date AS report_date, MAX(c.date) AS date
    FROM     (SELECT DISTINCT id   FROM mytable) a JOIN
             (SELECT DISTINCT date FROM mytable) b JOIN
             mytable AS c ON (c.id = a.id AND c.date <= b.date)
    GROUP BY a.id, b.date
 ) AS y
GROUP BY y.report_date

sqlfiddleで参照してください。

于 2012-05-15T18:20:24.123 に答える
2

これについて私が考えることができるSQLソリューションはあまりきれいではありません(日付シーケンステーブルへの右結合を伴う値列のcaseステートメント内のサブセレクト...それはかなり醜いです。)ので、私はPython バージョン:

import pyodbc
#connect to localhost
conn = pyodbc.connect('Driver={MySQL ODBC 5.1 Driver};Server=127.0.0.1;Port=3306;Database=information_schema;User=root; Password=root;Option=3;')
cursor = conn.cursor()

sums = {}  ## { id : { 'dates': [], 'values': [], 'sum': 0 } }      # sum is optional, you can always just sum() on the values list.

query = """SELECT
    id, value, date
FROM mytable
ORDER BY date ASC, id ASC;"""

## note that I use "fetchall()" here because in my experience the memory
## required to hold the result set is available. If this is not the case
## for you, see below for a row-by-row streaming

for row in cursor.execute(query).fetchall():
    id = sums.get(row['id'], {'dates' : [], 'values': [], 'sum': 0})
    if len(id['date']) > 0: # previous records exist for id
        # days diff is greater than 1
        days = row['date'] - id['dates'][-1]).days  
        ## days == 0, range(0) == [], in which case the loop steps won't be run
        for d in range(1, days):   
            id['dates'].append(id['dates'][-1] + datetime.timedelta(days = 1))  # add date at 1 day increments from last date point
            id['values'].append(id['values'][-1])  # add value of last date point again
            id['sum'] = id['sum'] + id['values'][-1]    # add to sum
        ## finally add the actual time point
        id['dates'].append(row['date'])
        id['values'].append(row['value'])
        id['sum'] = id['sum'] + row['value']

    else: # this is the first record for the id
        sums[row['id']] = {'dates': [row['date']], 'values': [row['value']], 'sum': row['value'] }

代替の行ごとのストリーミング ループ:

cursor.execute(query)
while 1:
    row = cursor.fetchone()
    if not row:
        break
    id = sums.get(row['id'], {'dates' : [], 'values': [], 'sum': 0})
    if len(id['date']) > 0: # previous records exist for id
        # days diff is greater than 1
        days = row['date'] - id['dates'][-1]).days  
        ## days == 0, range(0) == [], in which case the loop steps won't be run
        for d in range(1, days):   
            id['dates'].append(id['dates'][-1] + datetime.timedelta(days = 1))  # add date at 1 day increments from last date point
            id['values'].append(id['values'][-1])  # add value of last date point again
            id['sum'] = id['sum'] + id['values'][-1]    # add to sum
        ## finally add the actual time point
        id['dates'].append(row['date'])
        id['values'].append(row['value'])
        id['sum'] = id['sum'] + row['value']

    else: # this is the first record for the id
        sums[row['id']] = {'dates': [row['date']], 'values': [row['value']], 'sum': row['value'] }

完了したら、接続を閉じることを忘れないでください。

conn.close()
于 2012-05-15T18:18:00.453 に答える
0

date列のセマンティクスについてもう少し考えてみてください。

おそらくdate、代わりに列を追加して範囲を作成する必要があります。

レコードからのデータを含まない操作はすべて遅くなる可能性があります。リクエストの文字通りの解釈では、date各値を合計するためのトラバーサルが必要になる可能性があります。

于 2012-05-15T18:09:30.910 に答える