SQL: Как вы усредняете данные ежемесячно, ссылаясь только на месяцы из данного года? - PullRequest
0 голосов
/ 07 апреля 2019

Я работаю над проектом для одного из моих классов Python и пытаюсь собрать среднемесячный снегопад за определенный год.В моем наборе данных, данные, собранные за период с 2016 по 2017 год для многих различных форпостов погоды.

Это просто для очистки некоторых CSV-файлов с погодой с помощью SQLite.Мне удалось получить данные, традиционно в формате CSV, в формат sqlite в памяти, но мой SQL ржавый, и я не могу получить данные для пересылки так, как я хочу.Я просмотрел, попытался разделить данные с помощью WHERE DATE < '20170101' перед группировкой по дате, но я даже не могу разделить данные с датами (возможно, проблема в том, как SQL выглядит для дат и как мои даты выбиваются,который выглядит как 12/24/2017).

Вот что я пытаюсь запустить

con = sqlite3.connect(":memory:")
cur = con.cursor()
cur.execute("CREATE TABLE t (STATION, NAME, DATE, AWND, SNOW);")

with open('filteredData.csv','r') as fin:
    # csv.DictReader uses first line in file for column headings by default
    dr = csv.DictReader(fin) # comma is default delimiter
    to_db = [(i['STATION'], i['NAME'], i['DATE'], i['AWND'], i['SNOW']) for i in dr]

cur.executemany("INSERT INTO t (STATION, NAME, DATE, AWND, SNOW) VALUES (?, ?, ?, ?, ?)", to_db)
con.commit()
data = cur.execute("SELECT STATION, NAME, DATE, AWND, AVG(SNOW) FROM t GROUP BY STATION")

, и я пытался добавить строку в execute или executemanyоператоры для сортировки всех записей данных и фильтрации до года, например, так:

cur.executemany("INSERT INTO t (STATION, NAME, DATE, AWND, SNOW) VALUES (?, ?, ?, ?, ?) WHERE DATE < '20170101'", to_db)

Я ожидал, что результаты покажут (прямо сейчас) средние снегопады по каждому местоположению за 2016 год (все еще работая над дальнейшим разделением до среднемесячного снегопадакаждое местоположение), но когда я добавляю строку выше, я получаю сообщение об ошибке.Когда я запускаю код без оператора WHERE, код обрабатывается нормально (и выводит обратно в CSV, как я и хотел), но показывает только средние значения для каждого местоположения, независимо от того, на какой временной шкале были взяты эти средние значения.

Для тех, кому интересно, формат даты в csv, из которого я импортирую, выглядит примерно так: 12/24/2017

EDIT: Я изменил оператор execute впеременная data, похожая на

Jan = cur.execute("SELECT STATION, NAME, DATE, AWND, AVG(SNOW) FROM t WHERE (DATE > '2016-01-01' AND DATE < '2016-02-01') GROUP BY STATION")

Ян теперь отражает среднее значение для дат 2016-01-01 до 2016-02-01, которое, для записи, похоже, на самом деле берет январское среднее количество снегопада и выводит егов CSV.Сейчас я работаю над тем, чтобы заставить февраль печатать после него, не перезаписывая его, из-за чего просто вызывая другой оператор записи с другой переменной, кажется, просто перезаписываем его.

Ответы [ 3 ]

0 голосов
/ 07 апреля 2019

Это то, что вы хотите?

select station, name, strftime('%Y-%m') as yyyymm,
       avg(snow)
from t
group by station, name, strftime('%Y-%m');

Вы можете добавить предложение where, чтобы ограничить данные определенным периодом времени. Например, на 2016 год:

select station, name, strftime('%Y-%m', date) as yyyymm,
       avg(snow)
from t
where date >= '2016-01-01' and
      date < '2017-01-01'
group by station, name, strftime('%Y-%m', date);
0 голосов
/ 07 апреля 2019

Хорошо, поэтому, поработав некоторое время с другом над программой, мы оба поняли, что нам нужно на самом деле вызвать программу в цикл и выполнить до ее фиксации в файле.Вот что мы написали:

with open("Average2016.csv",'w') as f:
    writer = csv.writer(f)
    writer.writerow(['STATION','NAME','DATE','AWND','SNOW'])
    '''
    Fun for loop for generating dates. This uses zfill to pad the dates to 2 decimals
    and checks whether we are on Dec. or not. If we are, skip to next January.
    Then we use an f-string to create a SQL command and execute it and then write
    the return value into the CSV.
    '''
    for x in range(1, 13):
        date1 = '2016-' + str(x).zfill(2) + '-01'
        date2 = '2016-' + str(x + 1).zfill(2) + '-01'
        if (x == 12):
            date2 = '2017-01-01'
        sqlCmd = f"SELECT STATION, NAME, DATE, AWND, AVG(SNOW) FROM t WHERE (DATE >= '{date1}' AND DATE < '{date2}') GROUP BY STATION"
        db_val = cur.execute(sqlCmd)
        writer.writerows(db_val)

Я хотел сказать, что именно так я и писал, во-первых, но я думаю, что он называется немного иначе, чем (откровенно грязный) способ, которым я звонил раньше,Спасибо всем остальным за помощь, хотя!

0 голосов
/ 07 апреля 2019
SELECT
    STATION
  , NAME
  , MIN(DATE)
  , AVG(AWND)
  , AVG(SNOW)
FROM
 t
WHERE 
 DATE < '1/1/17'
GROUP BY
 STATION

Этот оператор SQL недопустим по стандартам SQL 92+.В общем случае при использовании GROUP BY все неагрегированные столбцы, которые используются в предложении SELECT, также должны быть в предложении GROUP BY.Таким образом, столбец Name также должен использоваться в предложении GROUP BY, но это даст вам недопустимые результаты для вашего вопроса.

Я полагаю, что вы ищете этот запрос.

SELECT 
 t.*
FROM (
  SELECT 
      STATION
    , MIN(DATE) AS min_date
    , AVG(AWND) AS avg_awnd
    , AVG(SNOW) AS avg_snow
  FROM 
   t
  WHERE
   DATE < '1/1/17'
  GROUP BY 
    STATION
) AS t_aggregated
INNER JOIN
 t 
ON
   t_aggregated.STATION = t.STATION
 AND
   t_aggregated.min_date = t.date
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...