【问题标题】:Pretty Print SQL in RubyRuby 中的漂亮打印 SQL
【发布时间】:2012-05-08 00:43:36
【问题描述】:

有没有一种简单的方法可以在 (rails 3) 控制台中pretty print随机 SQL?

类似于awesome_print,甚至可能是Pretty Print。

它不必了解所有可能的方言或超级高级。
我真正想要的只是更轻松地检查 ActiveRecord 生成的 SQL。

目前我只是将 SQL 复制到网上进行格式化,这显然是生产力杀手。

我真的很想query.to_sql.pretty_format_sql 看看更好的输出。

谢谢。

【问题讨论】:

  • 如果您使用的是 JRuby,您可以考虑为 Java 提出的 similar question 的一些答案,例如 Hibernate 的 org.hibernate.jdbc.util.BasicFormatterImpl

标签: sql ruby-on-rails ruby pretty-print


【解决方案1】:

试试这个:

git clone https://github.com/sonota/anbt-sql-formatter
cd anbt-sql-formatter
rails setup.rb

然后,在 Rails 初始化器中:

# config/initializers/pretty_format_sql.rb
class String
  def pretty_format_sql
    require "anbt-sql-formatter/formatter"
    rule = AnbtSql::Rule.new
    rule.keyword = AnbtSql::Rule::KEYWORD_UPPER_CASE
    %w(count sum substr date).each{|func_name|
      rule.function_names << func_name.upcase
    }
    rule.indent_string = "    "
    formatter = AnbtSql::Formatter.new(rule)
    formatter.format(self)
  end
end

测试:

rails console
# Some complex SQL
puts Recipe.joins(:festivity).where(['? BETWEEN festivities.starts_at AND festivities.ends_at', Time.utc(0,Time.now.month,Time.now.day,12,0,0)]).to_sql.pretty_format_sql
SELECT
        "recipes" . *
    FROM
        "recipes" INNER JOIN "festivities"
            ON "festivities" . "id" = "recipes" . "festivity_id"
    WHERE
        (
            '0000-04-27 12:00:00.000000' BETWEEN festivities.starts_at AND festivities.ends_at
        )
 => nil 

我把改进留给你(重构:猴子补丁 -> 模块,自定义格式等 :-))

【讨论】:

  • 它应该可以完成这项工作,但我真的想避免使用已弃用的 rails 插件(非 gems)。
  • 我也觉得它不是一个那么“标准”的库......但提取好的部分并将它们变成宝石应该不难(我测试了它,它工作得很好好吧,看到我找不到替代品,为什么要重写工作的东西?)...我会尝试!
【解决方案2】:

first answer 的anbt-sql-formatter 是available as a gem,你可以用:

gem install anbt-sql-formatter

这里是一个用法示例:

require "anbt-sql-formatter/formatter"
rule = AnbtSql::Rule.new
  formatter = AnbtSql::Formatter.new(rule)

[
"SELECT `col1`, `col2` FROM `table` WHERE ((`col1` = 1) AND (`col2` = 5))",
"SELECT `col1`, `col2` FROM `table` WHERE (`col1` = 1) AND (`col2` = 5)",
"SELECT `col1` FROM `table` WHERE (`col1` IN (SELECT * FROM `table21` WHERE (`col2` = 5)))",
"SELECT `col1` FROM `table` INNER JOIN `tab2` ON (`tab1`.`id` = `tab2`.`id1`) WHERE ((`id` >= 1) AND (`id` <= 5))",
].each{|sql_cmd| 
  puts "======"
  puts sql_cmd
  puts formatter.format(sql_cmd)
}

结果:

======
SELECT `col1`, `col2` FROM `table` WHERE ((`col1` = 1) AND (`col2` = 5))
SELECT
        `col1`
        ,`col2`
    FROM
        `table`
    WHERE
        (
            (
                `col1` = 1
            )
            AND (
                `col2` = 5
            )
        )
======
SELECT `col1`, `col2` FROM `table` WHERE (`col1` = 1) AND (`col2` = 5)
SELECT
        `col1`
        ,`col2`
    FROM
        `table`
    WHERE
        (
            `col1` = 1
        )
        AND (
            `col2` = 5
        )
======
SELECT `col1` FROM `table` WHERE (`col1` IN (SELECT * FROM `table21` WHERE (`col2` = 5)))
SELECT
        `col1`
    FROM
        `table`
    WHERE
        (
            `col1` IN (
                SELECT
                        *
                    FROM
                        `table21`
                    WHERE
                        (
                            `col2` = 5
                        )
            )
        )
======
SELECT `col1` FROM `table` INNER JOIN `tab2` ON (`tab1`.`id` = `tab2`.`id1`) WHERE ((`id` >= 1) AND (`id` <= 5))
SELECT
        `col1`
    FROM
        `table` INNER JOIN `tab2`
            ON (
            `tab1`.`id` = `tab2`.`id1`
        )
    WHERE
        (
            (
                `id` >= 1
            )
            AND (
                `id` <= 5
            )
        )

还有扩展规则的可能性,例如

# User defined additional functions:
%w(count sum substr date coalesce).each{|func_name|
  rule.function_names << func_name.upcase
}

【讨论】:

    【解决方案3】:

    六年后,这里有另一个选择:https://github.com/kvokka/pp_sql

    “用 anbt-sql-formatter gem 替换标准的 ActiveRecord#to_sql 方法,以便在控制台中输出漂亮的 SQL 代码。Rails 日志也将被格式化。”

    在底层使用 anbt-sql-formatter,但将其设为 .to_sql 的默认行为

    【讨论】:

      【解决方案4】:

      prettier-plugin-sql 的输出很好,例如

      SELECT
        DISTINCT "events".*
      FROM
        "events"
        INNER JOIN "approvals" ON "approvals"."event_id" = "events"."id"
        LEFT OUTER JOIN "attendances" ON "attendances"."event_id" = "events"."id"
      WHERE
        (
          "approvals"."status" = ?
          OR "events"."user_id" = ?
        )
        AND (
          "attendances"."user_id" = ?
          OR "events"."user_id" = ?
        )
      

      如果你在做puts Event.something.to_sql之后复制你的sql查询,你可以这样做:

      pbpaste | prettier --parser sql
      

      【讨论】:

        猜你喜欢
        • 2011-03-23
        • 2011-01-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-29
        • 1970-01-01
        • 1970-01-01
        • 2021-06-22
        相关资源
        最近更新 更多