Строка Teradata / текстовый поиск - PullRequest
0 голосов
/ 24 марта 2020

у меня 2 таблицы в терадате. Таблица A и Таблица B

Таблица A имеет 2 столбца, как показано ниже

Таблица A

Столбец 1 -> Имя базы данных

Столбец 2 -> Имя таблицы

В TableB есть несколько столбцов, включая текстовый столбец.

Я хочу найти databasename.tablename из таблицы A в столбце Text таблицы B. Оператор like не может быть использован, поскольку в Таблице A имеется около 2000 различных имен таблиц. Я пытался выполнить позиционное соединение, чтобы сделать это, как показано ниже, но запрос выполняется очень долго с высоким PJI, и мне пришлось вручную прервать его

select distinct a.Tablename ,b.text
from TableA a
inner join TableB b
on position(Trim(b.Text) in Trim('a.Databasename.'||a.tablename))>0
where b.theDate between add_months(date,-6) and date

UNION ALL

select distinct a.Tablename ,b.text
from TableA a
inner join TableB b
on position (Trim('a.Databasename.'||a.tablename) in Trim(b.Text))  >0
where b.theDate between add_months(date,-6) and date;

Есть ли альтернативный способ поиска вышеуказанной строки. Пожалуйста, поделитесь SQL.

Спасибо

Ответы [ 2 ]

0 голосов
/ 25 марта 2020

Если это для извлечения одного имени таблицы из CREATE TABLE AS, вы можете применять регулярные выражения для имени таблицы / БД:

RegExp_Substr(SqlTextInfo, 'AS\s+?(.*?[.])?\K.+?\s+?(?=WITH\s)',1,1,'i') AS TableName
RegExp_Substr(SqlTextInfo, 'AS\s+?\K.*?(?=[.](.+?\s+)?WITH\s)',1,1,'i') AS DatabaseName

Если имя базы данных отсутствует, вы можете COALESCE QryLogV.DefaultDatabase

0 голосов
/ 24 марта 2020

REGEXP_SIMILAR:

Один из вариантов - использовать REGEXP_SIMILAR(), который будет более точным, чем LIKE. Я не уверен, что будет быстрее, но это стоит попробовать:

CREATE MULTISET VOLATILE TABLE TABLEA 
(databasename varchar(30), tablename varchar(30)) 
PRIMARY INDEX (databasename, tablename) ON COMMIT PRESERVE ROWS;

INSERT INTO TABLEA VALUES ('dba','tbla');
INSERT INTO TABLEA VALUES ('dba','tblb');
INSERT INTO TABLEA VALUES ('dbb','tbla');

CREATE MULTISET VOLATILE TABLE TABLEB 
(id int, sqlqry VARCHAR(5000)) 
ON COMMIT PRESERVE ROWS;

INSERT INTO TABLEB VALUES (1, 'SELECT * FROM dba.tbla;');
INSERT INTO TABLEB VALUES (2, 'SELECT smoecolumn FROM dba.tblb INNER JOIN dba.tbla ON foo = bar WHERe 1=1;');
INSERT INTO TABLEB VALUES (3, 'SELECT * FROM dbb.tbla WHERE foo=bar');

SELECT *
FROM TABLEA
    INNER JOIN TABLEB
        ON REGEXP_SIMILAR(TABLEB.sqlqry, '^.*' || TABLEA.databasename || '\.' || TABLEA.tablename || '.*$', 'i') = 1;

+-----+------+---+-----------------------------------------------------------------------------+
| dbb | tbla | 3 | SELECT * FROM dbb.tbla WHERE foo=bar                                        |
| dba | tbla | 2 | SELECT smoecolumn FROM dba.tblb INNER JOIN dba.tbla ON foo = bar WHERe 1=1; |
| dba | tbla | 1 | SELECT * FROM dba.tbla;                                                     |
| dba | tblb | 2 | SELECT smoecolumn FROM dba.tblb INNER JOIN dba.tbla ON foo = bar WHERe 1=1; |
+-----+------+---+-----------------------------------------------------------------------------+

STRTOK_SPLIT_TO_TABLE:

Вот где я целился с этим strtok_split_to_tables комментарий. По сути, вы разбиваете sql в TABLEB на слова (разделение по пробелам и ; символам). Это создаст строку для каждого слова.

Из этого списка вы просто сохраняете слова, содержащие в себе точку (например, databasename.tablename).

Затем вы можете объединиться между TABLEB и TABLEA:

CREATE MULTISET VOLATILE TABLE TABLEA 
(databasename varchar(30), tablename varchar(30)) 
PRIMARY INDEX (databasename, tablename) ON COMMIT PRESERVE ROWS;

INSERT INTO TABLEA VALUES ('dba','tbla');
INSERT INTO TABLEA VALUES ('dba','tblb');
INSERT INTO TABLEA VALUES ('dbb','tbla');

CREATE MULTISET VOLATILE TABLE TABLEB 
(id int, sqlqry VARCHAR(5000)) 
ON COMMIT PRESERVE ROWS;

INSERT INTO TABLEB VALUES (1, 'SELECT * FROM dba.tbla;');
INSERT INTO TABLEB VALUES (2, 'SELECT smoecolumn FROM dba.tblb INNER JOIN dba.tbla ON foo = bar WHERe 1=1;');
INSERT INTO TABLEB VALUES (3, 'SELECT * FROM dbb.tbla WHERE foo=bar');

WITH sqlwords AS
(
    SELECT tablebid, sqlwordnum, sqlword
    FROM TABLE (strtok_split_to_table(TABLEB.id, TABLEB.sqlqry, ' ;')
    RETURNS (tablebid integer, sqlwordnum integer, sqlword varchar(100)character set unicode) ) as sqlwordsplitter
    WHERE sqlwordsplitter.sqlword like '%.%'
)
SELECT TABLEA.*, TABLEB.*
FROM TABLEA
    INNER JOIN sqlwords
        ON TABLEA.databasename = strtok(sqlwords.sqlword, '.', 1)
            AND TABLEA.tablename = strtok(sqlwords.sqlword, '.', 2)
    INNER JOIN TABLEB
        ON sqlwords.tablebid = TABLEB.id;


+-----+------+---+-----------------------------------------------------------------------------+
| dbb | tbla | 3 | SELECT * FROM dbb.tbla WHERE foo=bar                                        |
| dba | tbla | 2 | SELECT smoecolumn FROM dba.tblb INNER JOIN dba.tbla ON foo = bar WHERe 1=1; |
| dba | tbla | 1 | SELECT * FROM dba.tbla;                                                     |
| dba | tblb | 2 | SELECT smoecolumn FROM dba.tblb INNER JOIN dba.tbla ON foo = bar WHERe 1=1; |
+-----+------+---+-----------------------------------------------------------------------------+

Это не будет очень быстрым, так как нам придется разбивать слова, но это определенно получится работа сделана

...