SELECT ( SELECT ID FROM SYS_MENU smps WHERE NAME ='My Report Name' AND HREF ='/path/to/my/report' ) AS MENU_ID, 3AS "TYPE", ( SELECT ID FROM SYS_USER sus WHERE USER_NAME ='myUsername' ) AS OWNER FROM DUMMY;
SELECT ( SELECT ID FROM SYS_MENU smps WHERE NAME ='My Report Name' AND HREF ='/path/to/my/report' LIMIT 1) AS MENU_ID, 3AS "TYPE", ( SELECT ID FROM SYS_USER sus WHERE USER_NAME ='myUsername' LIMIT 1) AS OWNER FROM DUMMY;
SELECT smps.ID AS MENU_ID, 3AS "TYPE", sus.ID AS OWNER FROM SYS_MENU smps LEFTJOIN SYS_USER sus ON sus.USER_NAME ='myUsername' WHERE smps.NAME ='My Report Name' AND smps.HREF ='/path/to/my/report';
然而,我需要进一步的为 smps.ID 和 sus.ID 添加 COALESCE 函数,当 smps.ID 或 sus.ID 为 null 时,可以使用 USER_NAME 或 HREF 作为替代值。使用 LEFT JOIN 后,当右侧条件 WHERE LOWER(USER_NAME) = LOWER('myUsername') 匹配不到结果时,sus_ID 可以显示替代值,当左侧条件 WHERE NAME = 'My Report Name' 在表中没有任何匹配结果时,整个查询只会返回空结果集,就无法用 COALESCE 函数对 MENU_ID 插入替代值了。即使使用 FULL JOIN 或笛卡尔积 CROSS JOIN 也无法解决任何一边的结果集为空的情况。
用 UNION ALL 确保不返回空
为了解决这个问题,可以用 LEFT JOIN 将两个子查询连接在一起,并且 ON 条件始终为 true。然后在每个子查询的末尾添加一个 UNION ALL 子句,如果没有检查到匹配结果,就会通过 DUMMY 表添加一行带有 NULL 值的记录。这样即可确保即使 URL 没有匹配结果,仍然会返回带有替代值的结果。
SELECT COALESCE(TO_CHAR(smps.ID), '/path/to/my/report') AS MENU_ID, COALESCE(TO_CHAR(sus.ID), 'myUsername') AS OWNER FROM (SELECT ID FROM SYS_MENU WHERE NAME ='My Report Name' AND HREF ='/path/to/my/report' UNIONALL SELECTNULLAS ID FROM DUMMY WHERENOTEXISTS ( SELECT ID FROM SYS_MENU WHERE NAME ='My Report Name' AND HREF ='/path/to/my/report' )) AS smps LEFTJOIN (SELECT ID FROM SYS_USER WHERELOWER(USER_NAME) =LOWER('myUsername') UNIONALL SELECTNULLAS ID FROM DUMMY WHERENOTEXISTS ( SELECT ID FROM SYS_USER WHERELOWER(USER_NAME) =LOWER('myUsername') )) AS sus ON1=1;
最终我使用的 SQL 语句如下,再结合 Excel 公式和 SQL 转义,它完美地帮我将一份报表名称与URL重复/不对应、用户名不准确/大小写混淆、存在隐性的/无法匹配的Unicode字符的 xlsx 表格维护的 MENU 与 USER 的关系导入到了数据库中:上万数据一遍跑通,新数据更新旧数据,哪里匹配不上就留下问题定位信息,一对多记录也一并插入,还可以重复导入,最后手工纠正一下替代值,甚是畅快。
MERGE INTO SYS_MENU_USER AS target USING ( SELECT COALESCE(TO_CHAR(smps.ID), '/path/to/my/report') AS MENU_ID, 3AS "TYPE", COALESCE(TO_CHAR(sus.ID), 'myUsername') AS OWNER FROM ( SELECT ID FROM SYS_MENU WHERE NAME ='My Report Name' AND HREF ='/path/to/my/report' UNIONALL SELECT NULLAS ID FROM DUMMY WHERE NOTEXISTS ( SELECT ID FROM SYS_MENU WHERE NAME ='My Report Name' AND HREF ='/path/to/my/report' )) AS smps LEFTJOIN ( SELECT ID FROM SYS_USER WHERE LOWER(USER_NAME) =LOWER('myUsername') UNIONALL SELECT NULLAS ID FROM DUMMY WHERE NOTEXISTS ( SELECT ID FROM SYS_USER WHERE LOWER(USER_NAME) =LOWER('myUsername') )) AS sus ON 1=1) AS SOURCE ON target.MENU_ID = source.MENU_ID AND target."TYPE" = source."TYPE" WHEN MATCHED THEN UPDATE SET OWNER = source.OWNER WHENNOT MATCHED THEN INSERT (MENU_ID, "TYPE", OWNER) VALUES (source.MENU_ID, source."TYPE", source.OWNER);