Я пытаюсь получить данные из большого двоичного объекта, используя regexp_substr. Вот как выглядит капля
"select a,b ,upper(c from xyz), d from t1 where xyx;"
Требуемый результат:
t1
Вместо where
в BLOB-объекте это может быть fetch
, order by
или group by
.
Я пытаюсь с
REGEXP_SUBSTR(query_blob,'FROM\s(.*?)\s(WHERE|FETCH|ORDER|GROUP)',1,1,'i',1)
но это дает мне результат как
xyz), d from t1
Может ли кто-нибудь помочь мне получить имя таблицы между from и (где или получить, или сгруппировать, или упорядочить).
Да, это вложено из
@Littlefoot Не нужно удалять, если вы сделаете оговорку.
Если предположить, что это простой запрос Oracle SQL (т. е. без вложенных/коррелированных подзапросов), вы можете использовать регулярное выражение ([a-z][a-z0-9_$#]*|"[^"]+")
только для сопоставления символов в идентификаторе без кавычек или в кавычках (если вы используете другие языки, которые используют другие идентификаторы в кавычках, например квадратные скобки или обратные кавычки, вы также можете добавить их) на основе правил именования объектов базы данных:
Идентификаторы без кавычек должны начинаться с буквенного символа из набора символов вашей базы данных. Идентификаторы в кавычках могут начинаться с любого символа.
Идентификаторы без кавычек могут содержать только буквенно-цифровые символы из набора символов вашей базы данных, а также знак подчеркивания (_), знак доллара ($) и знак решетки (#). Ссылки на базы данных также могут содержать точки (.) и знаки «at» (@). Oracle настоятельно не рекомендует использовать $ и # в идентификаторах без кавычек.
Идентификаторы в кавычках могут содержать любые символы и знаки препинания, а также пробелы. Однако ни идентификаторы в кавычках, ни идентификаторы без кавычек не могут содержать двойные кавычки или нулевой символ (\0).
И следуйте за ним проверкой дополнительных предложений фильтра/агрегирования (также может быть псевдоним [которому в других диалектах SQL, отличных от Oracle, может предшествовать ключевое слово AS
] и/или предложение HAVING
без предложения GROUP BY
или без фильтров) .
Так:
SELECT REGEXP_SUBSTR(
query_blob,
'FROM\s+([a-z][a-z0-9_$#]*|"[^"]+")' -- FROM clause
|| '(\s+([a-z][a-z0-9_$#]*|"[^"]+"))?' -- FROM Alias
|| '\s*(\s(WHERE|FETCH|ORDER|GROUP|HAVING)|$)', -- Filter/Aggregation Clauses
1,
1,
'i',
1
) AS frm
FROM table_name;
Что для вашего примера данных:
CREATE TABLE table_name (query_blob) AS
SELECT 'select a,b ,upper(c from xyz), d from t1 where xyx;' FROM DUAL
Выходы:
Если вы хотите еще больше усложнить выражение, то:
SELECT REGEXP_SUBSTR(
query_blob,
'FROM\s+' -- FROM clause
|| '('
|| '([a-z][a-z0-9_$#]*|"[^"]+")' -- Identifier
|| '(\(\s*' -- Start Function call
|| '(' -- Start optional group
|| '[a-z][a-z0-9_$#]*' -- Unquoted identifier
|| '|"[^"]+"' -- Or quoted identifier
|| '|''([^'']|'''')*''' -- Or string literal
|| ')?\s*' -- End optional group
|| '(' -- Start zero-or-more group
|| ',\s*[a-z][a-z0-9_$#]*' -- Unquoted identifier
|| '|,\s*"[^"]+"' -- Or quoted identifier
|| '|,\s*''([^'']|'''')*''' -- Or string literal
|| ')*' -- End zero-or-more group
|| '\s*\))?' -- End Function call
|| ')'
|| '(\s+([a-z][a-z0-9_$#]*|"[^"]+"))?' -- FROM Alias
|| '\s*(\s(WHERE|FETCH|ORDER|GROUP|HAVING)|$)', -- Filter/Aggregation Clauses
1,
1,
'i',
1
) AS frm
FROM table_name;
Что для примера данных:
CREATE TABLE table_name (query_blob) AS
SELECT 'select a,b ,upper(c from xyz), d from t1 where xyx;' FROM DUAL UNION ALL
SELECT 'select a,b ,upper(c from xyz), d from abc(''xyz'') where xyx;' FROM DUAL UNION ALL
SELECT 'select a,b ,upper(c from xyz), d from abc(def) where xyx;' FROM DUAL UNION ALL
SELECT 'select a,b ,upper(c from xyz), d from abc( def, ''ghi'', jkl ) where xyx;' FROM DUAL
Выходы:
Или, если вам нужно простое выражение, которое может быть решением на 90%:
SELECT REGEXP_SUBSTR(
query_blob,
'FROM\s+' -- FROM clause
|| '(\S+)' -- Identifier
|| '(\s+(\S+))?' -- FROM Alias
|| '\s*(\s(WHERE|FETCH|ORDER|GROUP|HAVING)|$)', -- Filter/Aggregation Clauses
1,
1,
'i',
1
) AS frm
FROM table_name;
Что для тех же данных примера соответствует первым трем строкам, но не последней (поскольку внутри скобок вызова функции есть пробелы).
Не могли бы вы объяснить часть регулярного выражения.
@SnehaS [a-z]
— буквенный символ, который соответствует первому символу идентификатора без кавычек, [a-z0-9_$#]*
соответствует нулю или более следующих символов в идентификаторе без кавычек (см. документацию, указанную в ответе), который в совокупности соответствует идентификатор без кавычек, а "[^"]+"
соответствует идентификатору в кавычках. Остальное объясняется в ответе. Что еще вам нужно было объяснить?
почему мы используем || в части регулярного выражения? Кроме того, если мое предложение from похоже на from abc('xyx')
, получу ли я abc('xyx')
в качестве результата?
@SnehaS abc('xyz')
не является допустимым идентификатором Oracle. Если у вас есть функция abc
, которая генерирует выражение коллекции таблиц, тогда abc('xyz')
будет допустимо, но как только вы начнете вдаваться в эти детали, у вас не будет «простого» оператора Oracle SQL, и вы начнете доходить до того момента, когда вам нужно написать правильный синтаксический анализатор или же определите правила того, какое значение является приемлемым для соответствия в предложении FROM
(которое не описывает ваш вопрос), а затем вы сможете выяснить, способен ли синтаксис регулярных выражений обрабатывать эти правила.
||
позволяет разделить регулярное выражение на разные части и помогает логически организовать код с помощью встроенных комментариев.
@M10 Спасибо за решение и объяснение. Кажется, мне нужны сценарии, в которых abc('xyx')
действителен и его нужно получить.
Поскольку вы ищете текст между последними вхождениями предопределенных слов, если вы хотите сделать это без использования регулярного выражения, вот вариант, использующий только стандартные текстовые функции:
WITH -- cte acting as your sample table data
texts (ID, TEXT) AS
( Select 1, '"select a,b ,upper(c from xyz), d from t1 where xyx;"' From Dual Union All
Select 2, '"select a,b,d,e from t22 fetch last one;"' From Dual Union All
Select 3, '"select a,upper(c from xyz fetch 1 or 2 from tbl), d from t333 order by a;"' From Dual Union All
Select 4, '"select a,b ,upper(c from xyz group by c), d from t4t5t6 group by x,y;"' From Dual
),
... вы можете создать cte для определения комбинаций слов-рамок
-- cte defining border words - notice space character after word 1 and before word 2
words (WORD_1, WORD_2) AS
( Select 'FROM ', ' WHERE' From Dual Union All
Select 'FROM ', ' FETCH' From Dual Union All
Select 'FROM ', ' ORDER BY' From Dual Union All
Select 'FROM ', ' GROUP BY' From Dual
),
... еще один вызов, чтобы получить последние позиции слов-рамок в тексте
-- cte geting last position of words
last_occurrences AS
( Select t.ID, w.WORD_1, w.WORD_2,
Length(t.TEXT) - InStr(Upper(REVERSE(t.TEXT)), REVERSE(w.WORD_1)) + 1 "P1",
InStr(Upper(t.TEXT), w.WORD_2, Length(t.TEXT) - InStr(Upper(REVERSE(t.TEXT)), REVERSE(w.WORD_1)) + 1, 1) "P2"
From texts t
Inner Join words w ON( InStr(Upper(t.TEXT), w.WORD_1) > 0 And
InStr(Upper(t.TEXT), w.WORD_1) > 0
)
Where InStr(Upper(t.TEXT), w.WORD_2, Length(t.TEXT) - InStr(Upper(REVERSE(t.TEXT)), REVERSE(w.WORD_1)) + 1, 1) - 1 > 0
)
... используйте позиции, чтобы получить подстроку...
-- M a i n S Q L :
Select t.ID, t.TEXT,
SubStr( t.TEXT, o.P1, o.P2 - o.P1 ) "TBL"
From texts t
Inner Join last_occurrences o ON(o.ID = t.ID)
/* R e s u l t :
ID TEXT TBL
---------- --------------------------------------------------------------------------- ------------------
4 "select a,b ,upper(c from xyz group by c), d from t4t5t6 group by x,y;" t4t5t6
3 "select a,upper(c from xyz fetch 1 or 2 from tbl), d from t333 order by a;" t333
2 "select a,b,d,e from t22 fetch last one;" t22
1 "select a,b ,upper(c from xyz), d from t1 where xyx;" t1 */
Если вы присмотритесь, вы увидите, что ключевое слово
from
также появляется внутри вызова функцииupper()
. Regex здесь не очень подходит, потому что у вас есть вложенный контент. В общем, вам нужно будет использовать синтаксический анализатор SQL.