如何在 PL/SQL 中使用 select 语句为 SQL*Plus 变量赋值?
Posted
技术标签:
【中文标题】如何在 PL/SQL 中使用 select 语句为 SQL*Plus 变量赋值?【英文标题】:How to assign a value to SQL*Plus variable with select statement in PL/SQL? 【发布时间】:2016-03-23 22:03:25 【问题描述】:如何使用 select 语句为变量赋值并在 SQL*Plus 脚本中使用它?
VARIABLE FullCatCode VARCHAR2(7)
exec :FullCatCode := (SELECT CatCode from draw_catcodes where series = 123 and base = 158);
SELECT :FullCatCode || '-' || Other stuff... from table_name...
编辑:@AlexPoole,对于不精确的问题陈述感到抱歉。我正在从 280K 记录数据集中提取 50 列数据。我根据来自辅助表 (draw_catcodes) 的子字符串为每条记录分配序列 nextval。我在 SQL*Plus 中运行 SELECT 语句,假脱机到一个 CSV 文件。 SQL 现在看起来像这样(在下面测试您的第二个建议):
COLUMN CatCode NEW_VALUE FullCatCode;
SELECT
(CASE d.image WHEN 0 THEN 'NoImage.pdf'
ELSE lower(d.prefix || lpad(d.series,3,0) || lpad(d.base,3,0) || lpad(d.suffix,2,0) || lpad(d.rev,2,0) || '.pdf') END) as "Filename",
(SELECT EngDiscipline from draw_catcodes c where d.series = c.series and d.base = c.base) as "EngDiscipline",
(SELECT CatCode from draw_catcodes c where d.series = c.series and d.base = c.base),
SELECT &FullCatCode || '-' ||
lpad((CASE substr(&FullCatCode,0,3)
WHEN 'AEG' THEN (SELECT AEG_seq.NEXTVAL FROM DUAL)
WHEN 'ARY' THEN (SELECT ARY_seq.NEXTVAL FROM DUAL)
WHEN 'BBR' THEN (SELECT BBR_seq.NEXTVAL FROM DUAL)
ELSE 0
END),6,0) as "ItemID",
upper(d.prefix || '-' || lpad(d.series,3,0) || '-' || lpad(d.base,3,0) || '-' || lpad(d.suffix,2,0)) as "LegacyID",
...
from tablename where ...
我从一个“更新插入”序列表的存储函数开始(无法从函数执行 DML),尝试了一个带有 OUT 变量的存储过程(无法从 SQL SELECT 中调用该过程),现在在 CASE 语句中尝试序列(无法弄清楚如何使用上述变量)...任何建议将不胜感激!
编辑:@AlexPoole,由于变量在这种情况下不起作用,我只是直接选择我想要的值,然后使用 CASE 语句来指定正确的顺序。语法不正确,因为我在下一行收到 ORA-00933: SQL command not properly end 错误:
SELECT ((SELECT CatCode from draw_catcodes c where d.series = c.series and d.base = c.base) || '-' ||
lpad((CASE substr((SELECT CatCode from draw_catcodes c where d.series = c.series and d.base = c.base),0,3)
WHEN 'AEG' THEN AEG_seq.NEXTVAL
WHEN 'ARY' THEN ARY_seq.NEXTVAL
WHEN 'BBR' THEN BBR_seq.NEXTVAL
...
WHEN 'SPR' THEN SPR_seq.NEXTVAL
WHEN 'SRL' THEN SRL_seq.NEXTVAL
ELSE 0
END),6,0)) as "ItemID" FROM DUAL,
upper(d.prefix || '-' || lpad(d.series,3,0) || '-' || lpad(d.base,3,0) || '-' || lpad(d.suffix,2,0)) as "LegacyID",
编辑:@AlexPoole,我添加了 JOIN 并清理了 SELECT,但现在得到 ORA-02287:此处不允许序列号
(c.CatCode || '-' ||
(SELECT lpad(
(CASE substr(c.CatCode,0,3)
WHEN 'AEG' THEN AEG_seq.NEXTVAL
WHEN 'ARY' THEN ARY_seq.NEXTVAL
WHEN 'BBR' THEN BBR_seq.NEXTVAL
WHEN 'BSY' THEN BSY_seq.NEXTVAL
...
WHEN 'SDR' THEN SDR_seq.NEXTVAL
WHEN 'SLC' THEN SLC_seq.NEXTVAL
WHEN 'SLD' THEN SLD_seq.NEXTVAL
WHEN 'SMS' THEN SMS_seq.NEXTVAL
WHEN 'SPP' THEN SPP_seq.NEXTVAL
WHEN 'SPR' THEN SPR_seq.NEXTVAL
WHEN 'SRL' THEN SRL_seq.NEXTVAL
ELSE 0 END ),6,0) FROM DUAL)) as "ItemID",
...
FROM md_draw d
join draw_catcodes c on d.series = c.series and d.base = c.base
order by lpad(d.series,3,0), lpad(d.base,3,0), lpad(d.suffix,2,0);
有什么建议吗?
编辑:@AlexPoole,你说得对,我删除了包含序列调用的子查询,但仍然得到 ORA-02287: sequence number not allowed here 错误:
SELECT
(CASE d.image WHEN 0 THEN 'NoImage.pdf'
ELSE lower(d.prefix || lpad(d.series,3,0) || lpad(d.base,3,0) || lpad(d.suffix,2,0) || lpad(d.rev,2,0) || '.pdf') END) as "Filename",
c.EngDiscipline as "EngDiscipline",
c.CatCode || '-' || lpad(CASE substr(c.CatCode,0,3)
WHEN 'AEG' THEN AEG_seq.NEXTVAL
WHEN 'ARY' THEN ARY_seq.NEXTVAL
WHEN 'BBR' THEN BBR_seq.NEXTVAL
...
WHEN 'SPP' THEN SPP_seq.NEXTVAL
WHEN 'SPR' THEN SPR_seq.NEXTVAL
WHEN 'SRL' THEN SRL_seq.NEXTVAL
ELSE 0 END,6,'0') as "ItemID",
upper(d.prefix || '-' || lpad(d.series,3,0) || '-' || lpad(d.base,3,0) || '-' || lpad(d.suffix,2,0)) as "LegacyID",
...
FROM md_draw SAMPLE (1) d
join draw_catcodes c on d.series = c.series and d.base = c.base
order by c.ccProgram, lpad(d.series,3,0), lpad(d.base,3,0), lpad(d.suffix,2,0);
【问题讨论】:
您只有一个语句,并且您试图在稍后的同一语句中使用子查询中的 CatCode 的值? 您编辑问题时我没有收到通知,我只是碰巧回来了。为什么你还有一个子查询——那不在我的回答中?这就是导致新错误的原因。您是否看到有关使用分析函数而不是序列的编辑 - 如果您使用的比最初显示的更多,可能会更有用? @AlexPoole,删除子查询,仍然出现同样的错误... 还有所有额外的括号?我用自己的表运行了一个版本,删除了子查询没问题,但我也去掉了括号,我不能 100% 确定哪个清除了 ORA-02287。 【参考方案1】:这相当容易。在 PL/SQL 中,查询要么需要是游标,要么必须选择 into 东西;在此,进入您的绑定变量:
VARIABLE FullCatCode VARCHAR2(7)
exec SELECT CatCode into :FullCatCode from draw_catcodes where series = 123 and base = 158;
SELECT :FullCatCode || '-' || Other stuff... from table_name...
如果您只打算在后面的 SQL 语句中使用它,您也可以使用替换变量,而不是绑定变量:
COLUMN CatCode NEW_VALUE FullCatCode
SELECT CatCode from draw_catcodes where series = 123 and base = 158;
SELECT &FullCatCode || '-' || Other stuff... from table_name...
对于您修改后的问题,这根本不是您想要做的。您试图在同一查询的另一部分引用子查询中的值,而不是稍后在脚本中的单独语句。并且不涉及 PL/SQL。
上述任何一种机制都无法做到这一点;第一个是因为没有 PL/SQL 块来执行 select ... into
,第二个是因为在运行语句之前评估和替换了替换变量 - new_value
直到查询运行后才存在。
你不想要一个子查询,你应该使用一个连接,比如:
SELECT
CASE d.image WHEN 0 THEN 'NoImage.pdf'
ELSE lower(d.prefix || lpad(d.series,3,'0') || lpad(d.base,3,'0') || lpad(d.suffix,2,'0') || lpad(d.rev,2,'0') || '.pdf')
END as "Filename",
c.EngDiscipline as "EngDiscipline",
c.CatCode, -- not sure if you actually want this raw value?
c.CatCode || '-' || lpad(CASE substr(c.CatCode,0,3)
WHEN 'AEG' THEN AEG_seq.NEXTVAL
WHEN 'ARY' THEN ARY_seq.NEXTVAL
WHEN 'BBR' THEN BBR_seq.NEXTVAL
ELSE 0
END,6,'0') as "ItemID",
upper(d.prefix || '-' || lpad(d.series,3,'0') || '-' || lpad(d.base,3,'0') || '-' || lpad(d.suffix,2,'0'))
as "LegacyID",
...
from tablename d
join draw_catcodes c on d.series = c.series and d.base = c.base
where ...
您可以在尝试使用&FullCatCode
的地方直接引用c.CatCode
。
如果序列只存在于此查询并且 ItemId 没有更广泛的意义,您可以使用分析函数来生成 ItemIds:
c.CatCode || '-' ||
lpad(row_number() over (partition by substr(c.CatCode,0,3) order by null),6,'0')
as "ItemID",
ItemId 不会有确定性的顺序,但顺序方法不会;如果需要,您可以修改窗口子句以指定顺序。
【讨论】:
谢谢亚历克斯!更改 SELECT 后,出现以下错误:(EXEC SELECT CatCode into :FullCatCode from draw_catcodes c where d.series = c.series and d.base = c.base)* 第 20 行出现错误:ORA-00907:缺少右括号这个语句在一个更大的 Select 语句中,这个 'Into' 必须在最外面的语句中吗? @BarryPrentiss - 不太确定你的意思。exec
是一个 SQL*Plus 命令,不是 SQL 语句的一部分,所以它不属于那里。 into
需要在最外面的语句中,是的。但目前尚不清楚该 sn-p/子查询在哪里适合更大的查询 - 它是选择列表表达式、内联视图还是连接条件?还是我没有想到的……?
@BarryPrentiss - 根据我认为您正在尝试做的事情进行了更新。每次运行时,ItemID 是否应该从 1 开始,或者每次运行都应该从最后一次停止的地方开始?我试图弄清楚您是否真的需要这些序列,或者您是否只想要一个在查询中唯一的类似序列的后缀。
我根据唯一的序列/碱基对在选择时将 CatCodes 和顺序 ItemIDs 分配给记录,因此每个 CatCodes 都会有自己的序列号集。我会尝试加入,看看我是否可以让它工作......谢谢指针!
是的,但它们是否仅在此查询中相关?每行获取的序列值(即 ItemID)仅在文件中,而不是存储在您的数据库中。我想另一种看待它的方式是——你是否为这个查询创建了序列,如果你再次运行它,你会将序列重置为从 1 开始吗? (我想做的只是看看你是否能在没有序列的情况下得到你想要的结果)以上是关于如何在 PL/SQL 中使用 select 语句为 SQL*Plus 变量赋值?的主要内容,如果未能解决你的问题,请参考以下文章
PL/SQL:, 如何将变量传递给 SELECT 语句并返回所有结果行
在 ORACLE 的 select 语句中从 PL/SQL 调用函数
如何从 oracle pl sql 中的包主体内的 select 语句中捕获特定列