I've recently shifted from knowing MSSQL very well to using PLSQL. One of the really useful sets of scripts I have in MSSQL is for understanding the structures of databases where there is no documentation or advice available (only too often, sadly). One of these tools is a script to search a database for a specific value (e.g. an ID). I'm trying to replicate that script for PLSQL. The script I'm trying to develop here is to search for an integer value.
The approach I'm taking is to create a temp table of schema/table/columns of numeric columns and then to create dynamic SQL to count how many rows there are in each instance that contain the value that I'm searching for. Finally I select the rows where the number of matches are greater than zero. I'm having difficulty with declaring a temp table within a script. I'm using SQL Developer. The script I have so far is below.
DECLARE cSQL VARCHAR2(1000);
iSearchValue INT;
CREATE PRIVATE TEMPORARY TABLE ORA$PTT_COL_MATCHES
(
SCHEMA_NAME VARCHAR2(100),
TABLE_NAME VARCHAR2(100),
COLUMN_NAME VARCHAR2(100),
DATA_TYPE VARCHAR2(100),
MATCH_COUNT INT
)
ON COMMIT PRESERVE DEFINITION;
BEGIN
iSearchValue := 237001;
INSERT INTO ORA$PTT_COL_MATCHES
(SCHEMA_NAME,
TABLE_NAME,
COLUMN_NAME,
DATA_TYPE,
MATCH_COUNT)
SELECT col.owner as schema_name,
col.table_name,
col.column_name,
col.data_type,
0
FROM sys.all_tab_columns col
INNER JOIN sys.all_tables t ON col.owner = t.owner
AND col.table_name = t.table_name
WHERE col.owner NOT IN ('SYS', 'SYSTEM');
--AND col.DATA_TYPE IN ('INT', 'NUMBER', 'FLOAT', 'LONG')
FOR rec IN
(SELECT *
FROM ORA$PTT_COL_MATCHES)
LOOP
cSQL = 'UPDATE ' || ORA$PTT_COL_MATCHES || '
SET MATCH_COUNT = (SELECT COUNT(*) FROM ' || rec.SCHEMA_NAME || '.' || rec.TABLE_NAME || ' WHERE ' || rec.COLUMN_NAME || ' = ' || TO_CHAR(iSearchValue) || ')
WHERE SCHEMA_NAME = ''' || rec.SCHEMA_NAME || '''
AND TABLE_NAME = ''' || rec.TABLE_NAME || '''';
EXECUTE IMMEDIATE cSQL;
END LOOP;
SELECT *
FROM ORA$PTT_COL_MATCHES
WHERE MATCH_COUNT > 0;
END;
The error I'm receiving is:
Error report -
ORA-06550: line 4, column 1:
PLS-00103: Encountered the symbol "CREATE" when expecting one of the following:
begin function pragma procedure subtype type <an identifier>
<a double-quoted delimited-identifier> current cursor delete
exists prior
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
In SQL Developer I'm manually selecting the entire script to execute. I understand that the above error indicates that I cannot using CREATE at that point in the script. My questions are:
- Why can't I create a temp table there, and
- Where can I create it as inside the BEGIN-END block doesn't work either?
- Bonus question: Is there a better way to do this in PLSQL?
CREATE TABLEis a DDL statement and you cannot use DDL statements in PL/SQL. You either need to do it before the PL/SQL block or usingEXECUTE IMMEDIATE(which will create an SQL scope within the PL/SQL block). Similarly, you cannot useSELECTstatement on its own in a PL/SQL block; you either wantSELECT ... [BULK COLLECT] INTO ...or to use a cursor with theSELECT.You can (and should) also use bind variables wherever possible in dynamic SQL statements to minimise the risk of SQL injection attacks.
fiddle