Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Sqlalchemy:使用两个数组类型列的筛选操作_Python_Arrays_Sqlalchemy - Fatal编程技术网

Python Sqlalchemy:使用两个数组类型列的筛选操作

Python Sqlalchemy:使用两个数组类型列的筛选操作,python,arrays,sqlalchemy,Python,Arrays,Sqlalchemy,我有两个类:问题和用户。问题类有一个名为category\u id的字段,类型为Column(数组(整数)),而用户类有一个名为preferences的对象,该对象有一个名为ignored\u categories的字段,类型也为Column(数组(整数)) 我试图从用户的首选项中查询出现在忽略的\u类别字段中的类别ID字段中至少没有一个值的所有问题,或者如果前面的值为真,在category\u id字段中有用户首选项字段ignore\u categories之外的任何其他值。因此,以下情况应该

我有两个类:问题和用户。问题类有一个名为
category\u id
的字段,类型为
Column(数组(整数))
,而用户类有一个名为
preferences
的对象,该对象有一个名为
ignored\u categories
的字段,类型也为
Column(数组(整数))

我试图从用户的首选项中查询出现在
忽略的\u类别
字段中的
类别ID
字段中至少没有一个值的所有问题,或者如果前面的值为真,在
category\u id
字段中有用户首选项字段
ignore\u categories
之外的任何其他值。因此,以下情况应该是正确的:

  • category\u id
    =[]和
    ignored\u categories
    =[1,2,3]=>应该通过
  • category\u id
    =[1,2,4]和
    ignored\u categories
    =[1,2,3]=>应该通过
  • category\u id
    =[1]和
    ignored\u categories
    =[1,2,3]=>应该忽略
  • category_id
    =[1,2,3]和
    忽略的_分类
    =[1,2,3]=>应该忽略
  • category\u id
    =[1,2,3,4]和
    ignored\u categories
    =[1,2,3]=>应该通过
  • category\u id
    =[5,7]和
    ignored\u categories
    =[1,2,3]=>应该通过
这就是我到目前为止的想法:

user = DBSession.query(User).filter_by(id=user_id).one() # this gets the user object
query = DBSession.query(Question).order_by(Question.created_at.desc())
query = query.filter(
    or_(
        not_(
            Question.category_ids.overlap(user.preferences.ignored_categories)
        ),
        Question.category_ids.contains(user.preferences.ignored_categories)
    )
)
这方面的问题是,如果
类别ID
忽略的类别
的超集,则
仅包含
测试,这无法为以下数据集提供正确的结果:

  • category\u id
    =[1]和
    ignored\u categories
    =[1,2,3]=>应该忽略
因此,它需要另一个条件来测试是否至少有一个值匹配,而没有其他值不匹配

overlap
功能仅测试两个数组中是否至少存在一个值,但这会使测试失败,例如:

  • category\u id
    =[1,2,4]和
    ignored\u categories
    =[1,2,3]=>应该通过
它应该通过,但它没有,因为我需要否定这个操作。如果我不否定它,它只会过滤那些完全没有共同点的数组

编辑:这是我的表格的外观:

class User(Base, DictSerializable):
    __tablename__ = 'users'
    __table_args__ = dict(schema='user')

    id = Column(types.Id, primary_key=True)
    # other fields


class UserPreferences(Base, DictSerializable):
    __tablename__ = 'user_preferences'
    __table_args__ = dict(schema='user')

    id = Column(types.Id, primary_key=True)
    user_id = Column(types.Id, ForeignKey(User.id))
    ignored_categories = Column(types.ARRAY(types.Number), default=[])
    # other fields

    user = relationship("User",
                        backref=backref("preferences", single_parent=True, cascade="all, delete-orphan",
                                        passive_deletes=True, uselist=False),
                        )

class Question(Base, DictSerializable):
    __tablename__ = 'questions'
    __table_args__ = dict(schema='question')

    id = Column(types.Id, primary_key=True)
    user_id = Column(types.Id, ForeignKey(User.id, ondelete="CASCADE", onupdate="CASCADE"))

    # other fields

    category_ids = Column(types.ARRAY(types.Integer))

    user = relationship("User", foreign_keys=user_id,
                        backref=backref("questions", order_by=id, single_parent=True, uselist=True,
                                        cascade="all, delete-orphan", passive_deletes=True)
                        )


question_categories = Table('question_categories', Base.metadata, 
    Column('question_id', types.Integer, ForeignKey(Question.id)), 
    Column('category_id', types.Integer, ForeignKey(Category.id)) )
Question.categories = relationship(Category, secondary=question_categories, backref=backref('questions'))

这个问题相当于在
category\u id
中找到一个元素,该元素在
ignored\u categories
中不存在,在特殊情况下,如果
category\u id
为空,则不会忽略该元素

这可以通过连接表实现,如下所示:

SELECT DISTINCT questions.*
FROM questions
LEFT JOIN question_categories ON questions.id = question_categories.question_id
WHERE (
  question_categories.category_id IS NULL  -- special case where question has no categories
  OR question_categories.category_id NOT IN (
    SELECT category_id FROM user_ignored_categories WHERE user_id = 123  -- for this user
  )  -- find a category that isn't ignored
)
要对阵列执行此操作,可以执行以下操作:

SELECT questions.*
FROM questions
WHERE (
  cardinality(categories) = 0  -- special case where question has no categories
  OR NOT ((SELECT ignored_categories FROM users WHERE id = 123) @> categories)
);

您可以根据您的数据测试这些设置。

您需要的是设置差异操作。不能使用交集(“重叠”)和子集(“包含”)模拟集差异。如何实现设置差异取决于您的数据库。由于这个原因,数组通常被认为不如联接表灵活。@univerio我用表结构更新了这个问题。你能给我推荐一下我使用联接静默的方式吗?我所说的“联接表”是指
创建表问题\类别(问题\ id int,类别\ id int,主键(问题\ id,类别\ id)
。对于你的特定情况,你可能可以忽略
忽略\类别。包含(类别\ id)
,说明了
类别ID
为空的情况。您使用的数据库是什么?我怀疑Postgresql使用了架构和数组,如果是这样的话,@univerio这样的表已经存在。我已经用它更新了问题(
问题类别
)。我需要
category\u id
列,以便更快地访问类别,而不必将所有类别作为对象数组发送。但我仍然无法看到如何使用该表筛选我想要的问题。