I have 2 tables in teradata. TableA and TableB
TableA has 2 columns as shown below
Table A
Column 1 --> Databasename
Column 2 --> Tablename
TableB has multiple columns including a text column.
I want to search databasename.tablename from Table A in Table B's Text column. The like operator cannot be used as there are around 2000 distinct table names in Table A. I have tried position join to do this as shown below but the query is extremely long running with high PJI and i had to manually abort it
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;
Is there an alternate way to do the above string search. Kindly share the SQL.
Thanks
REGEXP_SIMILAR:
One option is to use REGEXP_SIMILAR()
which will be more precise than LIKE
. I'm not sure if will be quicker, but it's worth a shot:
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:
Here's where I was aiming with that strtok_split_to_tables
comment. Basically you split your sql in TABLEB
into words (splitting by space and ;
characters). That will generate a row for every word.
From that list you just keep words that contain a period in them (like databasename.tablename
).
Then you can do your join on that between TABLEB and 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; |
+-----+------+---+-----------------------------------------------------------------------------+
This isn't going to be super fast since we have to do word splitting, but it will definitely get the job done.
If it's for extracting a single tablename from CREATE TABLE AS you can apply Regular Expressions for table/DB name:
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
If the database name is missing you can COALESCE QryLogV.DefaultDatabase
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.