我遇到了在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', ',')))
答案 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日期格式,顺便说一句。为什么呢?
相关: