Convert each parameter to question mark for query statement - sql

I mean from this:
SELECT * FROM my_tab WHERE col1 = 'name1' AND col2 in(1,2,3);
how to get this:
SELECT * FROM my_tab WHERE col1 = ? AND col2 in(?,?,?);
pg_stat_statements does similar but it not saves original(with parameters) statement. I need original query also.
May be there is some open source or regex expression, which does this?

If you have access to Python, you may try:
sql = "SELECT * FROM my_tab WHERE col1 = 'name1' AND col2 IN (1,2,3);"
output = re.sub(r'\bIN\s*\((.*?)\)', lambda m: 'IN (' + re.sub(r'\w+', '?', m.group(1)) + ')', sql)
print(output)
This prints:
SELECT * FROM my_tab WHERE col1 = 'name1' AND col2 IN (?,?,?);

You might be able to do this for specific queries, but a general solution for this question would require parsing the SQL statement, which is complicated, to say the least.
Try to find a different solution for the problem underlying your question.

Related

Optional clauses in WHERE SQL COBOL

I have a form and each field is optional.
I would like to make an SQL query that includes optional conditions in the WHERE.
I'm using as a programming language COBOL, so i can't concatinate where clauses on the query
Bellow is my Query
SELECT *
FROM TABLE
WHERE Field1 = :VAL1
AND Field2 = :VAL2
How can i fill VAL1 and VAL2 when fields of the form is empty to get all row of the table TABLE
You can add an extra condition in the filtering. For example:
SELECT *
FROM TABLE
WHERE (Field1 = :VAL1 or :VAL1 = '')
AND (Field2 = :VAL2 or :VAL2 = '')
Note: If performance becomes an issue, it can be improved by the use of Dynamic SQL. That is, by dynamically adding only the parameters that are significant. This, of course, requires extra effort on coding and testing.
You could use different queries depending on the values filled from the form.
For example:
IF VAL1 EQUAL SPACES AND VAL2 EQUAL SPACES
EXEC SQL
SELECT *
FROM TABLE
END-EXEC
ELSE IF FIELD1 EQUAL SPACES
EXEC SQL
SELECT *
FROM TABLE
WHERE FIELD2 = :VAL2
END-EXEC
ELSE
EXEC SQL
SELECT *
FROM TABLE
WHERE FIELD1 = :VAL1
END-EXEC
END-IF
You can use SQLCODE =100 here is an example :
EXEC SQL
SELECT *
FROM TABLE
WHERE Field1 = :VAL1
AND Field2 = :VAL2
END-EXEC.
EVALUATE SQLCODE
WHEN ZEROS
CONTINUE
WHEN 100
*fill VAL1 and VAL2
WHEN OTHER
DISPLAY 'ERREUR'
END-EVALUATE.

Optional Reporting Parameters (is there a better way?)

I have a report with 4 parameters. I would like to make them not required. The problem is the conventional approach to do this, creates 16 OR/AND statements. If I were to have 10 not required parameters the SOL statement would be out of control. This works but is there an easier way?
Here is what I have:
MAIN DATA SET:
select *
from table
where
table.one = #param1 OR #param1 IS NOT NULL
AND.....(etc.etc..)
#param1, #param2,#param3,#param4: (default value null/blank)
Select some_column from any_table UNION SELECT '' as Nothing
The way I've always done it is
WHERE
col1 = isnull(#col1, col1)
and col2 = isnull(#col2, col2)
...etc
So pretty much what you have, with some semantic corrections.

Firebird sql to insert a typical record from another table with only one different field

I work on Firebird 2.5
and I have two tables, all their columns are similar except one has a primary key with auto increment and a not null foreign key field (A) for master table
I know I can use sql like this to insert all values from the two tables
insert into table1 select * from table2 where somthing = 'foo'
but what about the field (A) is there any way to insert this value manually in the same sql statement ? as this is the only field need to be entered manually
Thanks
You can specify both the source and target fields explicitly (and you should; don't use select * unless you have a specific reason to):
insert into table1
(
col1,
col2,
col3,
col4
)
select
col1,
col2,
col3,
'foo'
from table2
where something = 'foo'
Came upon this post because I was looking for a solution to do the same, but without hard-coding the field names because the fields maybe added/removed and didn't want to have to remember to update the copy record procedure.
After googling around for awhile, I came up with this solution:
select cast(list(trim(RDB$FIELD_NAME)) as varchar(10000))
from RDB$RELATION_FIELDS
where RDB$RELATION_NAME = 'YOUR_TABLE'
and RDB$FIELD_NAME not in ('ID') -- include other fields to NOT copy
into :FIELD_NAMES;
NEW_ID = next value for YOUR_TABLE_ID_GENERATOR;
execute statement '
insert into YOUR_TABLE (ID,' || FIELD_NAMES || ')
select ' || cast(:NEW_ID as varchar(20)) || ',' ||
FIELD_NAMES || '
from YOUR_TABLE
where ID = ' || cast(:ID_OF_RECORD_TO_COPY as varchar(20));
Hope this saves some time for anyone else who comes across this issue!

Referring to column values directly without using variables in T-SQL

Is there a way in T-SQL (SQL Server 2005) to assign a whole record to a record variable and then refer to the particular values using column names?
I mean, instead of:
select #var1 = col1,
#var2 = col2
from mytable
where ID = 1;
and referring to them as #var1 and #var2, something like
#record =
select col1, col2
from mytable
where ID = 1;
and referring to them like #record.col1 and #record.col2 .
I am beginner in t-sql, so hopefully the question is not too trivial.
You can create a table variable and select the whole resultset into it:
DECLARE #tt TABLE (col1 INT, col2 INT)
INSERT
INTO #tt
SELECT col1, col2
FROM mytable
WHERE id = 1
, but you cannot access its data except than in the SELECT query as well.
With pure TSQL (that it without custom datatypes) the thing you ask is impossible.
sounds like you are a programmer ... look at linq maybe as it does what you want.
You can use a temporary table and SELECT...INTO to avoid specifying the column names at the beginning :
SELECT Field1, Field2
INTO #TempTable
FROM MyTable
WHERE MyTable.MyID = 1
but of course you'll still need the FROM #TempTable part when referring to the column names.
SELECT Field1, Field2
FROM #TempTable
and of course to remember to drop the table at the end :
DROP #TempTable
The app code is where you'd normally refer to a single row at a time as a variable.
You could use XML, but you'd have to play with this...
DECLARE #MyRecord xml
DECLARE #Mytable TABLE (col1 int NOT NULL, col2 varchar(30) NOT NULL)
INSERT #Mytable (col1, col2) VALUES (1, 'bob')
select #MyRecord =
(SELECT *
from #Mytable
where col1 = 1
FOR XML AUTO)
SELECT #myRecord.value('./#col', 'int') --also #myRecord.value('#col', 'int')
--gives error
Msg 2390, Level 16, State 1, Line 12
XQuery [value()]: Top-level attribute nodes are not supported
Buried in the Transact SQL documentation I came across this restriction on variables:
Variables can be used only in expressions, not in place of object names or keywords.
Since you'd need to use an object name to qualify a column I don't believe that this is allowed.

How can I copy a record, changing only the id?

My table has a large number of columns. I have a command to copy some data - think of it as cloning a product - but as the columns may change in the future, I would like to only select everything from the table and only change the value of one column without having to refer to the rest.
Eg instead of:
INSERT INTO MYTABLE (
SELECT NEW_ID, COLUMN_1, COLUMN_2, COLUMN_3, etc
FROM MYTABLE)
I would like something resembling
INSERT INTO MYTABLE (
SELECT * {update this, set ID = NEW_ID}
FROM MYTABLE)
Is there a simple way to do this?
This is a DB2 database on an iSeries, but answers for any platform are welcome.
You could do this:
create table mytable_copy as select * from mytable;
update mytable_copy set id=new_id;
insert into mytable select * from mytable_copy;
drop table mytable_copy;
I don't think this is doable entirely within SQL without going to the trouble of creating a temp table. Doing it in memory should be much faster. Beware if you go the temporary table route that you must choose a unique name for your table for each function invocation to avoid the race condition where your code runs twice at the same time and mangles two rows of data into one temp table.
I don't know what kind of language you're using but it should be possible to obtain a list of fields in your program. I would do it like this:
array_of_field_names = conn->get_field__list;
array_of_row_values = conn->execute ("SELECT... ");
array_of_row_values ["ID"] = new_id_value
insert_query_string = "construct insert query string from list of field names and values";
conn->execute (insert_query_string);
Then you can encapsulate that as a function and just call it specifying table, old id and new id and it'd work it's magic.
In Perl code the following snippet would do:
$table_name = "MYTABLE";
$field_name = "ID";
$existing_field_value = "100";
$new_field_value = "101";
my $q = $dbh->prepare ("SELECT * FROM $table_name WHERE $field_name=?");
$q->execute ($existing_field_value);
my $rowdata = $q->fetchrow_hashref; # includes field names
$rowdata->{$field_name} = $new_field_value;
my $insq = $dbh->prepare ("INSERT INTO $table_name (" . join (", ", keys %$rowdata) .
") VALUES (" . join (", ", map { "?" } keys %$rowdata) . ");";
$insq->execute (values %$rowdata);
Hope this helps.
Ok, try this:
declare #othercols nvarchar(max);
declare #qry nvarchar(max);
select #othercols = (
select ', ' + quotename(name)
from sys.columns
where object_id = object_id('tableA')
and name <> 'Field3'
and is_identity = 0
for xml path(''));
select #qry = 'insert mynewtable (changingcol' + #othercols + ') select newval' + #othercols;
exec sp_executesql #qry;
Before you run the "sp_executesql" line, please do "select #qry" to see what the command is that you're going to run.
And of course, you may want to stick this in a stored procedure and pass in a variable instead of the 'Field3' bit.
Rob
Your example should almost work.
Just add the column names of the new table to it.
INSERT INTO MYTABLE
(id, col1, col2)
SELECT new_id,col1, col2
FROM TABLE2
WHERE ...;
i've never worked with db2 but in mssql you could solve it with following procedure. this solution only works if you dont care what new id the items get.
1.) create new table with same scheme but where the id column incrementes automatically. (mssql "identitity specification = 1, identity increment = 1)
2.) than a simple
insert into newTable(col1, col2, col3)
select (col1, col2, col3) from oldatable
should be enough, be sure not to include your id colum in the above statement