将 id 插入具有相同信息的行的 PL/SQL 过程
Posted
技术标签:
【中文标题】将 id 插入具有相同信息的行的 PL/SQL 过程【英文标题】:PL/SQL procedure to insert id to rows having same information 【发布时间】:2017-01-15 14:00:04 【问题描述】:我在 Oracle 表中有联系方式数据,如下所示...
我想插入新列以将相同的 ID 分配给具有匹配信息的联系人,即基于姓氏、名字和(电话和/或电子邮件)的组
输出应该如下所示
我是这个论坛的新手,所以在发布问题时遇到格式问题,请查看附件图片以便于理解我的要求
在我们庞大的数据库中寻找 PL/SQL 过程来完成这项工作
【问题讨论】:
你能在这里分享示例数据,以便我可以尝试在本地查询。它真的很有帮助 meta.***.com/questions/285551/… 为什么你认为你需要一个存储过程?一个简单的rank()
就可以了
始终将表格格式的示例数据作为文本而不是图像发布
@a_horse_with_no_name 如果您认为 rank() 可以解决我的目的,请提供解决方案。我正在考虑程序,因为数据很复杂,例如,您在我的 ID 2 示例输出要求中看到,电话和电子邮件有多种组合。对于相同的总共 13 个名字姓氏,这些实际上只是 4 个不同的联系人,因为您可以分析给定示例输出中的组合。
【参考方案1】:
由于您提供的数据的性质,我认为不可能在一个 SQL 中执行此操作或对其进行更好的调整。
创建表格并使用您的示例填充的脚本:
create table TAB_TEST(LAST_NAME VARCHAR2(200),
FIRST_NAME VARCHAR2(200),
PHONE NUMBER,
EMAIL VARCHAR2(200))
/
INSERT INTO TAB_TEST VALUES
('Ho','Kim', 2058371579, 'ABC@GMAIL.COM')
/
INSERT INTO TAB_TEST VALUES
('Ho','Kim', 4479940000, 'ABC@GMAIL.COM')
/
INSERT INTO TAB_TEST VALUES
('Ho','Kim', 7195739945, 'XYZ@HOTMAIL.COM')
/
INSERT INTO TAB_TEST VALUES
('Ho','Kim', 7475393956, 'XYZ@HOTMAIL.COM')
/
INSERT INTO TAB_TEST VALUES
('Ho','Kim', 7475393956, 'XYZ@HOTMAIL.COM')
/
INSERT INTO TAB_TEST VALUES
('Ho','Kim', 7473430336, null)
/
INSERT INTO TAB_TEST VALUES
('Ho','Kim', 7195739945, 'XYZ@HOTMAIL.COM')
/
INSERT INTO TAB_TEST VALUES
('Ho','Kim', 7475393956, '123@HOTMAIL.COM')
/
INSERT INTO TAB_TEST VALUES
('Ho','Kim', null, '123@HOTMAIL.COM')
/
INSERT INTO TAB_TEST VALUES
('Ho','Kim', 1168548666, '456@HOTMAIL.COM')
/
INSERT INTO TAB_TEST VALUES
('Ho','Kim', 1168548666, '456@HOTMAIL.COM')
/
INSERT INTO TAB_TEST VALUES
('Ho','Kim', 1168548666, null)
/
INSERT INTO TAB_TEST VALUES
('Ho','Kim', 7473430336, null)
/
ALTER TABLE TAB_TEST ADD ID NUMBER
/
以及要更新的脚本
DECLARE
lncount NUMBER := 1;
-- had to create this record in order to add the rowid
TYPE lttab_test IS RECORD(
ROWID VARCHAR2(200),
last_name VARCHAR2(200),
first_name VARCHAR2(200),
phone NUMBER,
email VARCHAR2(200),
id NUMBER);
TYPE lttype
IS TABLE OF LTTAB_TEST;
larecords LTTYPE;
BEGIN
SELECT ROWID,
last_name,
first_name,
phone,
email,
id
bulk collect INTO larecords
FROM tab_test a;
FOR i IN 1..larecords.count LOOP
IF Larecords(i).id IS NULL THEN
FOR j IN 1..i-1 LOOP
IF Larecords(j).phone = Larecords(i).phone
AND Larecords(i).id IS NULL THEN
Larecords(i).id := Larecords(j).id;
exit;
END IF;
END LOOP;
FOR j IN 1..i-1 LOOP
IF Larecords(j).email = Larecords(i).email
AND Larecords(i).id IS NULL THEN
Larecords(i).id := Larecords(j).id;
exit;
END IF;
END LOOP;
IF Larecords(i).id IS NULL THEN
Larecords(i).id := lncount;
lncount := lncount + 1;
END IF;
END IF;
END LOOP;
forall i IN 1..larecords.count
UPDATE tab_test
SET id = Larecords(i).id
WHERE ROWID = Larecords(i).ROWID;
COMMIT:
END;
【讨论】:
如果您可以将我的评论标记为答案,它可以在未来对其他人有所帮助,并且我会获得声誉。谢谢 您上面的代码在样本测试数据上运行良好,但是当我们处理大量数据时它会失败。您能否分享一下批量限制的代码,比如测试数据中一次 5 行,这应该会产生相同的输出。 'fors' 让它变慢了,说实话,我不知道如何将您的问题实施到更快的查询中。 Bulk 不起作用,因为它总是需要查看记录的先前状态。【参考方案2】:这不是最有效/最漂亮的代码,但它可以在您只需要序列号的情况下工作
DECLARE
I NUMBER := 0;
BEGIN
ALTER TABLE TABLE
ADD ID NUMBER;
COMMIT;
FOR REC IN (SELECT * FROM TABLE)
LOOP
IF(REC.ID IS NULL) THEN
UPDATE TABLE T SET ID = I
WHERE (T.EMAIL = REC.EMAIL OR T.PHONE = REC.PHONE)
AND ID IS NULL;
COMMIT;
I := I + 1;
END IF;
END LOOP;
END;
【讨论】:
DDL 自动提交事务,不需要使用 COMMIT。 TheName@ 如果您从 java 启动 PL/SQL 过程,情况可能并非总是如此 什么意思? TheName@在Java中创建连接对象,使用Connection.setAutoCommit设置autocommit为false,然后使用Java Connection.prepareCall调用存储过程以上是关于将 id 插入具有相同信息的行的 PL/SQL 过程的主要内容,如果未能解决你的问题,请参考以下文章