我有一个表,将SQL查询存储在字符串列中,如下所示。 (我在下面给出了3个示例行)
select sql_query_part_1_tx from Table1;
sql_query_part_1_tx
--------------------------------------------------------
SELECT SUM(BAL_AM) FROM SCH.DERHCE03 WHERE 1=1 AND HIRHCC04<>'US' AND HIRHCE01 IN ('TDCD','TDOA','IRATD') AND HIREG039 IN ((660),(661),(604)) AND HIREG234 <> 345 ;
SELECT SUM(BAL_AM) FROM SCH.DEFD1520 WHERE 1=1 AND HIRHCV04='Y' AND HIRHCC04<>'US' AND HIRHCN17='FDIC' AND HIFD1516<>'Y' AND HIFD1527='FDIC';
SELECT SUM(OUTSTANDING_AM) FROM SCH.DEFD1520 WHERE 1=1 AND HIRHCV04='Y' AND HIRHCC04<>'US' AND HIRHCN17='FDIC' AND HIFD1516='Y';
因此,列sql_query_part_1_tx以字符串格式存储SQL查询。我的要求是读取这些查询并动态执行它们,并将结果存储在另一个表中。
在上面存储的查询中,挑战在于哪里存在<>(不等于)条件,它不获取具有NULL值的行(这是预期的)。但是我还需要具有NULL值的行。
例如:
SELECT SUM(BAL_AM) FROM SCH.DERHCE03 WHERE 1=1 AND HIRHCC04<>'US' AND HIRHCE01 IN ('TDCD','TDOA','IRATD') AND HIREG039 IN ((660),(661),(604)) AND HIREG234 <> 345 ;
在上面的查询字符串中,条件为HIRHCC04<>'US'
。因此它将不会使用HIRHCC04 IS NULL
来获取记录。
我想像下面一样更改上面的查询字符串,在条件中找到NVL
的任何地方应用<>
函数。
SELECT SUM(BAL_AM) FROM SCH.DERHCE03 WHERE 1=1 AND NVL(HIRHCC04,'###')<>'US' AND HIRHCE01 IN ('TDCD','TDOA','IRATD') AND HIREG039 IN ((660),(661),(604)) AND NVL(HIREG234,999999) <> 345 ;
这样我就可以获得NULL
和'HIRHCC04'
的具有'HIREG234'
值的行。
因此,我想更新我的表,该表使用NVL
或COALESCE
选项存储这些查询字符串。我希望我清楚。
注意:请注意,我们需要考虑数据类型和“禁止输入”条件。
答案 0 :(得分:1)
以下查询应该可以解决问题:
SELECT REGEXP_REPLACE(sql_query_part_1_tx, '(\w+)\s*<>', 'COALESCE(\1, 9999) <>')
FROM mytable;
正则表达式说明:
'(\w+)\s*<>'
捕获<>
左侧的单词(即连续的字母数字和下划线字符),并在两者之间使用可选的空格序列'COALESCE(\1, 9999) <>'
:将匹配的字符串替换为捕获的单词(列名),称为'\ 1'
此 demo on DB fiddle 及其示例数据将返回:
| REGEXP_REPLACE(SQL_QUERY_PART_1_TX,'(\W+)\S*<>','COALESCE(\1,9999)<>') | | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | SELECT SUM(BAL_AM) FROM SCH.DERHCE03 WHERE 1=1 AND COALESCE(HIRHCC04, 9999)<>'US' AND HIRHCE01 IN ('TDCD','TDOA','IRATD') AND HIREG039 IN ((660),(661),(604)) AND COALESCE(HIREG234, 9999)<> 345 ; | | SELECT SUM(BAL_AM) FROM SCH.DEFD1520 WHERE 1=1 AND HIRHCV04='Y' AND COALESCE(HIRHCC04, 9999)<>'US' AND HIRHCN17='FDIC' AND COALESCE(HIFD1516, 9999)<>'Y' AND HIFD1527='FDIC'; | | SELECT SUM(OUTSTANDING_AM) FROM SCH.DEFD1520 WHERE 1=1 AND HIRHCV04='Y' AND COALESCE(HIRHCC04, 9999)<>'US' AND HIRHCN17='FDIC' AND HIFD1516='Y'; |
顺便说一句,让我建议对您的替换逻辑进行优化。
此:
COALESCE(HIRHCC04, 9999)<>'US'
通常拼写更好:
(HIRHCC04 IS NULL OR HIRHCC04 <> 'US')
第二个表达式更明确,更高效,因为它将很高兴地使用要过滤的列上的现有索引(而第一个表达式则不会)。当要检查的列不是数字时,还可以避免潜在的转换问题。
可以使用以下正则表达式生成这些表达式:
SELECT REGEXP_REPLACE(
sql_query_part_1_tx,
'(\w+)\s*<>\s*''(\w+)''',
'(\1 IS NULL OR \1 <> ''\2'')'
)
FROM mytable;
| REGEXP_REPLACE(SQL_QUERY_PART_1_TX,'(\W+)\S*<>\S*''(\W+)''','(\1ISNULLOR\1<>''\2'')') | | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | SELECT SUM(BAL_AM) FROM SCH.DERHCE03 WHERE 1=1 AND (HIRHCC04 IS NULL OR HIRHCC04 <> 'US') AND HIRHCE01 IN ('TDCD','TDOA','IRATD') AND HIREG039 IN ((660),(661),(604)) AND HIREG234 <> 345 ; | | SELECT SUM(BAL_AM) FROM SCH.DEFD1520 WHERE 1=1 AND HIRHCV04='Y' AND (HIRHCC04 IS NULL OR HIRHCC04 <> 'US') AND HIRHCN17='FDIC' AND (HIFD1516 IS NULL OR HIFD1516 <> 'Y') AND HIFD1527='FDIC'; | | SELECT SUM(OUTSTANDING_AM) FROM SCH.DEFD1520 WHERE 1=1 AND HIRHCV04='Y' AND (HIRHCC04 IS NULL OR HIRHCC04 <> 'US') AND HIRHCN17='FDIC' AND HIFD1516='Y'; |
更新
这是一个更新的查询,还将处理NOT IN
子句,并在<>
运算符(以及NOT IN
列表的左侧)中允许数字和字符串:>
SELECT REGEXP_REPLACE(
REGEXP_REPLACE(sql_query_part_1_tx, '(\w+)\s*<>\s*(''*\w+''*)', '(\1 IS NULL OR \1 <> \2)'),
'(\w+)\s*NOT IN\s*(\([^)]+\))',
'(\1 IS NULL OR \1 NOT IN \2)'
) FROM mytable;
| REGEXP_REPLACE(REGEXP_REPLACE(SQL_QUERY_PART_1_TX,'(\W+)\S*<>\S*(''*\W+''*)','(\1ISNULLOR\1<>\2)'),'(\W+)\S*NOTIN\S*(\([^)]+\))','(\1ISNULLOR\1NOTIN\2)') | | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | SELECT SUM(BAL_AM) FROM SCH.DERHCE03 WHERE 1=1 AND (HIRHCC04 IS NULL OR HIRHCC04 <> 'US') AND (HIRHCE01 IS NULL OR HIRHCE01 NOT IN ('TDCD','TDOA','IRATD')) AND HIREG039 IN ((660),(661),(604)) AND (HIREG234 IS NULL OR HIREG234 <> 345) ; | | SELECT SUM(BAL_AM) FROM SCH.DEFD1520 WHERE 1=1 AND HIRHCV04='Y' AND (HIRHCC04 IS NULL OR HIRHCC04 <> 'US') AND HIRHCN17='FDIC' AND (HIFD1516 IS NULL OR HIFD1516 <> 'Y') AND HIFD1527='FDIC'; | | SELECT SUM(OUTSTANDING_AM) FROM SCH.DEFD1520 WHERE 1=1 AND HIRHCV04='Y' AND (HIRHCC04 IS NULL OR HIRHCC04 <> 'US') AND HIRHCN17='FDIC' AND HIFD1516='Y'; |
答案 1 :(得分:0)
这是该问题的原始版本:
在上面存储的查询中,挑战在于哪里存在<>(不等于)条件,它不获取具有NULL值的行(这是预期的)。但是我还需要带有NULL值的行。
这真是令人讨厌。我不能说我真的宽恕了。您的查询的书写方式不一致(在一个地方<>
周围有空格,在另一个地方没有空格)。我怀疑可能比存储此类原始SQL更好地解决您的总体问题。
也就是说,我很高兴您遇到了问题。这很棘手,因为您同时拥有字符串和数字,这使事情变得棘手。你可能有约会。以下内容不适用于日期。但是,regexp_replace()
可以做一些事情:
select regexp_replace(regexp_replace(q, ' ([^ <]+) ?<> ?''', ' NVL(\1, ''XXX'') <> '''), ' ([^ <)]+) ?<> ?[^'']', ' NVL(\1, -1) <> ')
from (select 'SELECT SUM(BAL_AM) FROM SCH.DERHCE03 WHERE 1=1 AND HIRHCC04<>''US'' AND HIRHCE01 IN (''TDCD'',''TDOA'',''IRATD'') AND HIREG039 IN ((660),(661),(604)) AND HIREG234 <> 345 ;' as q
from dual) x
注意:这几乎是假设<>
之前的引用是单列引用,而不是更复杂的表达式。