Применить функцию к столбцу перед фильтрацией
У меня есть столбец в моей базе данных под названием coordinates
, теперь столбец координат содержит информацию о диапазоне времени, которое объект занимает в моем графике. Я хочу разрешить пользователю фильтровать по дате, но проблема в том, что я использую функцию для определения даты в обычном режиме. Возьмем:
# query_result is the result of some filter operation
for obj in query_result:
time_range, altitude_range = get_shape_range(obj.coordinates)
# time range for example would be "2006-06-01 07:56:17 - ..."
Теперь, если я хочу фильтровать по дате, я бы хотел, чтобы это был like
:
query_result = query_result.filter(
DatabaseShape.coordinates.like('%%%s%%' % date))
Но проблема в том, что мне сначала нужно применить get_shape_range
к coordinates
, чтобы получить строку. Есть ли способ сделать... Я предполагаю операцию transform_filter? Такое, что до like
происходит, я применяю некоторую функцию к координатам? В этом случае мне нужно будет написать функцию get_time_range
, которая вернула бы только время, но вопрос остается тем же.
EDIT: Здесь мой класс базы данных
class DatabasePolygon(dbBase):
__tablename__ = 'objects'
id = Column(Integer, primary_key=True) # primary key
tag = Column(String) # shape tag
color = Column(String) # color of polygon
time_ = Column(String) # time object was exported
hdf = Column(String) # filename
plot = Column(String) # type of plot drawn on
attributes = Column(String) # list of object attributes
coordinates = Column(String) # plot coordinates for displaying to user
notes = Column(String) # shape notes
lat = Column(String)
@staticmethod
def plot_string(i):
return constants.PLOTS[i]
def __repr__(self):
"""
Represent the database class as a JSON object. Useful as our program
already supports JSON reading, so simply parse out the database as
separate JSON 'files'
"""
data = {}
for key in constants.plot_type_enum:
data[key] = {}
data[self.plot] = {self.tag: {
'color': self.color,
'attributes': self.attributes,
'id': self.id,
'coordinates': self.coordinates,
'lat': self.lat,
'notes': self.notes}}
data['time'] = self.time_
data['hdfFile'] = self.hdf
logger.info('Converting unicode to ASCII')
return byteify(json.dumps(data))
и я использую sqlite 3.0. Причина, по которой большинство вещей - это строки, состоит в том, что большинство моих значений, которые должны быть сохранены в базе данных, отправляются как строки, поэтому сохранение является тривиальным. Мне интересно, должен ли я все это развить магия с функциями раньше, и просто иметь больше записей в базе данных? для таких вещей, как decimal time_begin, time_end, latitude_begin вместо строки, содержащей диапазон времени, который я анализирую, чтобы найти time_begin и time_end, когда я фильтрую
Ответы
Ответ 1
Я думаю, что вам обязательно нужно разобрать строки в столбцах, прежде чем хранить их в базах данных. Пусть база данных выполнит работу, для которой она была создана!
CREATE TABLE [coordinates]
(
id INTEGER NOT NULL PRIMARY KEY,
tag VARCHAR2(32),
color VARCHAR2(32) default 'green',
time_begin TIMESTAMP,
time_end TIMESTAMP,
latitude_begin INT
);
create index ix_coord_tag on coordinates(tag);
create index ix_coord_tm_beg on coordinates(time_begin);
insert into coordinates(tag, time_begin, time_end, latitude_begin)
values('tag1', '2006-06-01T07:56:17', '2006-06-01T07:56:19', 123);
insert into coordinates(tag, time_begin, time_end, latitude_begin)
values('tag1', '2016-01-01T11:35:01', '2016-01-01T12:00:00', 130);
insert into coordinates(tag, color, time_begin, time_end, latitude_begin)
values('tag2', 'blue', '2014-03-03T20:11:01', '2014-03-03T20:11:20', 2500);
insert into coordinates(tag, color, time_begin, time_end, latitude_begin)
values('tag2', 'blue', '2014-03-12T23:59:59', '2014-03-13T00:00:29', 2978);
insert into coordinates(tag, color, time_begin, time_end, latitude_begin)
values('tag3', 'red', '2016-01-01T11:35:01', '2016-01-01T12:00:00', 13000);
insert into coordinates(tag, color, time_begin, time_end, latitude_begin)
values('tag3', 'red', '2016-01-01T12:00:00', '2016-01-01T12:00:11', 13001);
.headers on
.mode column
select * from coordinates where tag='tag1' and '2006-06-01T07:56:18' between time_begin and time_end;
select * from coordinates where color='blue' and time_end between '2014-03-13T00:00:00' and '2014-03-13T00:10:00';
Вывод:
sqlite> select * from coordinates where tag='tag1' and '2006-06-01T07:56:18' between time_begin and time_end;
id tag color time_begin time_end latitude_begin
---------- ---------- ---------- ------------------- ------------------- --------------
1 tag1 green 2006-06-01T07:56:17 2006-06-01T07:56:19 123
sqlite>
sqlite> select * from coordinates where color='blue' and time_end between '2014-03-13T00:00:00' and '2014-03-13T00:10:00';
id tag color time_begin time_end latitude_begin
---------- ---------- ---------- ------------------- ------------------- --------------
4 tag2 blue 2014-03-12T23:59:59 2014-03-13T00:00:29 2978
Ответ 2
Учитывая заголовок вопроса, я предполагаю, что вы не используете метод like()
.
SQLAlchemy Query.filter()
принимает любые критерии, которые оцениваются как логические.
Почему бы не изменить критерий фильтра, чтобы вместо использования метода like()
в строке вы тестировали объекты Python datetime.date
?
Я не знаю, как выглядит obj.coordinates
, но вот грубая схема, которая, на мой взгляд, имеет смысл:
def check_range(coords, date):
""" takes a date, and a "coordinates" value (representing a date
range), and a date as inputs, returns True if the
date is within that date range, else returns False
"""
#some code here...
query_result = query_result.filter(
check_range(DatabaseShape.coordinates, date)
)