SQL Developer bind variables prompt: force string values - sql

I'm trying to use SQL Developer bind variables prompt to speed up query execution, but I'm not getting the desired output: looks like the values I put in get converted in number.
Table description:
Nome Null Type
------------------ -------- ------------
NUM NOT NULL VARCHAR2(13)
IS_OK NUMBER(1)
initial situation:
select NUM, IS_OK from numbers_table where NUM = cast(:dn as varchar2(13));
NUM |IS_OK |
------------|------|
08331930078 |1 |
working updates:
1.
update numbers_table set IS_OK = 0 where NUM = 08331930078;
update numbers_table set IS_OK = 0 where NUM = '08331930078';
ouput:
'1 row updated'
non-working updates:
1.
update numbers_table set IS_OK = 0 where NUM = :dn;
update numbers_table set IS_OK = 0 where NUM = cast(:dn as varchar2(13));
output:
'0 rows updated'
Don't know what else can I do to force the value being parsed as a string.
SQL Developer version 4.1.3.20

That's interesting, and looks like a bug. You don't actually need to cast, the value from the 'enter binds' window is a string anyway, so this works:
update numbers_table set IS_OK = 0 where NUM = :dn;
when the zero-padded string 08331930078 is entered in the dialog.
The cast is not needed but ought to still work. If you run as a script instead, with a defined bind variable, then both forms do work:
var dn varchar2(13);
exec :dn := '08331930078';
update numbers_table set IS_OK = 0 where NUM = :dn;
rollback;
update numbers_table set IS_OK = 0 where NUM = cast(:dn as varchar2(13));
rollback;
You get 1 row updated for both statements. Going back to running as a statement still prompts and still has the same (odd) behaviour even when the bind variable has been defined in a script in the same session.
Incidentally, when you do:
update numbers_table set IS_OK = 0 where NUM = 08331930078;
what you're actually doing, as you can see form the execution plan's predicate section, is:
update numbers_table set IS_OK = 0 where to_number(NUM) = 8331930078;
which will stop any index on the num column being used, and may result in unexpected results - in this case, if these are e.g. UK phone numbers you probably won't have the same value with and without the leading zero, but it's something to be wary of generally.

Related

Searching for pattern with characters and numerics in SAS

I am examining data quality and am trying to see how many rows are populated properly. The field should contain a string with one character followed by nine numerical and is of type 'Character' length 10.
Ex.
A123456789
B123531490
C319861045
I have tried using PRXMATCH function, but I am unsure if i use the proper syntax. I have also tried using PROC SQL with "Where not like "[A-Z][0-9][0-9]" and so on. My feeling is that this should not be difficult to perform, does anyone have a solution?
Best regards
You can construct a REGEX to make that test. Or just build the test using normal SAS functions.
data want ;
set have ;
flag1 = prxmatch('/^[A-Z][0-9]{9}$/',trim(name));
test1 = 'A' <= name <= 'Z' ;
test2 = not notdigit(trim(substr(name,2))) ;
test3 = length(name)=10;
flag2 = test1 and test2 and test3 ;
run;
Results:
Obs name flag1 test1 test2 test3 flag2
1 A123456789590 0 1 1 0 0
2 B123531490ABC 0 1 0 0 0
3 C3198610 0 1 1 0 0
4 A123456789 1 1 1 1 1
5 B123531490 1 1 1 1 1
6 C319861045 1 1 1 1 1
You can use:
^[a-zA-z][0-9]{9}$
The built-in SAS functions NOTALPHA and NOTDIGIT can perform validation testing.
invalid_flag = notalpha(substr(s,1,1)) || notdigit(s,2) ;
You can select invalid records directly with a where statement or option
data invalid;
set raw;
where notalpha(substr(s,1,1)) || notdigit(s,2) ; * statement;
run;
data invalid;
set raw (where=(notalpha(substr(s,1,1)) || notdigit(s,2))); * data set option;
run;
There are several functions in the NOT* and ANY* families and they can offer faster performance than the general purpose regular expression functions in the PRX* family.
you can use prxparse and prxmatch as shown below.
data have;
input name $20.;
datalines;
A123456789590
B123531490ABC
C3198610
A123456789
B123531490
C319861045
;
data want;
set have;
if _n_=1 then do;
retain re;
re = prxparse('/^[a-zA-z][0-9]{9}$/');
end;
if prxmatch(re,trim(name)) gt 0 then Flag ='Y';
else Flag ='N';
drop re;
run;
if you want only records those match the criteria then use
data want;
set have;
if _n_=1 then do;
retain re;
re = prxparse('/^[a-zA-z][0-9]{9}$/');
end;
if prxmatch(re,trim(name));
drop re;
run;

SQL : Update value when the value in the database is null

I know this is already asked question and possible to be close.
But i really want a answer, I already searched through the internet, Read documentations, Blogs, and Question to SO.
This is my Query so Far,
declare #count numeric
select #count = (select count(1) from E496_TitleReference a where
exists (select 1 from #tempTransactions b where a.EPEB_RoD = b.tEPEB_RoD and
a.EPEB_ENO = b.tEPEB_ENO and a.EPEB_ID = b.tEPEB_ID and a.Title_Seq = b.tTitle_Seq))
update E496_TitleReference
set PrintStatus = '{0}',Is_AESM=isnull(-1,Is_AESM)
from E496_TitleReference a where
exists (select 1 from #tempTransactions b where a.EPEB_RoD = b.tEPEB_RoD and
a.EPEB_ENO = b.tEPEB_ENO and a.EPEB_ID = b.tEPEB_ID and a.Title_Seq = b.tTitle_Seq)
if ##rowcount <> #count
begin
rollback tran
Print "Error: There is an error on table E496_TitleReference."
return
end
go
For eg, In my table in Database i have column name Is_AESM, In Is_AESM column it have 4 values.
Is_AESM
NULL
NULL
-1
-2
Something like this.
Now when i run my script, it has no problem when i run it,
Is_AESM=isnull(-1,Is_AESM)
In this query it will detect if Is_AESM is null, it will update Is_AESM = -1 if not it will retain the value.
Now my problem is, if my query detect Is_AESM has a null value, it will update all the value to -1.
Is_AESM
-1
-1
-1
-1
The result is something like that. Now i want is update only the null value not all the value in column Is_AESM.
I think this query is wrong Is_AESM=isnull(-1,Is_AESM).
Any ideas will be a big help.
You may try with coalsece() function
update E496_TitleReference
set PrintStatus = '{0}',Is_AESM=coalsece(Is_AESM,-1)
from E496_TitleReference a where
exists (select 1 from #tempTransactions b where a.EPEB_RoD = b.tEPEB_RoD and
a.EPEB_ENO = b.tEPEB_ENO and a.EPEB_ID = b.tEPEB_ID and a.Title_Seq = b.tTitle_Seq)
you need to replace order of parameters.
Is_AESM=isnull(Is_AESM, -1)
You can use COALSECE function. It returns the first non-null entry from the given list. So:
Is_AESM= COALSECE(IS_AESM,-1)
This will return IS_AESM value if it is not null (since it is the first non-null value)
Else if IS_AESM is NULL then it returns -1 (since it is the non-null value)

PLSQL syntax error near ";"

I am trying to run a query for liquibase update and I have a PLSQL block in there, the block has over 500 lines so I only post a few lines where the error is happening for now.
BEGIN
IF NOT EXISTS(select 1 from "public"."eod_report" where "id" = NEW."id") THEN
-- LOADING STRUCTURE SECTION
select "id" into NEW.organization_unit_id from organization_unit where site_id = NEW.organization_unit_id;
orgUnitId := CAST(NEW.organization_unit_id as int8);
--INSERT
IF (NEW.transactions_count is NULL) THEN
NEW.transactions_count := 0;
END IF;
IF (NEW.total_sales is NULL) THEN
NEW.total_sales := 0;
END IF;
INSERT INTO "public"."eod_report"("id",batch,total_sales,transactions_count,organization_unit_id,pos_total_sales,pos_transactions_count,pos_total_points,total_points,transaction_date)
VALUES (NEW."id",NEW.batch,NEW.total_sales,NEW.transactions_count,orgUnitId,NEW.pos_total_sales,NEW.pos_transactions_count,NEW.pos_total_points,NEW.total_points,NEW.transaction_date);
-- updates delay transaction or each batch
select max(id) into lastEodId from "public"."transaction" where transaction_type = 4 and org_unit_id = orgUnitId and id &lt ;NEW."id";
for eodRow IN
select count(case when transaction_type = 3 then -1 else 1 end) as trCount,sum(case when report_prefix = true then points else -points end) as ptSum,sum(case when report_prefix = true then amount else -amount end) as trSum, batch as trBatch from "public"."transaction"
where id &gt ;lastEodId and id &lt ;NEW."id" and report_prefix is not null and org_unit_id = orgUnitId
and batch &lt ;NEW.batch group by batch
LOOP
UPDATE "public"."eod_report" SET delayed_points =
(delayed_points + eodRow.ptSum),former_delayed_sales =
END LOOP;
END IF;
RETURN NULL;
And I am getting this error when I try to execute the query:
ERROR:
syntax error at or near ";"
LINE 453: ..._type = 4 and org_unit_id = orgUnitId and id &lt ;NEW."id";
^
SQL state: 42601
Character: 15018
there is a screenshot where the error is highlighted
Looks like the < and > chars are replaced with &lt ; so the syntax is incorrect.
fix the SQL by replacing all &lt ; with < to have
... org_unit_id = orgUnitId and id < NEW."id";
Also &gt ; must be replaced with >
It could happens e.g. because of URL encoding of text sent from UI (browser)
You find the same problem in multiple parts of your query, because HTML entities like "&lt ;" and "&gt ;" are not legal in an SQL query, which the error points to. You should change them to "<" and ">" accordingly.

conditional handling of update sql script depending on input parameter

I am new to SQL and using Oracle 11. I need to write a sql script which uses different update command based on whether the input param is null or not null.
I need something like this
['&' followed by the parameter name is the way i see parameters being used in other such
script for our project]
IF &PRG_ID IS NULL
UPDATE PROGRAM_TABLE P SET HANDLED_IND = 'Y' WHERE EXISTS
(SELECT 1 FROM HANDLED_PROGRAM H WHERE H.PROGRAM_ID = P.PROGRAM_ID);
ELSE
UPDATE PROGRAM_TABLE P SET HANDLED_IND = 'Y' WHERE
P.PROGRAM_ID = &PRG_ID AND EXISTS
(SELECT 1 FROM HANDLED_PROGRAM H WHERE H.PROGRAM_ID = P.PROGRAM_ID);
END IF;
Something like (is not tested):
UPDATE PROGRAM_TABLE P SET HANDLED_IND = 'Y' WHERE EXISTS
(SELECT 1 FROM HANDLED_PROGRAM H WHERE H.PROGRAM_ID = P.PROGRAM_ID)
AND (&PRG_ID IS NULL OR P.PROGRAM_ID = &PRG_ID);
But take into account this change may lead to the performance degradation for the case when PRG_ID has definite value.

how do i shorten this SQL?

I run this command :
select * from LIST where JCODE = 8 and
KCODE = 01 and LCODE = 2011
and if the above retruns no rows then perform the below :
insert into LIST
select * from LIST#LNDB where JCODE = 8 and
KCODE = 01 and LCODE = 2011 and ban
in (select BAN from billing_account)
Update LIST set STS = null where JCODE = 8
AND KCODE = 01;
Update LIST set NO = '1' where JCODE = 8 AND
KCODE = 01;
moreover can i use some variable in the begininng which
sets
JCODE= somevalue
KCODE= anothervalue
LCODE=someothervalue
so that i dont have to edit every line every time i run it.
I am using :
Oracle 9i Enterprise Edition release 9.2.8.0 - 64 bit Production
I can't tell for the SELECT, but you should be allowed to UPDATE several fields at once:
UPDATE LIST set STS = null , NO = '1' WHERE JCODE = 8 AND KCODE = 01;
Edit: I don't understand why you need the second SELECT (with LIST#LNDB), but in both queries I don't think you really need all the fields, so instead of using SELECT *, which is heavy for the system, use only and explicitly the primary key's field name (like SELECT id FROM ...).
And there is a way to do it in one request, probably something like:
UPDATE LIST set STS = null , NO = '1' WHERE JCODE = 8 AND KCODE = 01 AND 0<(SELECT COUNT(*) FROM LIST WHERE JCODE = 8 AND KCODE = 01 AND LCODE = 2011);
This way, if there is no result found by SELECT, the WHERE clause in UPDATE will be false for every row, as 0<0 is false. There may also be a way to use COUNT() with a named field instead of *, I don't know Oracle enough for that.
Re-edit: indeed, if your second SELECT is actually an INSERT, you probably need that * :) But I don't think you can apply the same trick on the INSERT as the one on the UPDATE...
Re-re-edit: to write better what I put in the comment - taken from http://www.oradev.com/oracle_insert.jsp - your one and only request could be:
INSERT
WHEN (0=(SELECT COUNT(id) FROM LIST WHERE JCODE=8 AND KCODE=01 AND LCODE=2011))
INTO LIST (field1, field2, field3, STS, field4, field5, NO, field6)
SELECT field1, field2, field3, null, field4, field5, 1, field6
FROM LIST#LNDB
WHERE JCODE=8 AND KCODE=01 AND LCODE=2011
AND ban IN (SELECT BAN FROM billing_account)
Naturally you can add the GuZzie touch, use DECLARE, BEGIN and END to make the writing of parameters easier ;)
You can combine the two update queries.
Update LIST set STS = null, NO = '1' where JCODE = 8 AND KCODE = 01;
If you want to use variables you need to declare them and then simply call them in the query
DECLARE
v_JCODE NUMBER := 8;
v_KCODE NUMBER := 01;
v_LCODE NUMBER := 2011;
BEGIN
Update LIST set STS = null, NO = '1' where JCODE = v_JCODE and KCODE = v_KCODE;
END;
/
EDIT: Due to the discussion and comments below I've made a PL/SQL procedure which should do what you are looking for. please note that you neet to replace the schemaname.procedure in the 1st row as this is the name of the procedure in the scheme you're currently working.
CREATE OR REPLACE PROCEDURE schemaname.procedure is
-- Declare vars
v_JCODE NUMBER := 8;
v_KCODE NUMBER := 01;
v_LCODE NUMBER := 2011;
v_checkvar NUMBER;
BEGIN
select count(*)
into v_checkvar
from LIST
where JCODE = v_JCODE
and KCODE = v_KCODE
and LCODE = v_LCODE;
if v_checkvar = 0 then
insert into LIST
select * from LIST#LNDB
where JCODE = v_JCODE
and KCODE = v_KCODE
and LCODE = v_LCODE
and ban in (select BAN from billing_account);
update LIST
set STS = null, NO = '1'
where JCODE = v_JCODE
and KCODE = v_KCODE;
end if;
END;