如何在 Rails 3 中使用自定义 SQL 查询检索 BOOLEANS Postgres?

发布于 2024-12-03 19:12:47 字数 2024 浏览 1 评论 0原文

在我的模型中,我做了这个自定义的 sql 查询:

SELECT
    training_courses.id,
    training_courses.training_id,
    training_courses.course_id,
    training_courses.is_pre_test, 
    training_courses.order_by,
    training_course_histories.id AS training_course_history_id, 
    training_course_histories.finished_at,
    training_course_histories.score,
    CAST(coalesce(user_training_courses.id, 0) as BOOLEAN) as purchased
FROM
    training_courses
    LEFT OUTER JOIN training_course_histories
        ON training_course_histories.training_course_id = training_courses.id AND training_course_histories.id = (
            SELECT th1.id
            FROM training_course_histories th1      
            WHERE th1.training_course_id = training_courses.id
              AND th1.finished_at IS NOT NULL
              AND th1.user_id = 1
            ORDER BY th1.finished_at DESC LIMIT 1
        )
    LEFT OUTER JOIN user_training_courses
        ON user_training_courses.training_course_id = training_courses.id AND user_training_courses.id = (
            SELECT th2.id
            FROM user_training_courses th2          
            WHERE th2.training_course_id = training_courses.id 
              AND th2.user_id = 1
        )
WHERE (training_courses.training_id = 1)
GROUP BY
    training_courses.id,
    training_courses.id,
    training_courses.training_id,
    training_courses.course_id,
    training_courses.is_pre_test, 
    training_courses.order_by,
    training_course_histories.id,
    training_course_histories.finished_at,
    training_course_histories.score, 
    user_training_courses.id
ORDER BY 
    order_by ASC, 
    id ASC, 
    training_courses.order_by ASC, 
    training_courses.id ASC

之前,我使用的是 Mysql 数据库,所以完全没有问题,查询就像:ISNULL(user_training_courses.id) as buy

但现在,我正在使用 Postgres,并且我必须购买 CAST(coalesce(user_training_courses.id, 0) as BOOLEAN)

问题:对于 Rails,购买 = 't' 或 'f'(字符串)

我想要什么:购买 = true 或 false(布尔值)

可能吗?

谢谢。

In my model I've made this custom sql query :

SELECT
    training_courses.id,
    training_courses.training_id,
    training_courses.course_id,
    training_courses.is_pre_test, 
    training_courses.order_by,
    training_course_histories.id AS training_course_history_id, 
    training_course_histories.finished_at,
    training_course_histories.score,
    CAST(coalesce(user_training_courses.id, 0) as BOOLEAN) as purchased
FROM
    training_courses
    LEFT OUTER JOIN training_course_histories
        ON training_course_histories.training_course_id = training_courses.id AND training_course_histories.id = (
            SELECT th1.id
            FROM training_course_histories th1      
            WHERE th1.training_course_id = training_courses.id
              AND th1.finished_at IS NOT NULL
              AND th1.user_id = 1
            ORDER BY th1.finished_at DESC LIMIT 1
        )
    LEFT OUTER JOIN user_training_courses
        ON user_training_courses.training_course_id = training_courses.id AND user_training_courses.id = (
            SELECT th2.id
            FROM user_training_courses th2          
            WHERE th2.training_course_id = training_courses.id 
              AND th2.user_id = 1
        )
WHERE (training_courses.training_id = 1)
GROUP BY
    training_courses.id,
    training_courses.id,
    training_courses.training_id,
    training_courses.course_id,
    training_courses.is_pre_test, 
    training_courses.order_by,
    training_course_histories.id,
    training_course_histories.finished_at,
    training_course_histories.score, 
    user_training_courses.id
ORDER BY 
    order_by ASC, 
    id ASC, 
    training_courses.order_by ASC, 
    training_courses.id ASC

Before, I was using a Mysql database so, no problem at all, the query was like : ISNULL(user_training_courses.id) as purchased

But now, I'm using Postgres and I must have CAST(coalesce(user_training_courses.id, 0) as BOOLEAN) as purchased

The problem: for Rails, purchased = 't' or 'f' (strings)

What I want : purchased = true or false (booleans)

Is it possible ?

Thx.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

隔岸观火 2024-12-10 19:12:47

最后,我宁愿在我的模型中有一个访问器来处理这种情况。

def purchased
  ![false, 'false', 'f', 'FALSE', 'F', 0, '0'].include?(self[:purchased])
end

Finally, I rather have an accessor in my model to handle this case.

def purchased
  ![false, 'false', 'f', 'FALSE', 'F', 0, '0'].include?(self[:purchased])
end
烈酒灼喉 2024-12-10 19:12:47

Rails PostgreSQL 驱动程序了解 PostgreSQL 布尔值以 't''f' 形式出现,并且通常会正确翻译它们。你的 CAST:

CAST(coalesce(user_training_courses.id, 0) as BOOLEAN)

也应该没问题:

psql=> select cast(11 as boolean), cast(1 as boolean), cast(0 as boolean);
 bool | bool | bool 
------+------+------
 t    | t    | f

所以我猜 Rails 只是不知道你的 CAST 的列类型。例如:

rails > ActiveRecord::Base.connection.select_rows('select cast(1 as boolean), 11 = 11')
 => [["t", "t"]]

您可以使用 ActiveRecord::ConnectionAdapters::Column 中的 Set 常量自行将 't''f' 转换为布尔值:

TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE'].to_set
FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE'].to_set

或者您可以使用 ActiveRecord::ConnectionAdapters::Column.value_to_boolean

rails > ActiveRecord::Base.connection.select_rows('select cast(1 as boolean), 11 = 11').map { |r| r.map { |b| ActiveRecord::ConnectionAdapters::Column.value_to_boolean(b) } }
 => [[true, true]] 

但是您仍然必须知道所有列的类型,并手动排序,如果您'我们将使用低级 SQL 接口。类似的问题也适用于整数、日期和您返回的任何其他非字符串类型。

The Rails PostgreSQL driver understands that PostgreSQL booleans come out as 't' and 'f' and usually translates them properly. Your CAST:

CAST(coalesce(user_training_courses.id, 0) as BOOLEAN)

should also be fine:

psql=> select cast(11 as boolean), cast(1 as boolean), cast(0 as boolean);
 bool | bool | bool 
------+------+------
 t    | t    | f

So I'd guess that Rails just doesn't know the column type of your CAST. For example:

rails > ActiveRecord::Base.connection.select_rows('select cast(1 as boolean), 11 = 11')
 => [["t", "t"]]

You can convert the 't' and 'f' to booleans yourself using the Set constants in ActiveRecord::ConnectionAdapters::Column:

TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE'].to_set
FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE'].to_set

or you can use ActiveRecord::ConnectionAdapters::Column.value_to_boolean:

rails > ActiveRecord::Base.connection.select_rows('select cast(1 as boolean), 11 = 11').map { |r| r.map { |b| ActiveRecord::ConnectionAdapters::Column.value_to_boolean(b) } }
 => [[true, true]] 

But you'll still have to know what types all your columns are and sort things out by hand if you're going to use the low level SQL interface. Similar issues apply to integers, dates, and any other non-string types that you get back.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文