Reputation: 2906
I do not have sufficient privileges to use a CREATE
statement, I can only SELECT
. I have a script that has three distinct parts and calculations that need to run and each one references the same complicated WITH
statement selection that redundantly clutters the code and is a pain to maintain in three separate locations.
I have tried creating temp tables and views, but again, privileges do not support. Is there a way using either SQL or PL/SQL syntax to define my WITH
statement ONCE without using CREATE, and then reference it like I would any other table? Example:
--Define the temp table
WITH tempview AS (SELECT .... FROM ...);
--First query
SELECT ... FROM tempview;
/
--Second query
SELECT ... FROM tempview;
/
--Third query
SELECT ... FROM tempview;
/
Upvotes: 1
Views: 1146
Reputation: 60262
Another trick with SQL*Plus is to import code from a second SQL script. You can do this with the @
command (making sure to put the @
at the very start of a line), e.g.:
tempview.sql
WITH tempview AS (SELECT .... FROM ...)
(notice there is no ending semicolon ;
here, and make sure you either don't have a blank line at the end of the file or set sqlblanklines on
)
main.sql
--First query
@tempview.sql
SELECT ... FROM tempview
/
--Second query
@tempview.sql
SELECT ... FROM tempview
/
--Third query
@tempview.sql
SELECT ... FROM tempview
/
Upvotes: 2
Reputation: 191265
Getting the correct permissions and creating permanent objects is the best approach. It sounds like this view would only be used in a single script, which doesn't necessarily make it any less valid to create it, but you might find it harder to justify depending on your DBA and policies. It's certainly worth trying that approach, as @DCookie suggested.
If that fails then there may be hacky workarounds, depending on the client you will run this script in.
For instance, in SQL*Plus it's possible to abuse substitution variables to get something close to what you describe. This uses the define
command to create a substitution variable that contains the 'view' query, and then uses that variable inside a WITH
clause. (You can't replace the entire with
like this, but it's maybe clearer like this anyway). I'm used a trivial dummy query:
define tempview_query = 'SELECT * -
FROM dual -
UNION ALL -
SELECT * -
FROM dual'
WITH tempview AS (&tempview_query)
SELECT * FROM tempview;
WITH tempview AS (&tempview_query)
SELECT * FROM tempview;
When the script is run the output produced is:
D
-
X
X
2 rows selected.
D
-
X
X
2 rows selected.
I've also executed set verify off
to hide the substitutions, but turning it on might be instructive to see what's happening.
Notice the dashes at the end of each line of the query; that's the continuation character, and as the define
docs mention:
If the value of a defined variable extends over multiple lines (using the SQL*Plus command continuation character), SQL*Plus replaces each continuation character and carriage return with a space.
so the 'new' query shown by set verify on
will have your entire view query on a single line (if you display it). It's feasible that with a long enough query you'd hit some line length limit but hopefully you won't reach that point (except you did; see below).
You can do the same thing in SQL Developer, but there the continuation needs to use two dashes, so:
define tempview_query = 'SELECT * --
FROM dual --
UNION ALL --
SELECT * --
FROM dual'
except it isn't quite the same as the continuation in SQL*Plus; here the define has to end with a dash, but it is not replaced in the way the SQL*Plus docs describe - so with a single dash the define works but the query ends up invalid. (At least in 4.2.0; possibly a bug...) By using two dashes the multi-line define still works, the dashes remain part of the query, but they're treated as comment markers; so they make the substituted query look odd (again, if you display it) but don't stop it working. You won't notice with set verify off
unless someone looks in v$sql
.
If your query exceeds 240 characters - which is rather likely unless it's trivial enough to repeat anyway - you'll hit something like:
string beginning "'SELECT * ..." is too long. maximum size is 240 characters.
Both SQL*Plus and SQL Developer allow you to set a substitution variable from a query, using the column ... new_value
command:
column tempalias new_value tempview_query
set termout off
select q'[SELECT *
FROM dual
UNION ALL
SELECT *
FROM dual]'
FROM dual;
set termout on
The query selects the text of your view query as a string; I've used the alternative quoting mechanism, with []
as the delimiters, so you don't have to escape any single quotes in the view query. (You need to pick a delimiter that can't appear in the query too, of course). Also note that you don't need the line continuation character any more.
The text literal that query generates is aliased as tempalias
. The column
command sets the tempview_query
substitution variable to whatever that aliased column expression contains. Using the substitution variable is then the same as in the previous examples.
WITH tempview AS (&tempview_query)
SELECT * FROM tempview;
The set termout
lines just hide that generating query; you can temporarily omit the off
line to see what the query produces, and that it does exactly match the view query you expected.
Other clients might have similar mechanisms, but those are the only two I'm really familiar with. I should probably also reiterate that this is a bit of a hack, and not something I'd necessarily recommend...
Upvotes: 3