Soma diária em BD com python

Segue um exemplo de como fazer uma consulta em um banco de dados (BD), calcular a soma diária dos valores de uma coluna e gravar um arquivo com o valor. Escrito em python e com uma consulta usando SQL, contém vários elementos para estudo.

Primeiramente, script a seguir importa os módulos necessários, recebe três argumentos externos (tipo/grupo, data inicial e data final) e define o caminho (path) do script em execução. Depois, ele abre um arquivo com o nome e código dos pontos de um grupo para ler linha por linha (exceto a primeira). Cada linha é quebrada pelo caractere espaço de modo a formar um vetor para guarda o primeiro elemento (o código do ponto).

A query de consulta ao banco de dados PostgreSQL extrai ano, mês e dia da coluna “data” para salvar essas variáveis em colunas separadas. Além disso, os dados são agrupados (GROUP BY) por dias e ordenados cronologicamente. Desse modo, são somados todos os valores horários da coluna “variavel” dentro de um mesmo dia (SUM).

O resultado da consulta ao banco é guardado no vetor de vetores “valores” (cada dia tem cinco valores, e o vetor final tem tantos elementos quanto o número de dias). Foi incluída uma verificação do tamanho do vetor para saber se tem o número desejado de dias ou se o resultado está incompleto ou mesmo vazio.

import psycopg2
import psycopg2.extras
import os
import sys

tipo = sys.argv[1]
datai = sys.argv[2]
dataf = sys.argv[3]
path = os.path.dirname(os.path.realpath(__file__))

with open('%s/Arq_Entrada/%s_postos.txt' % (path, tipo)) as arq:
	next(arq)
	for linha in arq:
		vetor = linha.strip().split(" ")
		posto = vetor[0]

		# Montar query
		query = '''SELECT codigo, EXTRACT(YEAR FROM data) as year, EXTRACT(MONTH FROM data) as month, EXTRACT(DAY FROM data) as day, SUM(variavel) 
		FROM schema.table WHERE codigo = '%s' AND data BETWEEN '%s' AND '%s' 
		GROUP BY codigo, EXTRACT(DAY FROM data), EXTRACT(MONTH FROM data), EXTRACT(YEAR FROM data) ORDER BY year ASC, month ASC, day ASC;''' %(posto, datai, dataf)
		#print(query)

		# Executar query
		conn = psycopg2.connect(host = "hostname", database = "db", user="usuario")
		cursor = conn.cursor(cursor_factory = psycopg2.extras.DictCursor)
		cursor.execute(query)
		valores = cursor.fetchall()
		# Fechar ponteiro e conexão
		cursor.close()
		conn.close()
		if len(valores) != 46:
			print "Posto " + posto + " vazio ou incompleto!"
		else:
			print "Posto " + posto + " OK"
		
		# Gravar arquivo com dados
		with open('%s/Arq_Saida/Posto_%s.txt' % (path, posto), 'wb') as f:
			f.write('codigo data valor\n')
			for line in valores:
				i = 0
				for elemento in line:
					if elemento == None:
						line[i] = "-"
					else:
						line[i] = round(float(elemento),1)
					i = i + 1
				f.write("%08d %02d/%02d/%04d %s\n" %(int(line[0]),int(line[3]),int(line[2]),int(line[1]),str(line[4])))
			#sys.exit("fim de teste")

Por fim, é gravado um arquivo de saída com o nome do ponto trabalhado (com cabeçalho), linha por linha. Em cada linha (um vetor), é feita uma verificação em cada elemento: se estiver vazio, grava um traço; caso contrário, arredonda o valor para uma casa decimal. O código (formatado para ter 8 dígitos), a data e o valor (já convertido para string) são gravados separados por espaço.