postgresql中数据表如何通过一个字段标识数据行多种状态?

通常我们在业务开发过程中,为了避免多余字段的创建,要尽可能的减少单表字段个数,针对一些数据状态可以采用一个数字融合多种数据状态。

以下是业务开发过程中的枚举类:

@Getter
public enum TicketTagEnum {

    REMINDERS(1, "状态1"),
    REASSIGNMENT(2, "状态2"),
    REWORK(4, "状态3"),
    SUSPEND(8, "状态4"),
    TRANSFER(16, "状态5"),
    INSPECTION(32, "状态6"),
    ALARM(64, "状态7");

    private final Integer code;
    private final String desc;

    TicketTagEnum(Integer code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    // 将标签数字和拆分成2次幂的数字
    public static List<Integer> splitTags(int n) {
        List<Integer> result = new ArrayList<>();
        int bit = 1;
        while (n > 0) {
            if ((n & bit) != 0) {
                result.add(bit);
            }
            n -= (n & bit);
            bit <<= 1;
        }
        return result;
    }

    // 添加标签
    public static int addTag(int oldTag, int newTag) {
        return oldTag | newTag;
    }

    // 移除标签,但是这种计算需要旧的标签中一定包含了新的标签
    public static int removeTag(int oldTag, int newTag) {
        return splitTags(oldTag).contains(newTag) ? oldTag ^ newTag : oldTag;
    }
    
    // 移除标签 更加完善的写法
    public static int removeTagPro(int oldTag, int newTag) {
        return oldTag & ~newTag;
    }
}

添加数据状态时:TicketTagEnum.addTag(oldTag, newTag);

移除数据状态时:TicketTagEnum.removeTag(oldTag, newTag);

SQL查询数据行是否包含某种状态时:select * from table where 4 = any(split_into_powers_of_two_arr(tags))

具体SQL函数的实现如下:

CREATE OR REPLACE FUNCTION "public"."split_into_powers_of_two_arr"("n" int8)
  RETURNS "pg_catalog"."_int8" AS $BODY$
DECLARE
    current_value BIGINT := n;
    current_power BIGINT := 1;
    powers_arr BIGINT[] := '{}';
BEGIN
    WHILE current_value > 0 LOOP
        IF (current_value & 1) = 1 THEN
            powers_arr := array_append(powers_arr, current_power);
        END IF;

        current_value := current_value >> 1;
        current_power := current_power << 1;
    END LOOP;

    RETURN powers_arr;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100

 

posted @ 2024-10-23 09:38  文所未闻  阅读(4)  评论(0编辑  收藏  举报