DB2 - If table is empty for date X, insert, else go on - db2

--DB2 version 10 on AIX
I have a stored procedure, which I need to update. And want to check if there is data for a certain date. If data exists, go on, else run insert and then go on.
IF (SELECT COUNT(*)
FROM SCHEMA1.TABLE1_STEP1
WHERE XDATE = '9/27/2014' < 1)
THEN (INSERT INTO SCHEMA1.TABLE1_STEP1 (SELECT * FROM SCHEMA2.TABLE2 FETCH FIRST 2 ROWS ONLY))
END IF;
This errors-out.
DB2 Database Error: ERROR [42601] [IBM][DB2/AIX64] SQL0104N An unexpected token "(" was found following "/2014') < 1) THEN". Expected tokens may include: "". SQLSTATE=42601
Any thoughts on what's wrong?

I'm guessing you probably want the less than sign outside of the parenthesis...
However, as an aside, you can also do this kind of statement without an IF (although, I don't have an AIX DB2 available to check for sure. It worked on DB2 for z/OS and LUW, however):
INSERT INTO SCHEMA1.TABLE1_STEP1
SELECT *
FROM SCHEMA2.TABLE2
WHERE NOT EXISTS (
SELECT *
FROM SCHEMA1.TABLE1_STEP1
WHERE XDATE = '9/27/2014'
)
FETCH FIRST 2 ROWS ONLY
Also, you're not providing an ORDER BY on the SCHEMA2.TABLE2 select, so your results could come back in any order (whatever is "easiest" for the database engine)... order is not guaranteed unless you provide the ORDER BY statement.

Related

How to do row level locking for ensuring select and update statement thread safe in db2 procedure?

I have one select statement in proc which is query the integer value from one table and then i increment that integer value by one , i have one update statement which is updating the increment value in table .
I want make this atomic while calling the procedure for getting the updated integer value in each request.
please help to make this atomic .
i was trying to use only update command with inline assignment variable like
Update table SET col=col+1, #variable = col+1 where ?
but it is working in sybase db but not wrking in db2 .
Consider using the following syntax:
select columnName from final table ( update yourTable set columnName = ColumnName + 1 where ... )
This removes the need for two separate statements, better for concurrency.
For best results ensure that the WHERE clause is fully indexed, so you should examine the access plan to confirm this.
Choose the correct isolation level (at connection level, or statement level) to match the other statements (if any) in the transaction with the business requirements.

tgreenplumrow-Join and Filter is not woking

When i try to execute Multiple Queries in tgreenplumRow component.
It is not allowing me Join and Filter queries.
Input Info
Source and target table both in greenplum only
Source table - Pointing the External source called HDFS
Target TABLE - regular table in greenplum database
Like this
SQL Transaction
Begin;
"insert into target_tbl (select S.* from source_tbl s "LEFT JOIN" target_tbl d ON s."PK"=d."PK" where d."PK" is null) ;
UPDATE target_tbl d
SET
"COL" = s."COL"
FROM source_tbl s
WHERE s."PK"=d."PK" and d."COL" != s."COL"
;
END;
Error I Get:
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
Syntax error on tokens, delete these tokens
Actual Data Flow is
tgreenplumconnection
|
tjdbcinput -->tmap -->thdfsoutput -->tgreenplumrow -->tgreenplumcommit
Q1: How to run multiple queries with Join and filter in txxxROW component.
Q2: Is that possible to Handle above Source and target file scenario in tmap ?
Any Help on this would be much appreciated ?
I like to break these queries into separate components. In your case you want to turn off auto commit on the connection.
So after that mapping you have 2 greenplumRows and 1 commit component.
I think this makes the code more easier to understand and debug, because right now you don't know whether insert or update throws an error.
Don't forget to escape the \ and double quotes with a \ character. I think that what is giving you trouble here.
t*row just simply passes the query that you write in to the database.
In tgreeenplumrow component, you have to simply have the queries in between double quotes like
"Begin;
insert into target_tbl (select S.* from source_tbl s LEFT JOIN target_tbl d ON s.PK=d.PK where d.PK is null) ;
UPDATE target_tbl d
SET
COL = s.COL
FROM source_tbl s
WHERE s.PK=d.PK and d.COL != s.COL;
END;"
Hope this would help you out.

Copying of data from varchar2 to number in a same table

I have two columns and i need to copy of data from column VISITSAUTHORIZED to NEWVISITS, When i use below command to copy data i am getting an error message "invalid number".Can anyone correct this ?
VISITSAUTHORIZED VARCHAR2(10)
NEWVISITS NUMBER(8)
SQL> update patientinsurance set NEWVISITS=VISITSAUTHORIZED ;
ERROR at line 1:
ORA-01722: invalid number
It depends what kind of data you have in your old column. If it is all consistently formatted then you might be able to do:
update patientinsurance
set newvisits = to_number(visitsauthorized, '<format model>')
But it sounds more likely that you have something less easy to deal with. (The joys of storing data as the wrong datatype, which I assume is what you're now correcting). If there are rogue characters then you could use translate to get rid of them, perhaps, but you'd have to wonder about the integrity of the data and the values you end up with.
You can do something like this to display all the values that can't be converted, which may give you an idea of the best way to proceed - if there are only a few you might be able to correct them manually before re-running your update:
set serveroutput on
declare
newvisits number;
number_format_exception exception;
pragma exception_init(number_format_exception, -6502);
begin
for r in (select id, visitsauthorized from patientinsurance) loop
begin
newvisits := to_number(r.visitsauthorized);
exception
when number_format_exception then
dbms_output.put_line(sqlcode || ' ID ' || r.id
|| ' value ' || r.visitsauthorized);
end;
end loop;
end;
/
This is guessing you have a unique identifier field called ID, but change that as appropriate for your table, obviously.
Another approach is to convert the numbers that are valid and skip over the rest, which you can do with an error logging table:
exec dbms_errlog.create_error_log(dml_table_name => 'PATIENTINSURANCE');
merge into patientinsurance target
using (select id, visitsauthorized from patientinsurance) source
on (target.id = source.id)
when matched then
update set target.newvisits = source.visitsauthorized
log errors into err$_patientinsurance reject limit unlimited;
You can then query the error table to see what failed:
select id, visitsauthorized, ora_err_number$
from err$_patientinsurance;
Or see which records in your main table have newvisits still null. Analysing your data should probably be the first step though.
If you want to strip out all non-numeric characters and treat whatever is left as a number then you can change the merge to do:
...
update set target.newvisits = regexp_replace(source.visitsauthorized,
'[^[:digit:]]', null)
But then you probably don't need the merge, you can just do:
update patientinsurance set newvisits = regexp_replace(visitsauthorized,
'[^[:digit:]]', null);
This will strip out any group or decimal separators as well, which might not be an issue, particularly as you're inserting into a number(8) column. But you could preserve those if you wanted to, by changing the pattern to '[^[:digit:].,]'... though that could give you other problems still, potentially.
You can also do this with translate if the regex is too slow.

conditional statement in DB2 without a procedure

I need to execute statements conditionally in DB2. I searched for DB2 documentation and though if..then..elseif will serves the purpose. But can't i use if without a procedure.?
My DB2 verion is 9.7.6.
My requirement is I have a table say Group(name,gp_id). And I have another table Group_attr(gp_id,value,elem_id). We can ignore ant the elem_id for the requirement now.
-> I need to check the Group if it have a specific name.
-> If it has then nothing to be done.
-> If it doesn't have I need to add it to the Group. Then I need to insert corresponding rows in the Group_attr. Assume the value and elem_id are static.
You can use an anonymous block for PL/SQL or a compound statement for SQL PL code.
BEGIN ATOMIC
FOR ROW AS
SELECT PK, C1, DISCRETIZE(C1) AS D FROM SOURCE
DO
IF ROW.D IS NULL THEN
INSERT INTO EXCEPT VALUES(ROW.PK, ROW.C1);
ELSE
INSERT INTO TARGET VALUES(ROW.PK, ROW.D);
END IF;
END FOR;
END
Compound statements :
http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.sql.ref.doc/doc/r0004240.html
http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.apdv.sqlpl.doc/doc/c0053781.html
http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.sql.ref.doc/doc/r0004239.html
Anonymous block :
http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.apdv.plsql.doc/doc/c0053848.html
http://www.ibm.com/developerworks/data/library/techarticle/dm-0908anonymousblocks/
Many ot this features come since version 9.7
I got a solution for the conditional insert. For the scenario that I mentioned, the solution can be like this.
Insert into Group(name) select 'Name1' from sysibm.sysdummy1 where (select count(*) from Group where name='Name1')=0
Insert into Group_attr(gp_id,value,elem_id) select g.gp_id,'value1','elem1' Group g,group_attr ga where ga.gp_id=g.gp_id and (select count(*) from Group_attr Ga1 where Ga.gp_id=g.gp_id)=0
-- In my case Group_attr will contain some data for sure if the group has exists already

SQL Injection : Syntax error

I have an essay on SQL injection ( what it is - how its done and how can it be avoided ). I get what it is and how it works. But i dont seem to be able to reproduce an injection on my database.
I made a pretty simple database ,using mysql workbench, meant for a video club. movies - stock - price - customers shopping cart etc.
I also made a pretty simple html page from which i can add movies - view what i have in stock etc.
So i have a txt field in which i enter a movie name and i get back some info for this specific movie.
The code that gets the name i type and makes the query is ::
$name = $_POST ['txtfld'];
$sql = ("SELECT * FROM test_table WHERE adad = '$Mname'");
if ($result = mysqli_query($dbc,$sql))
Now when i give 'a' as an input everything works as expected. I get back the one entry that has pk equal to [a].
Query becomes :: SELECT * FROM test_table WHERE adad= 'a'.
Next step was to see if i can get the whole table or some random entry from it.
Input was : [ a' OR 'x'='x ]
Query becomes :: SELECT * FROM test_table where adad = ' a' OR 'x' = 'x '
Everything works as expected and i get back the whole table contents.
Next step was to try inject a second query. I tried to update the test_table.
Input was :: [ a;' update test_table set asda = '123456' where adad = 'u ]
Query now becomes :: SELECT * FROM test_table WHERE adad= ' a;' UPDATE test_table SET asda ='123456' WHERE adad = 'u '
I got a syntax error so i tried every syntax i could think of including
[ a;' UPDATE test_table SET asda = '123456' where adad = 'u';# ]
. None of them worked.
Thing is, i dont really get why i get a syntax error.
For the input given above mysqli_error returns this message
error: You have an error in your SQL syntax; check the manual that corresponds to your
MySQL server version for the right syntax to use near 'update test_table set asda =
'123456' where adad = 'u'' at line 1
while an echo i inserted returns this
SELECT * FROM test_table WHERE adad = 'a;' UPDATE test_table SET asda = '123456' WHERE
adad = 'u'
I dont see any syntax error in the echo return and i dont get where the second [ ' ] character in the end of the mysqli_error return, comes from.
From what i understand this is rather a failure in executing a second query ( no matter what the query is - drop, insert, update )
Do i miss something?
Thanks in advance.
Michael.
mysql's PHP driver does NOT allow multiple queries in a single ->query() call, exactly for this reason. It's an anti-injection defense, to prevent the classic Bobby Tables attack. This true for all PHP db interfaces (mysql, mysqli, pdo), as they all use the same underlying mysql C api library to actually talk to the db. Any attempt to run 2+ queries in a single query call results in the syntax error.
Note that it does NOT protect against your ' or 1=1 injection, however.
In order for your stacked query injection technique to work, you will need to use the "mysqli_multi_query()" function:
http://php.net/manual/en/mysqli.multi-query.php
http://www.websec.ca/kb/sql_injection#MySQL_Stacked_Queries
MsSQL is the only database that supports stacked queries by default.
Also possibly a better injection technique, and a more reliable one, would be a UNION attack, and then dump the MySQL credentials from the "mysql.user" table, then use these to compromise the database.