How to bind by name in Oracle PRO*C - c++

I got a query with bind variables where the same bind variable shows up more than once, for example:
select *
from some_table
where param1 = :parm1 and
applied_date = (select min(applied_date)
from some_table
where param1 = :parm1)
When I run this query in sqlplus Oracle appears to be binding by name. I.e. recognizes that the first and the second occurrence of parm1 is the same parameter and prompts me for the value of parm1 only once.
However, when in my C++ program I describe the bind variables into the bind descriptor, it always bind by position.
EXEC SQL DESCRIBE BIND VARIABLES FOR my_stmt INTO myBindDesc
The value of myBindDesc->F is 2 not 1, and the query won't execute properly until I populate
both of them, even though it's the same value.
My question is: is there a way to bind by name in PRO*C?

I can't tell for sure the cause of this problem, but you can rewrite the query to use only the :VAR only once in several ways. I hope this can help you -- if not understand, at least solve your problem:
SELECT *
FROM some_table tout
JOIN (
SELECT MIN(param1) AS "param1_min", MIN(applied_date) AS "applied_date_min"
FROM some_table
WHERE param1 = :parm1
) taux ON (1=1
AND tout.param1 = taux.param1_min
AND tout.applied_date = taux.applied_date_min
)

Related

cx_oracle insert with select query not working

I am trying to insert in database(Oracle) in python with cx_oracle. I need to select from table and insert into another table.
insert_select_string = "INSERT INTO wf_measure_details(PARENT_JOB_ID, STAGE_JOB_ID, MEASURE_VALS, STEP_LEVEL, OOZIE_JOB_ID, CREATE_TIME_TS) \
select PARENT_JOB_ID, STAGE_JOB_ID, MEASURE_VALS, STEP_LEVEL, OOZIE_JOB_ID, CREATE_TIME_TS from wf_measure_details_stag where oozie_job_id = '{0}'.format(self.DAG_id)"
conn.executemany(insert_select_string)
conn.commit()
insert_count = conn.rowcount
But I am getting below error. I do not have select parameter of data as data is getting from select query.
Required argument 'parameters' (pos 2) not found
Please suggest how to solve this
As mentioned by Chris in the comments to your question, you want to use cursor.execute() instead of cursor.executemany(). You also want to use bind variables instead of interpolated parameters in order to improve performance and reduce security risks. Take a look at the documentation. In your case you would want something like this (untested):
cursor.execute("""
INSERT INTO wf_measure_details(PARENT_JOB_ID, STAGE_JOB_ID,
MEASURE_VALS, STEP_LEVEL, OOZIE_JOB_ID, CREATE_TIME_TS)
select PARENT_JOB_ID, STAGE_JOB_ID, MEASURE_VALS, STEP_LEVEL,
OOZIE_JOB_ID, CREATE_TIME_TS
from wf_measure_details_stag
where oozie_job_id = :id""",
id=self.DAG_id)

Referencing a macro variable created by a prompt SAS EG

I created a prompt in SAS EG that takes a text input and creates the macro variable called 'variableName'.
I am trying to reference this macro variable like so:
proc sql;
create table MyTable as
select * from Source_Table as a
where a.field = &variableName ;
This gives me an error that says: "Syntax error, expecting one of the following: a name, a quoted string, a numeric constant, a datetime constant, a missing value, BTRIM, INPUT, PUT, SUBSTRING, USER."
I have also tried enclosing &variableName in single and double quotes but when I do that I just don't get any results.
I am able to reference the prompt when I use query builder and filter data based on the prompt, but I am trying to use the prompt's value in calculated expressions, etc. and in queries I write without query builder. How can i reference the variable I created in the prompt??
Edit: code with a value that the macro variable would have
proc sql;
create table MyTable as
select * from Source_Table as a
where a.field = 'NAME OF PERSON';
When I run that, I get the results I want.
It needs to resolve to valid SAS code. Assuming &variableName is a string, then it would be something like:
proc sql;
create table MyTable as
select * from Source_Table as a
where a.field = "&variableName." ;
If this isn't working, please show a query that does work with the same value as the macro variable would have. And then we can suggest how to change your code.
Edit: based on your comment you do not have the prompt connected to your query. Right click the query and link the prompt to your query and it will run before the query to provide the value.

How to bind a value to TTL in INSERT, Cassandra C++ driver

I'm using prepared statements in the Cassandra Datastax C++ Driver. How do I bind an integer-value to the "USING TTL ?" part of a prepared statement?
My statement would be something like
INSERT INTO table (column1, column2, column3) VALUES (?, ?, ?) USING TTL ?
In other words, If I'm using the position to bind to TTL, what is its position? (In this example, is it 4?) If I'm using bind by column name, what is its column name?
It looks like this can be done in CQL, but I couldn't find any documentation about the C++ driver API for doing this.
In Cassandra CQL 2.0 you can have:
Cassandra 1.2 doesn't allow you to use a bind marker for the TIMESTAMP and TTL properties of update statements, nor for the LIMIT property of SELECT statements. This is now fixed and you can for instance prepare statements like:
SELECT * FROM myTable LIMIT ?;
UPDATE myTable USING TTL ? SET v = 2 WHERE k = 'foo';
See their blog for more.
Edit:
I found this pdf and it tells you more:
Bound parameters:
The driver supports two kinds of bound parameters: by marker and by name.
Binding parameters
The ? marker is used to denote the bind variables in a query string. This is used for both regular
and prepared parameterized queries. In addition to adding the bind marker to your query string,
your application must also provide the number of bind variables to
cass_statement_new() when constructing a new statement. If a query doesn’t require any bind variables then 0 can be used. The cass_statement_bind_*()
functions are then used to bind values to the statement’s variables.
Bind variables can be bound by the marker index or by name.
Bind by marker index example
CassString query = cass_string_init("SELECT * FROM table1 WHERE column1
= ?");
/* Create a statement with a single parameter */
CassStatement* statement = cass_statement_new(query, 1);
cass_statement_bind_string(statement, 0, cass_string_init("abc"));
/* Execute statement */
cass_statement_free(statement);
Bind by marker name example
Variables can only be bound by name for prepared statements. This limitation exists because query
metadata provided by Cassandra is required to map the variable name to the variable’s marker index.
/* Prepare statement */
/* The prepared query allocates the correct number of parameters
automatically */
CassStatement* statement = cass_prepared_bind(prepared);
/* The parameter can now be bound by name */
cass_statement_bind_string_by_name(statement, "column1",
cass_string_init("abc"));
/* Execute statement */
cass_statement_free(statement);
To answer your question you can use bind by index (works at least for sure):
CassString query = cass_string_init("INSERT INTO table (column1, column2, column3) VALUES (?, ?, ?) USING TTL ?");
/* Create a statement with a single parameter */
CassStatement* statement = cass_statement_new(query, 4); // Bind 4 variables.
cass_statement_bind_string(statement, 0, cass_string_init("abc")); // Bind abc to first column.
cass_statement_bind_string(statement, 1, cass_string_init("bcd")); // Bind bcd to second column.
cass_statement_bind_string(statement, 2, cass_string_init("cde")); // Bind cde to third column.
cass_statement_bind_string(statement, 3, cass_string_init(50)); // Bind 50 to TTL.
/* Execute statement */
cass_statement_free(statement);
Edit:
See https://docs.datastax.com/en/cql/3.3/cql/cql_using/useExpireExample.html where you see that in case of INSERT we have USING TTL as last part of query, as seen above.
I have experimented with Cassandra C++ driver 2.11. I have found following
TTL can be bound by position only and we should use (cass_int32_t) data for binding TTL value
Example: cass_statement_bind_int32(statement, 2, (cass_int32_t)20);
cass_statement_bind_int32_by_name won't work
Ex: cass_statement_bind_int32_by_name(statement, 2, (cass_int32_t)20); //won't work

SAS Proc SQL Macro variables in Where clause

I am trying to write a program in SAS using the Prompt manager variable within a PROC SQL statement. It isnt working for me and keeps saying that the symbol is not recognized and will be ignored.
Heres a sample of my code...
LIBNAME mylib ORACLE SCHEMA = 'myschema' PATH = prd USER = 'admin' PASSWORD = 'admin12';
PROC SQL;
SELECT DISTINCT TEST_ID, COUNT(*), TERM
FROM mylib.testtable
WHERE RELEASE = 'PRETEST'
AND TEST_ID IN (&TEST) /* 'MATH', 'READING', 'SCIENCE' */
AND TERM = 'SPRING'
GROUP BY TEST_ID, TERM
ORDER BY TEST_ID, TERM;
QUIT;
And here is the problem in the log:
40 WHERE RELEASE = 'PRETEST'
41 AND TEST_ID IN (&TEST) /* 'MATH', 'READING', 'SCIENCE' */
NOTE: Line generated by the macro variable "TEST".
41 'MATH', 'READING', 'SCIENCE'
_
22
_
200
ERROR 22-322: Syntax error, expecting one of the following: a quoted string, a numeric constant, a datetime constant,
a missing value, (, -, SELECT.
ERROR 200-322: The symbol is not recognized and will be ignored.
My prompt variable is &TEST and should hold the list of tests to take but it dosent.
The issue here is one related to macro quoting. It's apparent that the token is enclosed in macro quotes (similar to %nrstr basically) for some reason, which cause it to work slightly differently than a normal %let. %unquote fixes it. I suspect there is also a better way to define the prompt to cause this not to occur, but I'm not completely sure - maybe one of the more experienced EG
folks can answer.
(Define a TEXT - SINGLE VALUE prompt called type and attach it to a program containing this:)
proc sql;
select name, age
from sashelp.class;
where name in (%unquote(&type.))
;
quit;
OK, I found a solution to my dilemma. As Joe stated, its a macro quoting issue, but it was also an array issue too. Both are solved by wrapping the variable in double quotes and some rudimentary replication.
Long story short,
the way SAS handles arrays and multiple values caused the first value to show only the first value so I had to assign multiple nullable values.
Working product below:
SELECT DISTINCT
TEST_ID, COUNT(*), TERM
FROM mylib.&TABLE
WHERE RELEASE IN ("&RELEASE", "&RELEASE1", "&RELEASE2", "&RELEASE3")
AND TEST_ID IN ("&TEST", "&TEST1", "&TEST2", "&TEST3", "&TEST4", "&TEST5")
AND TERM IN ("&TERM", "&TERM1", "&TERM2", "&TERM3", "&TERM4")
GROUP BY TEST_ID, TERM
ORDER BY TEST_ID, TERM;
Adding the &Release, &Release1, ect. allows multiple values to be captured should there be an array of values, otherwise it would accept the first value default the
extra values to null and throw a warning.
This was sufficient enough to be able to provide a list of options to the user and allow them to run using one or more parameter in each field

Got stuck on using prepare() and bindvalue() in c++ Qt

I've written a SQL query based on Qt assistant and it says that you can use the prepare() method instead of exec() then you can pass your parameter by the help of two methods called :
bindvalue() and addbindvalue()
Here is an snippet code of my problem :
Query->prepare("SELECT ID , Row , Col FROM sometable WHERE Row = :row AND Col = :col");
Query->bindValue(":row" , __Row);
Query->bindValue(":col" ,__Col);
Query->exec();
qDebug("%s" , Query->executedQuery().toStdString().c_str());
output :
SELECT ID , Row , Col FROM sometable WHERE Row = ? AND Col = ?
and also I've used another suggested way :
Query->prepare("SELECT ID , Row , Col FROM sometable WHERE Row = :row AND Col = :col");
Query->addBindValue(0 , __Row);
Query->addBindValue(1 ,__Col);
Query->exec();
qDebug("%s" , Query->executedQuery().toStdString().c_str());
output :
SELECT ID , Row , Col FROM sometable WHERE Row = ? AND Col = ?
but when I use exec() normally it works perfectly and will replace the corresponding values instead of "?".
is there any explanation about that? or should I use the ordinary exec()?
Is the exec() call failing ?
Because it may just be ok what you're seeing, as ,depending on which sql server you're using, the binding could be done by the server ( e.g. Oracle ).
According to Qt docs, executedQuery: "In most cases this function returns the same string as lastQuery(). If a prepared query with placeholders is executed on a DBMS that does not support it, the preparation of this query is emulated". So, I guess, if the server supports binding values the preparation won't be emulated so you'd just see the query without the placeholders being replaced by real values.
This is just a guess but from http://qt.nokia.com/doc/4.6/qsqlquery.html I read the following:
Warning: You must load the SQL driver and open the connection before a QSqlQuery is created. Also, the connection must remain open while the query exists; otherwise, the behavior of QSqlQuery is undefined.
Is the connection open in your case?
You can try this if you want to how your query constructed with prepared statements:
qDebug("%s" , Query.lastQuery().toStdString().c_str());