oracle - 插入包含 200 列的表中
问题描述
我们的 Oracle DB 中有一个包含 200 列的表,我们必须将其插入其中,并且我们有一个 C 程序在该表中插入请求,它使用 Pro*C 调用 oracle DB 中的存储程序来完成这项工作。
目前我们用 TLV 格式{Tag-Length-Value} 序列化所有字段,并有一个带有 Varchar2 参数的函数(字段的序列化列表)。例如:
008603701212345678901201100611111104800622222220000633333320100644444401201420200321164712
更具人类可读性:
0086 037 012 123456789012 011 006 111111 048 006 222222 200 006 333333 201 006 444444 012 014 20200321164712
意思是:
String Len:86
Field037 with len 12:123456789012
Field011 with len 6:111111
Field048 with len 6:222222
Field200 with len 6:333333
Field201 with len 6:444444
Field012 with len 14:20200321164712
这些字段中的每一个都映射到表中的字段,存储的程序解析巨大的字符串并将它们填充到行类型中,最后将行插入表中。
多年来它运行良好,但是当我们为更多请求(因此更多插入)做好准备时,我们的 DBA 说我们正在使用大量 CPU 来反序列化 TLV。所以我们必须改变我们的插入方法。
我目前在 C 中创建了一个结构并映射其中的所有字段并调用:
typedef struct
{
char field37[12+1];
char field11[6+1];
char field48[6+1];
char field200[6+1];
char field201[6+1];
char field12[14+1];
} NewRecord;
NewRecord newRecord;
TlvToStruct(sTlv, &newRecord);//Mapper Function
EXEC SQL INSERT INTO MY_TABLE(FIELD37, FIELD11, FIELD200, FIELD201, FIELD12) VALUES(:newRecord);
EXEC SQL COMMIT WORK RELEASE;
这种方法目前效果很好,但我的问题是:我应该继续开发并将所有 200 个字段添加到此结构并使用此方法还是使用 PLSQL 调用(可能开发并使用另一个插入函数)而不是此 SQL 插入更好?
我目前知道 PLSQL 的好处,但这里有一些问题:
1- Pro*C does not support PLSQL Records
2- It is not so reasonable to have a function with 200 parameters!
3- We use Types in plsql but never used them in Pro*C(actually I tried once and I failed long ago)
我试图在这里描述问题,如果不清楚请询问
谢谢
====================================================
编辑:
这是我们旧的 Get_Tag 和 Put_Tag 函数:
FUNCTION GET_TAG(P_TAG_NAME IN VARCHAR2, P_TLV_STRG IN VARCHAR2, P_TAG_LEN OUT NOCOPY PLS_INTEGER, P_TAG_VALUE OUT NOCOPY VARCHAR2)
RETURN PLS_INTEGER IS
V_COUNTER_LOOP PLS_INTEGER := 1;
V_TLV_STRG VARCHAR2(4096) := SUBSTR(P_TLV_STRG, 5);
BEGIN
P_TAG_VALUE := NULL;
P_TAG_LEN := 0;
WHILE V_COUNTER_LOOP < LENGTH(V_TLV_STRG) LOOP
IF SUBSTR(V_TLV_STRG, V_COUNTER_LOOP, 3) = P_TAG_NAME THEN
P_TAG_LEN := TO_NUMBER(SUBSTR(V_TLV_STRG, V_COUNTER_LOOP + 3, 3));
P_TAG_VALUE := SUBSTR(V_TLV_STRG, V_COUNTER_LOOP + 6, P_TAG_LEN);
RETURN (DECLARATION_CST.OK);
END IF;
V_COUNTER_LOOP := V_COUNTER_LOOP + 6 + TO_NUMBER(SUBSTR(V_TLV_STRG, V_COUNTER_LOOP + 3, 3));
END LOOP;
RETURN 0;
EXCEPTION
WHEN OTHERS THEN
RETURN -1;
END GET_TAG;
==================================================== =========
FUNCTION PUT_TAG(P_TAG_NAME IN VARCHAR2, P_TAG_VALUE IN VARCHAR2, P_TLV_STRG IN OUT NOCOPY VARCHAR2)
RETURN PLS_INTEGER IS
V_COUNTER_LOOP PLS_INTEGER := 0;
TMP_VARCHAR VARCHAR2(4096);
BEGIN
P_TLV_STRG := SUBSTR(P_TLV_STRG, 5);
V_COUNTER_LOOP := 1;
WHILE V_COUNTER_LOOP < LENGTH(P_TLV_STRG) LOOP
IF SUBSTR(P_TLV_STRG, V_COUNTER_LOOP, 3) = SUBSTR(P_TAG_NAME, 1, 3) THEN
TMP_VARCHAR :=
SUBSTR(P_TLV_STRG, 1, V_COUNTER_LOOP - 1)
|| SUBSTR(P_TAG_NAME, 1, 3)
|| TO_CHAR(NVL(LENGTH(P_TAG_VALUE), 0), 'FM000')
|| P_TAG_VALUE
|| SUBSTR(P_TLV_STRG, V_COUNTER_LOOP + 6 + TO_NUMBER(SUBSTR(P_TLV_STRG, V_COUNTER_LOOP + 3, 3)));
P_TLV_STRG := TO_CHAR(LENGTH(TMP_VARCHAR), 'FM0000') || TMP_VARCHAR;
RETURN (DECLARATION_CST.OK);
END IF;
V_COUNTER_LOOP := V_COUNTER_LOOP + 6 + TO_NUMBER(SUBSTR(P_TLV_STRG, V_COUNTER_LOOP + 3, 3));
END LOOP;
P_TLV_STRG :=
P_TLV_STRG
|| SUBSTR(P_TAG_NAME, 1, 3)
|| TO_CHAR(NVL(LENGTH(P_TAG_VALUE), 0), 'FM000')
|| P_TAG_VALUE;
P_TLV_STRG := TO_CHAR(LENGTH(P_TLV_STRG), 'FM0000') || P_TLV_STRG;
RETURN 0;
EXCEPTION
WHEN OTHERS THEN
RETURN -1;
END PUT_TAG;
解决方案
您需要首先在数据库中创建映射到字段及其长度的映射表(在我的示例中,我已用作CTE
您的映射表:)YOUR_MAPPING_TABLE
。
甲骨文设置:
SQL> CREATE TABLE TEST1234 (
2 FIELD001 VARCHAR2(4000),
3 FIELD002 VARCHAR2(4000),
4 FIELD003 VARCHAR2(4000),
5 FIELD004 VARCHAR2(4000)
6 );
Table created.
解决方案查询:
SQL> INSERT INTO TEST1234
2 WITH YOUR_MAPPING_TABLE (FIELD_ID, LEN)
3 AS (
4 SELECT 'FIELD001', 4 FROM DUAL UNION ALL
5 SELECT 'FIELD002', 3 FROM DUAL UNION ALL
6 SELECT 'FIELD003', 3 FROM DUAL UNION ALL
7 SELECT 'FIELD004', 12 FROM DUAL
8 )
9 SELECT * FROM
10 ( SELECT M.FIELD_ID, -- Your string will go in following substring
11 SUBSTR('0086037012123456789012', M.STARTPOS + 1, M.TOTALLEN) AS FIELDVALUE
12 FROM ( SELECT FIELD_ID,
13 SUM(LEN) OVER(ORDER BY FIELD_ID ) - LEN AS STARTPOS,
14 LEN AS TOTALLEN
15 FROM YOUR_MAPPING_TABLE
16 ) M
17 ) PIVOT (
18 MIN ( FIELDVALUE )
19 FOR FIELD_ID IN ( 'FIELD001', 'FIELD002', 'FIELD003', 'FIELD004' )
20 );
1 row created.
测试结果
SQL> SELECT * FROM TEST1234;
FIELD001 | FIELD002 | FIELD003 | FIELD004
---------- | ---------- | ---------- | -------------
0086 | 037 | 012 | 123456789012
SQL>
您可以根据您的逻辑在查询中传递您的大字符串。
推荐阅读
- python - 如何在python中使用数值条件?
- node.js - 如何在 JSON 中添加变量键?
- javascript - 实现芯片
- datamodel - 将表链接到另一个表
- flutter - 打开/关闭抽屉布局时如何将导航抽屉汉堡菜单图标更改为箭头图标 - Flutter?
- java - 如何使用 Firebase 数据库更新本地对象
- python - 如果我试图拟合来自 pandas 数据帧的数据,如何将 input_shape 赋予卷积神经网络?
- visual-studio-code - VS 代码 - Biztalk 开发
- python - 使用“if”语句检测两只海龟的碰撞
- javascript - 使用 JavaScript 替换字符串中的 # 和 \s