我有一个应用程序,登录的用户有部门授权列表:
DEPT1, DEPT2, DEPT3, ..., DEPT5000, DEPT5001, ...
大多数用户为自己的个人资料分配了5,000多个部门。
我的任务是编写一个数据模型+应用程序代码,该代码将在用户每次登录时“快照”其授权部门的列表,以便我们可以参考该用户被授权执行的操作(注意:DEPT ID不是整齐地编号(如本例所示)。
我首先想到的是将部门列表转换为长CSV字符串并将其存储为CLOB:
CREATE TABLE UI_SECURITY_CONFIG (
SECURITY_CONFIG_ID NUMBER(19,0) NOT NULL,
DEPTSCSV CLOB NOT NULL
);
并且每个DEPTSCSV CLOB
都是唯一的。如果用户具有与以前登录的其他用户相同的安全配置文件,则只需选择该安全配置。否则,它将创建一个新行。基本上,选择DEPTSCSV ='DEPT1,DEPT2,DEPT3 ...',如果不存在,则将其插入。但是这种方法失败了,因为一个巨大的字符串(超过25,000个字符)是不可比的:
SELECT * FROM UI_SECURITY_CONFIG WHERE DEPTSCSV = 'DEPT0001, DEPT0002, DEPT0003, ..., DEPT5001, DEPT5002'
SQL Error [1704] [42000]: ORA-01704: string literal too long
因此,我想到了将CSV中的每个项目都做成表格中自己的行:
CREATE TABLE UI_SECURITY_CONFIG (
SECURITY_CONFIG_ID NUMBER(19,0) NOT NULL,
DEPTID VARCHAR2(20) NOT NULL
);
INSERT INTO UI_SECURITY_CONFIG(SECURITY_CONFIG_ID, DEPTID) VALUES(1, 'DEPT0001');
INSERT INTO UI_SECURITY_CONFIG(SECURITY_CONFIG_ID, DEPTID) VALUES(1, 'DEPT0002');
INSERT INTO UI_SECURITY_CONFIG(SECURITY_CONFIG_ID, DEPTID) VALUES(1, 'DEPT0003');
...
INSERT INTO UI_SECURITY_CONFIG(SECURITY_CONFIG_ID, DEPTID) VALUES(1, 'DEPT5001');
INSERT INTO UI_SECURITY_CONFIG(SECURITY_CONFIG_ID, DEPTID) VALUES(1, 'DEPT5002');
但是我正在努力编写SQL select,这将是一种有效的匹配算法,以查找是否存在与Departments列表完全匹配的SECURITY_CONFIG_ID。
我什至不确定是否有解决此问题的有效方法。
询问堆栈溢出。你会怎么做?
我能够实现策略1。与PreparedStatement相比,应用程序代码(Java)比我的SQL客户端(DBeaver)处理CLOB比较更好:
String sql = "SELECT SECURITY_CONFIG_ID FROM UI_SECURITY_CONFIG WHERE dbms_lob.compare(DEPTSCSV, ?) = 0";
String DEPTSCSV = "DEPT0001, DEPT0002, ...";
try(PreparedStatement objStmt = objConn.prepareStatement(sql)) {
Clob clob1 = objConn.createClob();
clob1.setString(1, DEPTSCSV);
objStmt.setClob(1, clob1);
ResultSet result = objStmt.executeQuery();
...
}