查找值与其他值不相交的条目

时间:2016-01-15 12:11:51

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

我遇到了在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', ',')))

2 个答案:

答案 0 :(得分:1)

好的,我想我理解了我遇到的问题。默认值为" blocked_dates"用户表是零。因此,查询无法计算重叠。我将blocked_dates的默认值更改为""而不是nil,NOT语句开始给我正确的值。

答案 1 :(得分:1)

您必须知道,只有WHERE子句表达式评估为TRUE符合条件。当用boolean反转NOT值时,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 < / strong>您的关系模型,其中一个单独的表列出了阻止日期,而不是列 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日期格式,顺便说一句。为什么呢?

相关: