当查询时需要判断查询对象中很多字段但是又不需要判断全部字段为空

本文介绍了一种利用反射机制实现的参数校验工具类,能够自动检查对象中被标记为必填的字段是否为空,并提供了自定义注解来排除不需要校验的字段。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先写个根据反射获取注解再判断的工具类

/**
 * 校验对象内 参数是否为空 工具类
 */
public class CheckParamUtils {

    public static String checkParam(Object obj){
        List<String> arrayList = new ArrayList();
        StringBuffer stringBuffer = new StringBuffer();
        try {
            for (Field f : obj.getClass().getDeclaredFields()) {
                f.setAccessible(true);
                if (f.getAnnotation(IgnoreParam.class)!=null){
                    continue;
                }
                Object o = f.get(obj);
                if (f.get(obj)==null){
                    arrayList.add(f.getName());
                }
//                else{
//                    //如果需要判断空字符串
//                    if (StringUtils.isBlank(String.valueOf(obj))){
//                        arrayList.add(f.getName());
//                    }
//                }
            }
            //拼接返回信息
            for (String param : arrayList) {
                stringBuffer.append("参数"+param+"缺失;");
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return stringBuffer.toString();
    }
}
注解类

/**
 * 实体对象内字段有此注解则不判断该字段是否为空
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD})
public @interface IgnoreParam {
}
在实体对象中的字段上加上该注解 不会判断该字段为空与否


如果谁有更好的方法  请告诉我


<think>我们面对的是一个关于Kingbase8数据库的问题:查询所有表中字段定义为非(NOT NULL)但实际上数据全为的表和字段信息。 根据引用[2]:统计信息中记录了列的信息,包括列上的值。但统计信息可能是实更新的,所以我们能完全依赖统计信息。 我们需要查询数据字典(系统表)来获取表结构信息(字段是否非),然后通过查询数据来验证这些非字段是否实际为。 步骤: 1. 查询所有用户表(排除系统表)。 2. 对于每个表,查询其所有定义为非(NOT NULL)的字段。 3. 对于每个这样的字段,检查表中该字段是否全部为NULL(即值)。注意:因为字段定义为非,所以理论上应该有NULL,但可能存在数据一致的情况。 然而,注意引用[4]中提到的模式(schema)问题,Kingbase中表可能位于同的模式下,所以我们需要考虑模式。 具体步骤: 1. 查询所有用户表(指定模式,比如public模式,或者所有用户模式): SELECT schemaname, tablename FROM sys_catalog.sys_tables WHERE ... (需要过滤系统表) 但Kingbase基于PostgreSQL,所以我们可以参考PostgreSQL的系统表。在Kingbase中,通常使用`sys_class`、`sys_attribute`等系统表(类似于pg_class, pg_attribute)。 然而,根据引用[2]和[4],Kingbase的系统表结构可能与PostgreSQL类似。我们可以这样: - 获取所有用户表:从`sys_tables`(或`sys_class`,其中relkind='r'表示普通表)中获取。 - 获取字段信息:从`sys_attribute`和`sys_constraint`(用于非约束)?或者更直接的是,我们可以通过`information_schema.columns`视图(Kingbase也支持)来获取。 考虑到兼容性和可读性,使用`information_schema`可能更标准。 在`information_schema.columns`视图中,有一个列`is_nullable`,如果为'NO',则表示该列允许为(即NOT NULL约束)。 因此,我们可以先获取所有允许为的列: 查询1:获取所有用户表的允许为的列 SELECT table_schema, table_name, column_name FROM information_schema.columns WHERE table_schema NOT IN ('sys_catalog', 'pg_catalog', 'information_schema') -- 排除系统模式 AND is_nullable = 'NO' 但是,这里有一个问题:Kingbase中可能还有其他系统模式?根据引用[4],我们看到有test=#,以及模式名为user1(后改为schema1)等。所以我们需要排除已知的系统模式。 2. 然后,对于上面查询得到的每一列,我们需要执行一个查询:检查该表中该列是否全部为NULL(即值)。如果全部为NULL,则说明违反了非约束(数据为)。 注意:由于表可能很大,逐个查询可能会很慢,但这是必要的。 我们可以动态生成SQL语句来检查每个字段。例如,对于表`sch.tbl`和字段`col`,执行: SELECT COUNT(*) FROM sch.tbl WHERE col IS NOT NULL 如果这个计数为0,则说明该列所有值都是NULL(或者表为,但表为,非字段也应该没有数据,所以也是违反的?因为非字段要求至少有一个非值,但表为,没有行,所以没有值,这并违反非约束?) 因此,我们需要区分: - 表为:那么非字段没有值,这并违反非约束(因为非约束是在插入数据检查的,表没有插入任何数据,所以没有违反)。 - 表,但该列所有值都是NULL:这违反了非约束。 所以,我们仅要检查该列是否全为NULL,还要检查表是否为。但是,如果表为,我们就需要报告了,因为非约束没有被违反。 因此,检查条件应该是:表且该列所有值都是NULL。 所以,对于每个表,我们检查两个条件: a. 表中有数据(行数>0) b. 该列的值全部为NULL(即该列中非NULL的个数为0) 因此,我们可以这样写: SELECT 1 FROM sch.tbl HAVING COUNT(*) > 0 AND COUNT(col) = 0 解释:COUNT(col) 统计非NULL值的数量。如果为0,且COUNT(*)>0(表示表中有行),则说明该列在每一行都是NULL。 3. 将步骤1和步骤2结合起来,我们可以使用动态SQL(因为要遍历所有表),在Kingbase中,我们可以使用PL/SQL(类似于PL/pgSQL)来编写存储过程。 但是,用户可能只需要一个查询语句?我们可以尝试用一条SQL语句,但可能需要使用集合操作或者CTE递归,这样可能很复杂,而且效率可能高。 因此,我们选择编写一个存储过程来生成报告。 由于用户要求的是查询,我们可以提供两种方式: - 方式1:编写一个存储过程,返回所有满足条件的表名和字段名。 - 方式2:生成一个包含多个查询的脚本,用户执行后可以逐个检查。 这里,我们采用方式1:存储过程。 注意:引用[5]中出现了错误,提示我们注意函数的使用(如json_array_length)需要正确类型。所以我们在动态SQL中要确保表名和列名的正确引用。 存储过程思路: - 创建一个临表来存储结果(模式名,表名,列名)。 - 遍历步骤1中查询到的每一个非列。 - 对于每个非列,构建一个动态SQL语句,检查该列是否全为NULL(且表)。 - 如果满足条件,则将信息插入临表。 - 返回临表的内容。 但是,由于Kingbase的PL/SQL语法与Oracle或PostgreSQL类似,我们参考PostgreSQL的语法。 由于存储过程编写相对复杂,且用户可能只需要一次性的查询,我们可以提供一个生成动态SQL查询语句的脚本,然后让用户执行这些语句来查看结果。 为了简化,我们也可以生成一个包含多个SELECT语句的脚本,每个SELECT语句检查一个字段,然后使用UNION ALL将所有结果合并。但是,由于字段可能很多,生成的SQL可能很长。 我们选择生成一个脚本,该脚本会生成一系列检查语句,并将结果插入到临表中,最后查询表。 步骤: 1. 创建一个临表来存储结果(schema_name, table_name, column_name)。 2. 使用游标遍历所有非列。 3. 对于每个非列,执行动态SQL检查,如果满足条件(表且该列全为NULL),则插入临表。 4. 返回临表的内容。 但是,由于在Kingbase中执行动态SQL需要权限,并且存储过程可能需要创建,我们提供一个存储过程示例。 考虑到用户可能没有权限创建存储过程,我们可以提供一个生成动态SQL文本的查询,用户可以将生成的SQL文本复制出来执行。 因此,这里我们提供两种方案: 方案一:生成动态SQL文本(适用于想创建存储过程的用户) 生成一个包含多个SELECT语句的脚本,每个SELECT语句检查一个字段,并将结果UNION起来。但是,如果字段很多,这个脚本会很长。 方案二:编写一个存储过程(推荐,但需要用户有创建存储过程的权限) 我们先尝试方案一(生成动态SQL文本): 查询1:获取所有非列(表模式和表名以及列名),然后为每个非列生成一个查询片段: SELECT 'SELECT ''' || c.table_schema || ''' AS schema_name, ''' || c.table_name || ''' AS table_name, ''' || c.column_name || ''' AS column_name FROM ' || quote_ident(c.table_schema) || '.' || quote_ident(c.table_name) || ' HAVING COUNT(*) > 0 AND COUNT(' || quote_ident(c.column_name) || ') = 0' FROM information_schema.columns c WHERE c.table_schema NOT IN ('sys_catalog', 'pg_catalog', 'information_schema') AND c.is_nullable = 'NO' 注意:这里我们使用了quote_ident函数来避免表名或列名是关键字或包含特殊字符。 但是,这样生成的每个查询片段返回的是符合条件的表的一行(如果该字段且表非,则返回一行,否则返回)。然后我们把这些查询用UNION ALL连接起来。 所以,完整的生成脚本: SELECT string_agg( 'SELECT ''' || c.table_schema || ''' AS schema_name, ''' || c.table_name || ''' AS table_name, ''' || c.column_name || ''' AS column_name FROM ' || quote_ident(c.table_schema) || '.' || quote_ident(c.table_name) || ' HAVING COUNT(*) > 0 AND COUNT(' || quote_ident(c.column_name) || ') = 0', ' UNION ALL ' ) AS sql_statement FROM information_schema.columns c WHERE c.table_schema NOT IN ('sys_catalog', 'pg_catalog', 'information_schema') AND c.is_nullable = 'NO'; 但是,这样生成的字符串可能会很长(如果有很多非列),而且Kingbase的string_agg可能有长度限制。 因此,我们可以聚合,而是直接输出多个SQL语句,中间用UNION ALL连接,然后用户复制执行。 SELECT 'SELECT ''' || c.table_schema || ''' AS schema_name, ''' || c.table_name || ''' AS table_name, ''' || c.column_name || ''' AS column_name FROM ' || quote_ident(c.table_schema) || '.' || quote_ident(c.table_name) || ' HAVING COUNT(*) > 0 AND COUNT(' || quote_ident(c.column_name) || ') = 0 UNION ALL' FROM information_schema.columns c WHERE c.table_schema NOT IN ('sys_catalog', 'pg_catalog', 'information_schema') AND c.is_nullable = 'NO' 注意:最后会多一个UNION ALL,需要用户手动去掉最后一个UNION ALL,并加上分号。 但是,这样太友好。我们可以用以下方式避免: SELECT 'SELECT ''' || c.table_schema || ''' AS schema_name, ''' || c.table_name || ''' AS table_name, ''' || c.column_name || ''' AS column_name FROM ' || quote_ident(c.table_schema) || '.' || quote_ident(c.table_name) || ' HAVING COUNT(*) > 0 AND COUNT(' || quote_ident(c.column_name) || ') = 0' FROM information_schema.columns c WHERE c.table_schema NOT IN ('sys_catalog', 'pg_catalog', 'information_schema') AND c.is_nullable = 'NO'; 然后用户将每个查询用UNION ALL连接起来执行。 但是,如果表很大,执行这么多查询可能会很慢。 方案二:存储过程(推荐) 存储过程代码(Kingbase PL/SQL): 注意:Kingbase的PL/SQL语法与Oracle类似。 我们创建一个函数,返回一个包含(schema_name, table_name, column_name)的结果集。 步骤: 1. 创建一个临表(或者使用返回表)来存储结果。 2. 使用游标遍历所有非列。 3. 对于每个非列,构建动态查询,检查是否满足条件(表中有行且该列全为NULL)。 4. 如果满足,则插入结果表。 5. 返回结果。 具体代码: ```sql CREATE OR REPLACE FUNCTION find_not_null_columns_with_all_null() RETURNS TABLE (schema_name text, table_name text, column_name text) AS $$ DECLARE rec record; v_sql text; v_count integer; BEGIN -- 临需要,因为我们可以使用RETURN QUERY,但这里我们使用循环动态执行 FOR rec IN SELECT c.table_schema, c.table_name, c.column_name FROM information_schema.columns c WHERE c.table_schema NOT IN ('sys_catalog', 'pg_catalog', 'information_schema') AND c.is_nullable = 'NO' LOOP -- 构建动态SQL:检查表中是否有行,并且该列的非计数为0 v_sql := 'SELECT COUNT(*) FROM ' || quote_ident(rec.table_schema) || '.' || quote_ident(rec.table_name) || ' HAVING COUNT(*) > 0 AND COUNT(' || quote_ident(rec.column_name) || ') = 0'; -- 执行动态SQL,如果返回一行,则说明满足条件 EXECUTE v_sql INTO v_count; -- 注意:动态SQL返回的是满足条件的表的数量(即HAVING子句过滤后,如果满足条件则返回一行,否则返回) -- 所以如果v_count(即返回了一行),则说明该列有问题 IF v_count IS NOT NULL THEN schema_name := rec.table_schema; table_name := rec.table_name; column_name := rec.column_name; RETURN NEXT; END IF; END LOOP; END; $$ LANGUAGE plpgsql; ``` 注意:由于Kingbase可能使用同的过程语言,这里我们使用plpgsql(因为Kingbase兼容PostgreSQL)。 但是,引用[1]中出现了错误,可能涉及编码问题,所以用户需要注意数据库连接编码。另外,引用[3]提到人大金仓的依赖,说明用户可能是通过JDBC连接,所以存储过程需要在数据库中创建。 用户执行: SELECT * FROM find_not_null_columns_with_all_null(); 即可得到结果。 但是,注意:如果表非常大,动态执行COUNT(*)可能会慢。我们可以考虑只检查是否存在至少一行且该列全,而需要精确的行数,这样可以使用EXISTS: v_sql := 'SELECT 1 FROM ' || quote_ident(rec.table_schema) || '.' || quote_ident(rec.table_name) || ' WHERE ' || quote_ident(rec.column_name) || ' IS NOT NULL LIMIT 1'; -- 然后检查是否存在非值,如果没有非值,则说明全(但还要判断) -- 但是,这样需要两个查询:先判断表是否为,再判断该列是否有非值。 我们原来的方法(一个查询)效率已经相对较高,因为它只需要一次全表扫描(但COUNT(*)可能扫描整个表)。 优化:我们可以先判断表是否为,如果为,则跳过。因为违反非约束。 先判断表行数: v_sql1 := 'SELECT 1 FROM ' || quote_ident(rec.table_schema) || '.' || quote_ident(rec.table_name) || ' LIMIT 1'; EXECUTE v_sql1 INTO v_exists; IF v_exists IS NOT NULL THEN -- 表 -- 然后检查该列是否有非值 v_sql2 := 'SELECT 1 FROM ' || quote_ident(rec.table_schema) || '.' || quote_ident(rec.table_name) || ' WHERE ' || quote_ident(rec.column_name) || ' IS NOT NULL LIMIT 1'; EXECUTE v_sql2 INTO v_exists; -- 如果v_exists为,说明没有非值,即全为 IF v_exists IS NULL THEN -- 记录结果 END IF; END IF; 这样,如果表为,我们就跳过,避免第二次查询。而且,第一次查询只需要取一行,所以很快。 另外,在检查非,只要找到一行非值,就可以停止(LIMIT 1)。所以,如果表中有大量数据,但第一行该列就是非,那么就会很快返回。 因此,我们优化后的存储过程: ```sql CREATE OR REPLACE FUNCTION find_not_null_columns_with_all_null() RETURNS TABLE (schema_name text, table_name text, column_name text) AS $$ DECLARE rec record; v_exists integer; BEGIN FOR rec IN SELECT c.table_schema, c.table_name, c.column_name FROM information_schema.columns c WHERE c.table_schema NOT IN ('sys_catalog', 'pg_catalog', 'information_schema') AND c.is_nullable = 'NO' LOOP -- 检查表是否为 EXECUTE 'SELECT 1 FROM ' || quote_ident(rec.table_schema) || '.' || quote_ident(rec.table_name) || ' LIMIT 1' INTO v_exists; IF v_exists IS NOT NULL THEN -- 表 -- 检查该列是否有非值(只要有一行非,就跳过) EXECUTE 'SELECT 1 FROM ' || quote_ident(rec.table_schema) || '.' || quote_ident(rec.table_name) || ' WHERE ' || quote_ident(rec.column_name) || ' IS NOT NULL LIMIT 1' INTO v_exists; -- 如果v_exists为NULL,说明没有找到非值 IF v_exists IS NULL THEN schema_name := rec.table_schema; table_name := rec.table_name; column_name := rec.column_name; RETURN NEXT; END IF; END IF; END LOOP; END; $$ LANGUAGE plpgsql; ``` 注意:这里我们使用了同一个变量v_exists,在第二次查询后,如果没找到非值,则v_exists会被设置为NULL(因为SELECT INTO没有返回行)。 使用这个存储过程,效率会更高。 总结:用户可以根据自己的情况选择使用存储过程或生成动态SQL。 由于用户问题中引用了人大金仓的异常(引用[1]),可能用户遇到了数据一致的问题,这个查询可以帮助用户发现违反非约束的列(这些列应该被修复)。 另外,引用[2]提到统计信息,但统计信息可能准确(特别是没有及更新统计信息),所以我们直接查询数据。 最后,我们提供存储过程的方式作为推荐方案。 注意:在Kingbase中,系统模式可能有同的命名,用户需要根据实际情况调整排除的模式(例如,可能还有'public'模式?但public是用户模式,需要排除)。我们这里排除了常见的系统模式。 如果用户没有创建存储过程的权限,则只能使用生成动态SQL文本的方式。 因此,我们提供两种方法。 方法1:存储过程(高效,推荐) 创建上述存储过程,然后执行: SELECT * FROM find_not_null_columns_with_all_null(); 方法2:生成动态SQL(无需创建存储过程) 执行以下查询生成检查语句(用户需要复制结果并执行): SELECT 'SELECT ''' || c.table_schema || ''' AS schema_name, ''' || c.table_name || ''' AS table_name, ''' || c.column_name || ''' AS column_name FROM ' || quote_ident(c.table_schema) || '.' || quote_ident(c.table_name) || ' WHERE EXISTS (SELECT 1 FROM ' || quote_ident(c.table_schema) || '.' || quote_ident(c.table_name) || ' LIMIT 1) ' || ' AND NOT EXISTS (SELECT 1 FROM ' || quote_ident(c.table_schema) || '.' || quote_ident(c.table_name) || ' WHERE ' || quote_ident(c.column_name) || ' IS NOT NULL LIMIT 1) ' FROM information_schema.columns c WHERE c.table_schema NOT IN ('sys_catalog', 'pg_catalog', 'information_schema') AND c.is_nullable = 'NO'; 这个动态SQL片段会生成一个查询,该查询在满足条件返回一行。然后用户将所有这些查询用UNION ALL连接起来。 但是,这样生成的每个查询片段已经是一个完整的查询,可以单独执行。为了合并结果,我们生成: SELECT 'SELECT ''' || c.table_schema || ''' AS schema_name, ''' || c.table_name || ''' AS table_name, ''' || c.column_name || ''' AS column_name ' || ' WHERE EXISTS (SELECT 1 FROM ' || quote_ident(c.table_schema) || '.' || quote_ident(c.table_name) || ' LIMIT 1) ' || ' AND NOT EXISTS (SELECT 1 FROM ' || quote_ident(c.table_schema) || '.' || quote_ident(c.table_name) || ' WHERE ' || quote_ident(c.column_name) || ' IS NOT NULL LIMIT 1) UNION ALL' FROM information_schema.columns c WHERE c.table_schema NOT IN ('sys_catalog', 'pg_catalog', 'information_schema') AND c.is_nullable = 'NO'; 然后用户去掉最后一个UNION ALL,并加上分号。但这样生成的语句可能太容易处理。 我们可以生成一个完整的SQL脚本: SELECT 'CREATE TEMPORARY TABLE temp_result AS '; -- 先创建临表 -- 然后生成每个查询并插入临表 SELECT 'INSERT INTO temp_result SELECT ''' || c.table_schema || ''', ''' || c.table_name || ''', ''' || c.column_name || ''' ' || ' WHERE EXISTS (SELECT 1 FROM ' || quote_ident(c.table_schema) || '.' || quote_ident(c.table_name) || ' LIMIT 1) ' || ' AND NOT EXISTS (SELECT 1 FROM ' || quote_ident(c.table_schema) || '.' || quote_ident(c.table_name) || ' WHERE ' || quote_ident(c.column_name) || ' IS NOT NULL LIMIT 1);' FROM information_schema.columns c WHERE c.table_schema NOT IN ('sys_catalog', 'pg_catalog', 'information_schema') AND c.is_nullable = 'NO'; -- 最后加上查询表的语句 SELECT 'SELECT * FROM temp_result;'; 这样,用户需要先执行创建临表,然后执行一系列INSERT,最后查询表。 但是,创建临表需要先定义结构。我们可以这样: SELECT 'CREATE TEMPORARY TABLE temp_result (schema_name text, table_name text, column_name text);'; -- 然后生成INSERT语句 然后,将所有这些语句按顺序输出。 因此,完整的生成脚本: SELECT 'CREATE TEMPORARY TABLE temp_result (schema_name text, table_name text, column_name text);' AS sql_statement UNION ALL SELECT 'INSERT INTO temp_result SELECT ''' || c.table_schema || ''', ''' || c.table_name || ''', ''' || c.column_name || ''' ' || ' WHERE EXISTS (SELECT 1 FROM ' || quote_ident(c.table_schema) || '.' || quote_ident(c.table_name) || ' LIMIT 1) ' || ' AND NOT EXISTS (SELECT 1 FROM ' || quote_ident(c.table_schema) || '.' || quote_ident(c.table_name) || ' WHERE ' || quote_ident(c.column_name) || ' IS NOT NULL LIMIT 1);' AS sql_statement FROM information_schema.columns c WHERE c.table_schema NOT IN ('sys_catalog', 'pg_catalog', 'information_schema') AND c.is_nullable = 'NO' UNION ALL SELECT 'SELECT * FROM temp_result;'; 这样,用户执行这个生成脚本,会得到一系列SQL语句,然后复制这些语句(按顺序)执行即可。 注意:第一个语句是创建临表,然后是一系列INSERT,最后是查询。 由于生成的是多个独立的SQL语句,用户需要一次性全部执行(或者按顺序执行)。 我们选择存储过程作为主要推荐,因为更高效和方便。如果用户没有权限,再使用动态SQL脚本。 最后,我们还需要注意:Kingbase可能有一些特殊的系统表,我们排除的模式可能需要根据实际情况调整。 另外,字段名和表名的大小写:如果创建使用了双引号(大小写敏感),那么我们在quote_ident会加上双引号,所以是安全的。 根据引用[4]中,表名和模式名都是小写,所以应该没有问题。 综上所述,我们提供两种方法。 由于用户问题中要求查询所有表中字段为非但数据为的表和字段信息,我们给出了解决方案。 相关问题: 1. 如何修复这些非约束字段的问题? 2. 为什么会出现非约束字段的情况? 3. 如何避免非约束字段的情况? 我们可以在回答中提供一些建议: - 出现这种情况可能是因为数据导入没有检查,或者程序逻辑错误导致插入了值(尽管有非约束,但可能通过绕过约束的方式插入,比如禁用约束?)。 - 修复:需要根据业务逻辑为这些字段设置默认值,或者删除这些行,或者更新这些字段的值。 - 避免:在应用层和数据库层加强约束检查,确保插入和更新数据字段。 但用户的问题主要是查询,所以修复和避免作为相关问题。 因此,回答如下:</think>### 查询 Kingbase8 中非字段但数据为的表和字段信息 要查询 Kingbase8 数据库中所有**字段定义为非(NOT NULL)但实际数据全为**的表和字段信息,需结合数据字典和动态数据检查。以下是两种解决方案: --- #### **方法 1:使用存储过程(推荐,高效)** 创建存储过程遍历所有非字段,动态检查数据是否全为: ```sql CREATE OR REPLACE FUNCTION find_not_null_columns_with_all_null() RETURNS TABLE (schema_name text, table_name text, column_name text) AS $$ DECLARE rec record; v_exists integer; BEGIN FOR rec IN SELECT c.table_schema, c.table_name, c.column_name FROM information_schema.columns c WHERE c.table_schema NOT IN ('sys_catalog', 'pg_catalog', 'information_schema') AND c.is_nullable = 'NO' -- 过滤非字段 LOOP -- 检查表是否非 EXECUTE 'SELECT 1 FROM ' || quote_ident(rec.table_schema) || '.' || quote_ident(rec.table_name) || ' LIMIT 1' INTO v_exists; IF v_exists IS NOT NULL THEN -- 表中有数据 -- 检查字段是否全为 EXECUTE 'SELECT 1 FROM ' || quote_ident(rec.table_schema) || '.' || quote_ident(rec.table_name) || ' WHERE ' || quote_ident(rec.column_name) || ' IS NOT NULL LIMIT 1' INTO v_exists; -- 若无非值,则记录结果 IF v_exists IS NULL THEN schema_name := rec.table_schema; table_name := rec.table_name; column_name := rec.column_name; RETURN NEXT; END IF; END IF; END LOOP; END; $$ LANGUAGE plpgsql; ``` **执行查询**: ```sql SELECT * FROM find_not_null_columns_with_all_null(); ``` **输出示例**: ``` schema_name | table_name | column_name -------------+------------+------------- public | employees | phone -- 表employees的phone字段定义为NOT NULL但实际全为 sales | orders | discount -- 表orders的discount字段违反非约束 ``` --- #### **方法 2:动态生成检查脚本(无需创建存储过程)** 生成 SQL 脚本手动执行,适合无权限创建存储过程的情况: ```sql -- 步骤1:生成临表创建语句 SELECT 'CREATE TEMPORARY TABLE temp_result (schema_name text, table_name text, column_name text);' AS sql_statement UNION ALL -- 步骤2:为每个非字段生成检查语句 SELECT 'INSERT INTO temp_result SELECT ''' || c.table_schema || ''', ''' || c.table_name || ''', ''' || c.column_name || ''' WHERE EXISTS (SELECT 1 FROM ' || quote_ident(c.table_schema) || '.' || quote_ident(c.table_name) || ' LIMIT 1) AND NOT EXISTS (SELECT 1 FROM ' || quote_ident(c.table_schema) || '.' || quote_ident(c.table_name) || ' WHERE ' || quote_ident(c.column_name) || ' IS NOT NULL LIMIT 1);' AS sql_statement FROM information_schema.columns c WHERE c.table_schema NOT IN ('sys_catalog', 'pg_catalog', 'information_schema') AND c.is_nullable = 'NO' UNION ALL -- 步骤3:生成结果查询语句 SELECT 'SELECT * FROM temp_result;'; ``` **操作步骤**: 1. 执行上述 SQL,获取生成的脚本(多条语句)。 2. 复制生成的完整脚本,在数据库中执行。 3. 结果将保存在临表 `temp_result` 中。 --- ### **关键说明** 1. **过滤系统表**: - 排除 `sys_catalog`, `pg_catalog`, `information_schema` 等系统模式[^2][^4]。 2. **非约束检查**: - `information_schema.columns.is_nullable = 'NO'` 标识字段定义为非[^2]。 3. **数据为判定**: - 表中有数据(`COUNT(*) > 0`)且字段无任何非值(`COUNT(column) = 0`)[^2]。 4. **安全性**: - 使用 `quote_ident()` 处理特殊字符(如大写表名)[^4]。 --- ### **可能原因与修复建议** - **原因**: 数据导入错误、程序逻辑漏洞或约束被绕过导致字段全为[^1]。 - **修复**: ```sql -- 示例:清理无效数据(需根据业务逻辑调整) DELETE FROM public.employees WHERE phone IS NULL; -- 或填充默认值 UPDATE sales.orders SET discount = 0 WHERE discount IS NULL; ``` --- ### 相关问题 1. **如何防止非字段出现值?** - 建议:应用层校验 + 数据库触发器 + 严格约束[^2][^4]。 2. **Kingbase8 中如何批量修改非字段的默认值?** - 示例:`ALTER TABLE table_name ALTER COLUMN column_name SET DEFAULT value;` 3. **如何监控数据库约束违规情况?** - 方案:定期执行此类检查脚本,或使用 `sys_constraint` 系统表[^2][^4]。 [^1]: 数据一致可能由程序错误或约束绕过导致,需结合业务逻辑修复。 [^2]: 数据字典记录字段约束和统计信息(如值分布),但需实验证数据[^2]。 [^4]: 模式(Schema)操作需注意依赖对象,删除前需解除依赖[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值