I have a variable date_from that I can use in my queries:
define date_from = '01.11.2019';
Is it possible to define a new variable as a result of a query? The following statement doesn't work:
define month_from = (select month_yyyymm from t_calendar where date_orig = '&date_from');
I'm using Oracle SQL Developer and I don't want to go into PL/SQL.
It is not possible to do what you want, directly. Note also that substitution variables (those created / assigned to with the define command and called with a leading &) are a SQL*Plus concept; they are pre-processed by the client software (in your case SQL Developer, which understands and honors most of, even though not all of, SQL*Plus).
You can do almost that, though, with the SQL*Plus option new_value to the column command. It goes something like this (not tested since you didn't provide sample data):
define date_from = '01.11.2019'
column month_yyyymm new_value month_from
select month_yyyymm from t_calendar where date_orig = '&date_from';
This is it - at this point the variable month_from stores the value of month_yyyymm returned by your query. Note that the first two commands are SQL*Plus (scripting) commands; only the last statement, the select, is ever seen by the database itself.
Related
it comes to me that sometimes parameterized query are not working in order by clause?
I have tried mysql; postgres; C#;
e.g.:
php+mysql
$stmt = $conn->prepare("SELECT id, name FROM user order by ? desc");
$stmt->bind_param("s", $orderby);
$orderby = "name";
$stmt->execute();
The order by get ignored
Postgres:
See this one https://github.com/brianc/node-postgres/issues/300
.net+mssql:
See this "Order By" using a parameter for the column name
Is there a standard reference for this situation documented somewhere? And on what platform that Parameterize does not work with ORDER BY?
you bind the string value 'name' to the parameter in the sql. That means that for each row processed, the SQL will see the same string, namely 'name'.
The point is that 'name' is not interpreted as the Literal name which matches the column name, but a VARCHAR value 'name' which has been set or bound to a replacement variable ?.
In this case, if you have a variable ORDER BY clause, you would have two (or more) versions of your SQL, which you can select with a regular if / then / else.
Another way is to concatenate the sorting column in your string directly rather than using bind variables. I would STRONGLY suggest against as this lays the foundation work for future SQL Injection. Either way, if you concatenate a variable input string to your SQL, then make sure it is sufficiently sanitized and checked to avoid issues.
Concatenation in PHP would be something simple like this:
$orderby = "name";
$stmt = $conn->prepare("SELECT id, name FROM user order by ".$orderby." desc");
$stmt->execute();
See also PHP - concatenate or directly insert variables in string (had to correct, used initially a syntax that only worked for the PHP echo command).
All the other Implementing Languages (C#, Java, etc) combined with any database (oracle, MySQL, TSQL, etc) would face same issues and solutions: You will have to make the distinction between bind variables and literals in your SQL.
If you still want to use a bind variable - there is a way, but you would have to modify your sql as follows:
SELECT id, name FROM user
ORDER BY CASE ? WHEN 'name' THEN name WHEN 'id' THEN id ELSE NULL END
Actually good thinking by you (in your comment) to still use bind variables somehow. Now I do not have the issue with SQL Injection anymore either. However, now you need to account for every possible sorting that can happen, and have that coded in your SQL instead.
The placeholders in prepared statements are for values, not parameters for ORDER BY or for column names. If you wish to dynamically inject an ORDER BY condition I suggest using concatenation in whatever language you are using, PHP in your case:
$orderByCondition = "name";
$stmt = $conn->prepare("SELECT id, name FROM user order by " . $orderByCondition . " desc");
$stmt->execute();
Of course, since you are not injecting input directly from the user you don't actually need to use a prepared statement.
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;
/
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...
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
/
I'm reading sql code which has a line that looks like this:
SELECT INTO _user tag FROM login.user WHERE id = util.uuid_to_int(_user_id)::oid;
What exactly does this do? The usual way to use SELECT INTO requires specifying the columns to select after the SELECT token, e.g.
SELECT * INTO _my_new_table WHERE ...;
The database is postgresql.
This line must appear inside of a PL/pgSQL function. In that context the value from column tag is assigned to variable _user.
According to the documentation:
Tip: Note that this interpretation of SELECT with INTO is quite different from PostgreSQL's regular SELECT INTO command, wherein the INTO target is a newly created table.
and
The INTO clause can appear almost anywhere in the SQL command. Customarily it is written either just before or just after the list of select_expressions in a SELECT command, or at the end of the command for other command types. It is recommended that you follow this convention in case the PL/pgSQL parser becomes stricter in future versions.
I'm so confused or rather I'm like, soooooooooo confused with pdo prepared statements. I know that prepared statements are the best way to keep data safe from hackers.
From : How can prepared statements protect from SQL injection attacks?
We are sending program to the server first
$db->prepare("SELECT * FROM users where id=?"); where the data is
substituted by some variable called "placeholder".
Note that the very same query being sent to the server, without any
data in it! And then we're sending the data with the second request,
totally separated from the query itself:
$db->execute($data);
query-
$query=$db->prepare("SELECT * FROM USERS WHERE username=?");
$query->execute(array($tex));
$tex=blah; DROP TABLE users;--
then it will be like - SELECT * FROM USERS WHERE username=blah; DROP TABLE users;--
how prepare statements will help me with this example above?
I'm really sorry if this question is vague to understand. Any help would be appreciated. Thanks in advance.
The prepared statement handler will make sure the bound value is always used as valid SQL value/literal (ie. an SQL string or a number) and never as 'raw SQL text'1.
This is why placeholders values cannot be used as identifiers such as column or table names or act as other SQL keywords; and cannot generate the vulnerable query hypothesized. Instead it is treated as the following:
WHERE username='blah; DROP TABLE users;--'
--^ placeholder ensures valid SQL string value is used
-- (note automatic/implicit addition of SQL quotes)
And even when binding with 'more tricky' data:
$tex = "blah'; DROP TABLE users;--"; // embedded SQL quote character
It would still be safe:
WHERE username='blah''; DROP TABLE users;--'
--^ placeholder STILL ensures valid SQL string value is used
Thus, when using placeholders, it is impossible to generate the SQL that is vulnerable (in this way).
For SQL Injection the 'shape' of the query (which includes keywords and identifiers, but excludes values) must itself be altered by the input.
1 Technically placeholders values can also be sent through a separate data channel (depending on adapter/driver) and thus might not even appear in the raw SQL query itself.
However a simple way to think about why placeholders are safe, or how they 'work' is:
When using placeholders the adapter ensures that the equivalent of 'sql really safe escape' and applicable quoting is always used for every bound text value - and is thus impossible for accidentally forget.
Is it safe to use same host variable for both input and output in an embedded SQL query ?
I'm using C and DB2 static embedded SQL.
Example:
EXEC SQL
SELECT someCol
INTO :someHostVar
FROM SomeTable
WHERE :someHostVar = someOtherCol;
Yes, you can do that. The value of someHostVar will be overwirtten and contain whatever the value of someCol is for this particular predicate - unless the value of someCol happens to be NULL at which point it the host variable remains unchanged.
Even though you can do this, I would suggest to you that this is not a good practice because someHostVar may end up containing values for different columns of the same table - too easy to screw up.