【问题标题】:Apply function to column before filtering过滤前将函数应用于列
【发布时间】:2016-04-10 05:26:09
【问题描述】:

我的数据库中有一个名为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 函数,但问题仍然存在。


编辑:这是我的数据库类

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。大多数东西背后都是字符串的原因是因为我要存储在数据库中的大多数值都是作为字符串发送的,所以存储是微不足道的。我想知道我是否应该使用 before 函数来完成所有这些解析魔法,并且只拥有更多的数据库条目?对于像十进制 time_begintime_endlatitude_begin 这样的东西,而不是包含我解析的 time 范围的字符串在过滤时找到 time_begintime_end

【问题讨论】:

  • 我认为最好的方法是将坐标作为类并将其作为数据库的元素,在那里您可以在坐标上添加所需的方法,而无需调用像 DatabaseShape.coordinates.get_shape_range 这样的更改数据库跨度>
  • @Eliethesaiyan ,如果我将一个类作为我数据库的一个元素,我可以做类似DatabaseShape.coordinates.get_shape_range.like('date')?但是在我的情况下 get_shape_range 不会返回一个字符串,所以你不能只使用 .like 吗?
  • 您使用的是哪个数据库? coordinates的内容是什么样的,是字符串吗?
  • 您正在尝试完成数据库的工作 - 过滤“query_result”。我会让数据库为你做这件事。在数据库端进行过滤。你用的是什么类型的数据库?你能对表格结构有所了解吗?使用适当的数据模型会相当容易。
  • "大多数东西背后都是字符串的原因是因为我要存储在数据库中的大多数值都是作为字符串发送的,所以存储是微不足道的。"正如您所发现的那样,考虑如何为分析目的构建数据并非易事。

标签: python python-2.7 sqlalchemy


【解决方案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() 将接受任何计算结果为布尔值的条件。

    为什么不修改您的过滤条件,以便在 Python 上测试 datetime.date 对象而不是对字符串使用 like() 方法?

    我不知道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)
        )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多