Oracle SQL替换变量,替换范围

Oracle SQL substitution variable, the scope of substitution

我一直在思考我实际上可以将什么以及多少放入替代变量中。我们可以只用它来替换单个 'entity' 而不是一串命令吗?我发现如果我想替换一块实际的 SQL,它不起作用(在 SqlDeveloper 中)。

我想知道如何解决这个问题...

/*------test--------------*/
CREATE TABLE Test_Persons (
    PersonID int,
    LastName varchar(255),
    FirstName varchar(255)
);

INSERT INTO Test_Persons
    (PersonID,LastName,FirstName)
    values(1,'LN_1','FN_1');

INSERT INTO Test_Persons
    (PersonID,LastName,FirstName)
    values(2,'LN_2','FN_2');

INSERT INTO Test_Persons
    (PersonID,LastName,FirstName)
    values(3,'LN_21','FN_2');

commit;

--------------sub-table, worked!---
set define #;

define first_name_input = 'FN_2';
define last_name_input = 'LN_2';
define tbl_Test_Persons = 'Test_Persons';
define temp_tbl_Test_Persons_FN = 'Test_Persons_FN';

with 
#temp_tbl_Test_Persons_FN as
(
    select * from #tbl_Test_Persons tp 
    where tp.FIRSTNAME = '#first_name_input'
)
select * from #temp_tbl_Test_Persons_FN tp 
    where tp.LASTNAME = '#last_name_input';

set define off;


--------------sub-table, replace the entire with clause, does NOT work - 'Invalid value for DEFINE command.'!---
set define #;

define first_name_input = 'FN_2';
define last_name_input = 'LN_2';
define tbl_Test_Persons = 'Test_Persons';
define temp_tbl_Test_Persons_FN = 'Test_Persons_FN2';
define with_clause = '
with 
#temp_tbl_Test_Persons_FN as
(
    select * from #tbl_Test_Persons tp 
    where tp.FIRSTNAME = ''#first_name_input''
)
';

#with_clause
select * from #temp_tbl_Test_Persons_FN tp 
    where tp.LASTNAME = '#last_name_input';

set define off;

From the documentation(对于 SQL*Plus 但也适用于 SQL 开发人员):

If the value of a defined variable extends over multiple lines (using the SQL*Plus command continuation character), SQL*Plus replaces each continuation character and carriage return with a space.

SQL 开发人员的行为 略有 不同,并将继续字符留在字符串中,这没有帮助。但是它也留下了换行符,所以你可以将连续字符从 - 加倍到 -- 以阻止它引起问题,因为它随后被视为注释;所以你可以这样做:

define with_clause = '--
with--
#temp_tbl_Test_Persons_FN as--
(--
    select * from #tbl_Test_Persons tp--
    where tp.FIRSTNAME = ''#first_name_input''--
)--
';

但还有一个更复杂的问题,因为 #with_clause 未被识别为命令 - 因为您尚未进入命令替换不会发生。您可以使用子查询来解决这个问题:

select * from (
#with_clause
select * from #temp_tbl_Test_Persons_FN tp 
    where tp.LASTNAME = '#last_name_input'
);

这并不理想。但是,如果您这样做,脚本输出 window 会显示正在发生的替换,并且您会返回一行:

old:select * from (
#with_clause
select * from #temp_tbl_Test_Persons_FN tp 
    where tp.LASTNAME = '#last_name_input'
)
new:select * from (
--
with--
Test_Persons_FN2 as--
(--
    select * from Test_Persons tp--
    where tp.FIRSTNAME = 'FN_2'--
)--

select * from Test_Persons_FN2 tp 
    where tp.LASTNAME = 'LN_2'
)

  PERSONID LASTNAME                                                                                                                                                                                                                                                        FIRSTNAME                                                                                                                                                                                                                                                      
---------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
         2 LN_2                                                                                                                                                                                                                                                            FN_2                                                                                                                                                                                                                                                           

(此外,有趣的是,这在 SQL 中仍然不起作用*另外,如果您使用 # 作为替换字符 - 您会得到 "ORA-24333: zero iteration count"。它不会得到& 的那个错误;我还没有尝试过任何其他的。你必须回到单个连接字符。但即使进行了这些更改,它仍然不能正确地替换 with 子句。还不确定为什么。)