我刚接触PostgreSQL(目前在PostgreSQL13上),可能与我遇到的其他SQL(Microsoft SQL)有些混淆.

其目标是断言表列中没有会被截断的值,然后减小列长度并对相关函数的返回类型执行相同的操作

代码提供错误的示例,以便可以重现:

/* 
 CREATE TABLE test_table (id uuid, col_a varchar(100), col_b int); 
 INSERT INTO test_table VALUES (gen_random_uuid(), 'asdf', 1);
 **/

DO $$
BEGIN
    IF NOT EXISTS (SELECT * FROM test_table WHERE character_length(col_a) > 100) THEN
        ALTER TABLE test_table ALTER COLUMN col_a TYPE varchar(100);
        
        DROP FUNCTION IF EXISTS test_function(varchar(100));
    
        CREATE OR REPLACE FUNCTION test_function(test_param varchar(100))
        RETURNS TABLE (
            id uuid,
            col_a varchar(100),
            col_b int
        )
        LANGUAGE plpgsql
        AS $$
        BEGIN
            RETURN QUERY
            SELECT test_table.id AS id, test_table.col_a AS col_a, test_table.col_b AS col_b
            FROM test_table
            WHERE test_table.col_a = test_param;
        END;
        $$;
    ELSE
        RAISE NOTICE 'Cannot Revert. Rows exist that would be truncated!';
    END IF;
END $$

SELECT id, col_a, col_b FROM test_function ('asdf');

/* DROP TABLE test_table */

我得到的错误是:

Sql错误[42601]:错误:在"Begin"位置或其附近出现语法错误:400

我已经try 了动态代码,我已经自己运行了Function语句--正常运行的健全性判断;事实上,在没有IF块的情况下,同时运行或单独运行每条语句也很好.

我的方法有什么问题,如何修复?

推荐答案

错误的直接原因是不正确的美元报价.这将会奏效:

DO
$do$
BEGIN
   IF NOT EXISTS (SELECT * FROM test_table WHERE character_length(col_a) > 100) THEN
      ALTER TABLE test_table ALTER COLUMN col_a TYPE varchar(100);

      DROP FUNCTION IF EXISTS test_function(varchar(100));

      CREATE OR REPLACE FUNCTION test_function(test_param varchar(100))
        RETURNS TABLE (
         id uuid,
         col_a varchar(100),
         col_b int
        )
      LANGUAGE plpgsql AS
      $func$
      BEGIN
         RETURN QUERY
         SELECT test_table.id, test_table.col_a, test_table.col_b
         FROM   test_table
         WHERE  test_table.col_a = test_param;
      END
      $func$;
   ELSE
      RAISE NOTICE 'Cannot Revert. Rows exist that would be truncated!';
   END IF;
END
$do$;

请参见:

But I wouldn't do most of what you are doing there to begin with. Use the data type text in table and function and be done with it. 请参见:

如果您确实需要对最大字符数进行限制,仍然可以考虑text并添加CHECK个限制.

ALTER TABLE test_table ADD CONSTRAINT test_table_col_a_maxlen_200 CHECK (length(col_a) < 201);

然后,如果以后要更改该约束,只需执行以下操作:

ALTER TABLE test_table
  DROP CONSTRAINT test_table_col_a_maxlen_200  -- or whatever it was
, ADD  CONSTRAINT test_table_col_a_maxlen_100 CHECK (length(col_a) < 101);

Postgres将自动为您验证CHECK约束,如果有任何行违反该约束,则会失败并返回错误:

错误:某行违反了关系"test_table"的判断约束"test_table_ol_a_Maxlen_100"

In fairness,在现代的Postgres中,您也可以将更改应用到varchar(n).如果有任何现有行太长,它将进行判断并失败:

错误:类型字符变化的值太长(100)

因此,即使你坚持varchar(n)个,你也可以简化事情.

Postgresql相关问答推荐

PostgreSQL:`row_alias为null`且`row_alias不是null`返回值不一致

如何在查询空字段时设置pgtype.comb为默认值?

如何获取实例化视图的列级权限?

我可以使用 SQLAlchemy 映射数据类创建 Postgres `GENERATED ALWAYS AS` 列吗?

IF 块中的 CREATE FUNCTION 语句抛出错误,同时运行它自己的作品

将数组的所有元素循环到jsonb中并修改值

需要用 jack/pgx 更新 golang 中复合类型的 PSQL 行

TimescaleDB 连续聚合:如何存储连续聚合结果

当我写 SELECT ~1;在 Postgresql 上它给了我 -2 结果.这是什么原因?它一直持续〜4和-5等

如何在 PostgreSQL hstore 中使用通配符查询值

消除 PostgreSQL SELECT 语句中的重复行

PostgreSQL:是否可以将枚举转换为整数?

UPDATE implies move across partitions

PostgreSQL INSERT 插入一个枚举数组

在 Spring Boot 上使用 Hibernate 映射 PostGIS 几何点字段

如何判断每个组中是否存在值

从time without time zone和时区名称中获取time with time zone

PostgreSQL 获取过go 12 小时的元素

Postgresql 中的 NOT EXISTS 子句

在 PostgreSQL 中使用 CASE 一次影响多个列