【问题标题】:Find entry where value does not intersect with other value查找值不与其他值相交的条目
【发布时间】:2016-01-15 12:11:51
【问题描述】:

我在 Ruby on Rails 中进行 ActiveRecord 查询时遇到问题,该查询将返回所有用户,其blocked_dates(自动生成的字符串值)与给定事件的formatted_dates(自动生成的字符串值)不相交。 我遇到的问题是,例如:

User.where.not("string_to_array(blocked_dates, ',') && string_to_array(?, ',')", "26.12.2015")

返回一个空列表,其中:

User.where("string_to_array(blocked_dates, ',') && string_to_array(?, ',')", "26.12.2015")

返回blocked_dates 实际上包含“26.12.2015”的正确用户。

这种奇怪的行为有什么原因吗?或者 Postgres 重叠运算符 && 不能与 NOT 一起使用?

如果出现问题,这里是生成的 SQL 查询:

SELECT "users".* FROM "users"  WHERE (NOT (string_to_array(blocked_dates, ',') && string_to_array('26.12.2015', ',')))

【问题讨论】:

  • 嗨,您是否尝试使用 AND 而不是 && ?我希望这适用于AND
  • PG::DatatypeMismatch: 错误:AND 的参数必须是布尔类型,而不是文本类型[]
  • 日期似乎是标量类型,恕我直言,无需将其转换为数组。 (顺便说一句:为什么是 german 日期格式?)
  • 因为应用程序要求将日期像这样放在其他组件中,但是由于该字段是自动生成的,所以我可以将它们放在我想要的任何格式中。

标签: sql ruby-on-rails database postgresql activerecord


【解决方案1】:

好的,我想我理解了我遇到的问题。 users 表的“blocked_dates”的默认值为 nil。因此,查询无法计算重叠。在我将blocked_dates 的默认值更改为“”而不是nil 后,NOT 语句开始为我提供正确的值。

【讨论】:

    【解决方案2】:

    您必须注意,只有 WHERE 子句表达式的计算结果为 TRUE 才符合条件。当用NOT 反转boolean 值时,NULL 保持为NULL 并且仍然不合格。你可以使用NULL-safe constructs 喜欢:

    WHERE  (string_to_array(blocked_dates, ',')
         @> string_to_array('26.12.2015', ',')) IS NOT TRUE
    

    (顺便说一句,使用更简单的contains operator @> 来测试单个日期的案例。)

    或者:

    WHERE  (blocked_dates IS NULL OR
            NOT (string_to_array(blocked_dates, ',') @> string_to_array('26.12.2015', ','))
    

    或者,在处理你笨拙的字符串时:

    WHERE  (blocked_dates LIKE '%26.12.2015%') IS NOT TRUE
    

    但所有这些都是在猪身上涂口红,所有的构造都容易出错,并且依赖于(希望)匹配的日期格式。为什么首先要进行字符串到数组的转换? blocked_dates 列至少应该是一个日期数组 (date[]),或者更好的是,normalize 你的关系模型使用单独的表格列出阻止日期而不是列 users.blocked_dates:

    CREATE TABLE user_blocked_date (
      user_id int REFERENCES users(user_id) ON DELETE CASCADE ON UPDATE CASCADE
    , blocked_date date
    , PRIMARY KEY (user_id, blocked_date)
    );
    

    根据数据分布,这可能会也可能不会占用更多磁盘空间。但是使用以下标准技术之一,您的查询会快得多

    SELECT *
    FROM   users u
    WHERE  NOT EXISTS (
       SELECT 1
       FROM   user_blocked_date
       WHERE  user_id = u.user_id
       AND    blocked_date = '2015-12-26';
    

    使用 ISO 8601 日期格式,顺便说一句。为什么?

    相关:

    【讨论】:

    • 我首先想到的是创建一个单独的表blocked_dates,其中包含正常日期格式的日期和user_id 外键。问题仍然是,考虑到我有这个表,我该怎么做才能有一个正常的 where 查询来过滤用户集合,不包括那些通过这个表链接到他们的特定日期的用户。您发布的查询应该在给定日期的情况下工作,但我不确定我是否可以使用这种方法仅过滤那些没有关联给定日期的blocked_date条目的用户。
    • 为了清楚起见,我的对象模型中有一个用户、一个事件和一个事件日。事件发生时有多个日期,用户有多个他应该能够阻止的日期。这个想法是能够过滤那些没有明确阻止日期 X[] 的用户(无论选择什么输入格式,对象都存储为标准 Postgres 日期),这样我就可以过滤那些可以显示特定日期的用户事件,以及对于用户,能够仅显示日期未被用户阻止的那些事件。可以使用数据库表或 date[] 来完成。
    • @VitalyStanchits:有趣的问题。必须非常清楚要测试什么(用户有任何事件日期被阻止?或所有事件日期被阻止?等等)。我建议您开始一个新问题,您还可以在其中提供确切的表定义、Postgres 版本和每个表的基数。
    • 好的,我能做到。 stackoverflow.com/questions/34821327/…
    • @VitalyStanchits:但你没有。我所要求的所有基本信息都不存在。
    猜你喜欢
    • 2020-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-08
    • 2022-11-15
    • 1970-01-01
    • 2022-09-27
    相关资源
    最近更新 更多