AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 24518
Accepted
dezso
dezso
Asked: 2012-09-20 00:32:46 +0800 CST2012-09-20 00:32:46 +0800 CST 2012-09-20 00:32:46 +0800 CST

如何有条件地停止 psql 脚本(基于变量值)?

  • 772

让我们考虑以下示例(从 psql 脚本开始):

\c :db_to_run_on

TRUNCATE the_most_important_table;
-- tried to avoid similarities to anything that exists out there

现在,如果它是通过命令运行的

psql [connection details] -v db_to_run_on=\'dev_database\'

然后它就会运行并且用户很高兴。但是,如果他(她)决定指定-v db_to_run_on=production_database呢?(让我们假设这可能发生,就像人们偶尔跑步一样rm -rf / # don't try this at home!!!。)希望该表有一个新的备份......

那么问题来了:如何检查传递给脚本的变量并根据它们的值停止进一步处理?

postgresql psql
  • 6 6 个回答
  • 17461 Views

6 个回答

  • Voted
  1. dezso
    2012-09-26T00:00:22+08:002012-09-26T00:00:22+08:00

    有一个选项可以在psql出错时停止执行命令,这是ON_ERROR_STOP. 如果我们能以某种方式引发错误,这将做我们想要的。

    问题是我们必须测试变量并以某种方式产生错误。由于不能在psql(因为没有)* 中使用控制结构,我唯一的想法是使用 SQL 进行测试。好吧,有条件地产生错误pl/pgsql是非常擅长的,所以我写了一个会产生错误的函数。我现在可以从一个简单的CASE结构调用这个函数。一个简单的例子:

    -- let's assume for clarity that there is no function with this name in the database
    CREATE OR REPLACE FUNCTION error_generator()
    RETURNS boolean AS
    $body$
    BEGIN
        RAISE 'Meaningful error message here';
        RETURN FALSE; -- just for aesthetical purposes
    END;
    $body$
    LANGUAGE plpgsql;
    
    \set ON_ERROR_STOP on
    
    BEGIN;
    
    -- test for the variable value
    -- notice that if :var is not set, it fails as well (with a syntax error)
    SELECT CASE WHEN 1 = :var THEN error_generator() ELSE TRUE END;
    
    INSERT INTO test_table (integer_value, text_value)
    VALUES (:var, 'something');
    
    COMMIT;
    

    *:您可以在 shell 之后\!和条件句之后使用任何 shell 命令,但是由于\!打开了一个新的 shell,因此执行那里的任何内容对当前的 psql 脚本没有任何影响。

    • 17
  2. Best Answer
    Evan Carroll
    2017-04-07T13:20:50+08:002017-04-07T13:20:50+08:00

    PostgreSQL 10

    PostgreSQL 10 为 psql 带来了条件。这不再是一个问题。

    \if :db_to_run_on = 'dev_database'
      TRUNCATE the_most_important_table;
    \endif
    

    我想你也可以使用DO..

    \if :db_to_run_on != 'dev_database'
    do $$
      BEGIN
        RAISE 'Meaningful error message here';
      END;
    $$ LANGUAGE plpgsql;
    \endif
    
    • 8
  3. Steve Bennett
    2018-08-09T18:41:28+08:002018-08-09T18:41:28+08:00

    dezso 答案的更简洁版本:

    CREATE OR REPLACE FUNCTION pg_temp.err(msg varchar) RETURNS boolean     
    AS $$ BEGIN RAISE '%',msg; END; $$ LANGUAGE plpgsql;
    

    然后你可以这样称呼它:

    \set ON_ERROR_STOP on
    
    SELECT CASE WHEN (
      SELECT COUNT(*) FROM mytable
    ) > 0 THEN pg_temp.err('Already loaded') END;
    
    • 2
  4. François Beausoleil
    2012-09-20T17:03:36+08:002012-09-20T17:03:36+08:00

    我发现对我来说非常有效的是使用脚本语言生成一个 SQL 文件,然后我将其通过管道传输到 psql 中,如下所示:

    #!/usr/bin/env ruby
    
    raise "Not a good database name: #{ARGV.first.inspect}" unless ARGV.first =~ /^(dev|test)/
    
    puts "\\timing off"
    puts "set client_min_messages='warning';"
    puts
    puts "TRUNCATE the_most_important_table;"
    puts "-- more commands"
    

    然后,我从驱动程序脚本中调用它:

    #!/bin/bash
    /usr/bin/ruby generator ${1} | /usr/bin/psql --dbname=${1} --file=- --single-transaction
    

    我的驱动程序脚本通常是一个 Rake 文件,但你明白了。

    • 1
  5. tbussmann
    2022-01-18T13:24:48+08:002022-01-18T13:24:48+08:00

    要退出psql脚本,您可以简单地使用meta 命令或在激活\quit时生成错误。ON_ERROR_STOP区别在于:

    • \quit如果使用嵌套0脚本或\i
    • ON_ERROR_STOP在打开时产生错误将退出状态3并在嵌套脚本的情况下传播到顶级脚本。

    生成错误然后RAISE从函数或匿名代码块执行的更简单的替代方法是无效的 SQL 命令,例如:INVALID;.

    要输出错误消息,您可以使用\warn元命令将其发送到stderr(启动 pg13)或简单地\echo发送到stdout.

    结合\if(开始 pg10)我对 OP 问题的尝试将是:

    SELECT :'db_to_run_on' = 'production_database' AS forbidden \gset
    \if :forbidden
        \warn 'You better not do this!'
        \set ON_ERROR_STOP on
        INVALID COMMAND;
    \endif
    \unset forbidden
    
    \c :db_to_run_on
    TRUNCATE the_most_important_table;
    

    不幸的是,我不知道有一种方法可以抑制无效命令生成的“语法错误”输出。因此,根据您的用例组合\warn 'You better not do this!'and\quit或\set ON_ERROR_STOP onandDO $$BEGIN RAISE 'You better not do this!'; END$$ LANGUAGE plpgsql;可能更合适。

    • 0
  6. Qwertie
    2022-06-22T09:25:52+08:002022-06-22T09:25:52+08:00

    在查询脚本(我猜它与 psql 脚本有所不同)中,\if被认为是语法错误,但这样的代码对我有用:

    DO $$ BEGIN
        IF problematic_value = 'undesired thing' THEN
            RAISE EXCEPTION 'Aborting: % is no good', problematic_value;
        END IF;
    END $$;
    

    在 PostgreSQL 13.2 中测试。DO存储过程中不需要外部块。

    • 0

相关问题

  • 我可以在使用数据库后激活 PITR 吗?

  • 运行时间偏移延迟复制的最佳实践

  • 存储过程可以防止 SQL 注入吗?

  • PostgreSQL 中 UniProt 的生物序列

  • PostgreSQL 9.0 Replication 和 Slony-I 有什么区别?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何查看 Oracle 中的数据库列表?

    • 8 个回答
  • Marko Smith

    mysql innodb_buffer_pool_size 应该有多大?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    从 .frm 和 .ibd 文件恢复表?

    • 10 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    如何选择每组的第一行?

    • 6 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    pedrosanta 使用 psql 列出数据库权限 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST
  • Martin Hope
    bernd_k 什么时候应该使用唯一约束而不是唯一索引? 2011-01-05 02:32:27 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve