What is CHR code for single quote ' in oracle? - oracle

What is CHR code for single quote (') in oracle?
I am generating update statements ATM for tables without PKs, and Regex replacing some special characters.
select 'UPDATE QUESTION SET questiontypeid = '||questiontypeid||', questiontext = '''||questiontext||''', questiondescription = '''||questiondescription||''', productid = '||productid||', mandatory = '||CASE WHEN mandatory IS NULL THEN 'NULL' ELSE to_char(mandatory) END ||', displayorder = '||displayorder||', minvalue = '||CASE WHEN minvalue IS NULL THEN 'NULL' ELSE to_char(minvalue) END||', maxvalue = '||CASE WHEN maxvalue IS NULL THEN 'NULL' ELSE to_char(maxvalue) END||', parentid = '||CASE WHEN parentid IS NULL THEN 'NULL' ELSE to_char(parentid) END||', questioncategoryid = '||questioncategoryid||', isasset = '||CASE WHEN isasset IS NULL THEN 'NULL' ELSE to_char(isasset) END||', ISTHUNDERHEADONLY = '||CASE WHEN ISTHUNDERHEADONLY IS NULL THEN 'NULL' ELSE to_char(ISTHUNDERHEADONLY) END||', QCODE = '''||QCODE||''' WHERE QUESTIONID = '||QUESTIONID from (
(select * from question where questionid not in
(select t.questionid from question t
full join question#somecomp.co.uk d on t.questionid = d.questionid
where t.questiontypeid <> d.questiontypeid
or t.questiontext <> d.questiontext
or t.questiondescription <> d.questiondescription
or t.productid <> d.productid
or t.mandatory <> d.mandatory
or t.displayorder <> d.displayorder
or t.minvalue <> d.minvalue
or t.maxvalue <> d.maxvalue
or t.parentid <> d.parentid
or t.questioncategoryid <> d.questioncategoryid
or t.isasset <> d.isasset))
)

Let's see the ASCII value :
SQL> select ascii('''') from dual;
ASCII('''')
-----------
39
Or, to avoid multiple single-quotation marks, using literal quote technique :
SQL> select ascii(q'[']') from dual;
ASCII(Q'[']')
-------------
39
Let's confirm :
SQL> select chr(39) from dual;
C
-
'
SQL>

Thanks to #a_horse_with_no_name:
There is nothing special about ' in Oracle. It's the standard ASCII value.
Answer is : CHR(39)

Related

Unexpected NULL in multi-column correlated update

I want to run a multi-column correlated update of this kind:
UPDATE t1 t1_alias
SET (table_name, tablespace_name) = (
SELECT table_name, tablespace_name
FROM t2 t2_alias
WHERE t1_alias.table_name = t2_alias.table_name
);
But my attempt:
update customer up
set (customer_name, account, active) = (
select tmp.name, tmp.account, case when tmp.active = 'Yes' then 1 else 0 end
from customer_temp tmp
where up.agent = substr(tmp.agent, -4) and up.customer_code = tmp.code
);
... throws:
ORA-01407: cannot update ("FOO"."CUSTOMER"."CUSTOMER_NAME") to NULL
The source table customer_temp has no null values so I must be getting matches wrong. What is my error or misconception?
Presumably, there are some rows in the target table that have no match in the subquery.
You can avoid this with by adding an exists condition that filters out "unmatched" rows:
update customer up
set (customer_name, account, active) = (
select tmp.name, tmp.account, case when tmp.active = 'Yes' then 1 else 0 end
from customer_temp tmp
where up.agent = substr(tmp.agent, -4) and up.customer_code = tmp.code
)
where exists (
select 1
from customer_temp tmp
where up.agent = substr(tmp.agent, -4) and up.customer_code = tmp.code
);

Oracle function to select multiple rows in a single row not working

I am loading a file into a staging record using Application Engine. when ever there is blank in BU,Deptid etc... I have to capture what all columns are blank and update error text field with those values.
UPDATE SYSADM.PS_VI_EMP_TS SET ERR_TEXT =
SELECT ERROR FROM (SELECT * FROM (
SELECT CASE WHEN BUSINESS_UNIT = ' ' THEN 'BUSINESS_UNIT IS NULL' ELSE ' ' END AS ERROR FROM SYSADM.PS_VI_EMP_TS WHERE USERID='JCOOPER' AND ACTION = 'E' AND PROCESS_INSTANCE = '7852429'
UNION
SELECT CASE WHEN DEPTID = ' ' THEN 'DEPTID IS NULL' ELSE ' ' END AS ERROR FROM SYSADM.PS_VI_EMP_TS WHERE USERID='JCOOPER' AND ACTION = 'E' AND PROCESS_INSTANCE = '9852429'
UNION
SELECT CASE WHEN PROJECT_ID =' ' THEN 'PROJECT_ID IS NULL' ELSE ' ' END AS ERROR FROM SYSADM.PS_VI_EMP_TS WHERE USERID='JCOOPER' AND ACTION = 'E' AND PROCESS_INSTANCE = '9852429'
)) WHERE ERROR <> ' '
WHERE USERID='JCOOPER' AND ACTION = 'E' AND PROCESS_INSTANCE = '9852429'
The above script results as below.
ERROR
BUSINESS_UNIT IS NULL
DEPTID IS NULL
I want the result as below.
ERROR
BUSINESS_UNIT IS NULL,DEPTID IS NULL
I am using ListAgg function but facing errors as below.Any help would be great.
SELECT LISTAGG(BUSINESS_UNIT, ';') WITHIN GROUP(ORDER BY USERID)
FROM SYSADM.PS_VI_EMP_TS WHERE USERID='JCOOPER'
GROUP BY BUSINESS_UNIT
Facing the error:
ORA-00923: FROM keyword not found where expected
00923. 00000 - "FROM keyword not found where expected"
*Cause:
*Action:
Error at Line: 47 Column: 43
You overcomplicated things. You don't need two unions and listagg at all. Simple use concatenation of case... when, write your select like here:
select case business_unit when ' ' then 'BUSINESS_UNIT IS NULL; ' end ||
case deptid when ' ' then 'DEPTID IS NULL; ' end ||
case project_id when ' ' then 'PROJECT_ID IS NULL; ' end as error
from ps_vi_emp_ts
where userid = 'JCOOPER' and action = 'E' and process_instance = '9852429'
demo
If your table has primary key then use it for update. Otherwise you can use merge with rowid. Or do it the way you did it if it worked for you, especially if there is only one row meeting criteria.

CASE not working in oracle

For one of my column in query I want a CASE statement.
The scenario is
If my column name ltt.f_complete task_completed value is 0 then the value shd be NO and if 1 then YES.
I tried like below but getting as
ORA-00905: missing keyword
here is query
SELECT flv.property_name project_name, flv.building building_name,
flv.flat_no unit_no,
ldet.customer_fname
|| ' '
|| ldet.customer_mname
|| ' '
|| ldet.customer_lname customer_name,
la.booking_date holding_date, ltt.start_date task_date,
tid.task_desc task_type, fol.next_follow_up_date,
ltt.remarks task_comment, ltt.f_complete task_completed,
CASE TASK_VALUE WHEN '0' THEN 'NO'
WHEN '1' THEN 'YES',
act.act_desc activity_description, flv.follow_type followup_type,
fol.remarks followup_comment,
fol.next_follow_up_date next_followup_date,
actt.act_desc next_todo_activity
FROM xxcus.xxacl_pn_leases_all la,
(SELECT *
FROM xxcus.xxacl_pn_lease_det
WHERE sr_no = 1) ldet,
xxcus.xxacl_pn_lease_task_trl ltt,
xxcus.xxacl_pn_customer_followup fol,
xxacl_pn_flat_det_v flv,
xxcus.xxacl_pn_hold_task_v tid,
xxcus.xxacl_pn_hold_act_v act,
xxcus.xxacl_pn_followup_type_v flv,
xxcus.xxacl_pn_hold_act_v actt
WHERE la.booking_no = ltt.draft_form_no(+)
AND ltt.draft_form_no = fol.booking_no(+)
AND ltt.task_id = fol.task_id(+)
AND ltt.task_sr_no = fol.task_sr_no(+)
AND la.delete_flag = 'N'
AND la.booking_no = ldet.booking_no
AND fol.followup_date = TO_DATE (SYSDATE - 1)
AND la.flat_id = flv.flat_id
AND ltt.task_id = tid.task_id
AND fol.activity_id = act.act_id
AND fol.followup_type_id = flv.follow_type_id
AND fol.next_activity_id = actt.act_id
kindly suggest what is wrong
UPDATE
SELECT flv.property_name project_name, flv.building building_name,
flv.flat_no unit_no,
ldet.customer_fname
|| ' '
|| ldet.customer_mname
|| ' '
|| ldet.customer_lname customer_name,
la.booking_date holding_date, ltt.start_date task_date,
tid.task_desc task_type, fol.next_follow_up_date,
ltt.remarks task_comment, ltt.f_complete task_completed,
act.act_desc activity_description, flv.follow_type followup_type,
fol.remarks followup_comment,
fol.next_follow_up_date next_followup_date,
actt.act_desc next_todo_activity
FROM xxcus.xxacl_pn_leases_all la,
(SELECT *
FROM xxcus.xxacl_pn_lease_det
WHERE sr_no = 1) ldet,
xxcus.xxacl_pn_lease_task_trl ltt,
xxcus.xxacl_pn_customer_followup fol,
xxacl_pn_flat_det_v flv,
xxcus.xxacl_pn_hold_task_v tid,
xxcus.xxacl_pn_hold_act_v act,
xxcus.xxacl_pn_followup_type_v flv,
xxcus.xxacl_pn_hold_act_v actt
WHERE la.booking_no = ltt.draft_form_no(+)
AND ltt.draft_form_no = fol.booking_no(+)
AND ltt.task_id = fol.task_id(+)
AND ltt.task_sr_no = fol.task_sr_no(+)
AND la.delete_flag = 'N'
AND la.booking_no = ldet.booking_no
AND fol.followup_date = TO_DATE (SYSDATE - 1)
AND la.flat_id = flv.flat_id
AND ltt.task_id = tid.task_id
AND fol.activity_id = act.act_id
AND fol.followup_type_id = flv.follow_type_id
AND fol.next_activity_id = actt.act_id
The keyword you are missing is END. It should read like this:
CASE TASK_VALUE WHEN '0' THEN 'NO'
WHEN '1' THEN 'YES' END

Trigger on one table field works for all table fields

I have a trigger which is for a few fields in a table. But for some reason, if another field is changed (which is not defined in trigger) then it still fires.
CREATE OR REPLACE TRIGGER INTEGRATION_EMPLOYMENT
AFTER UPDATE OF start_day_of_employment, end_of_employment ON hr_employment_data
FOR EACH ROW
DECLARE
BEGIN
IF UPDATING THEN
MERGE INTO ad_integration intg USING dual ON (intg.user_id = :NEW.user_id AND intg.integrated = 'NO')
WHEN MATCHED THEN
UPDATE SET
intg.start_day_of_employment = decode(:NEW.start_day_of_employment, NULL, ' ', :NEW.start_day_of_employment),
intg.end_of_employment = decode(:NEW.end_of_employment, NULL, ' ', :NEW.end_of_employment),
intg.manager_status = :NEW.manager_status,
intg.pid = (SELECT pid FROM arc.user_info WHERE user_id = :NEW.user_id),
intg.network_access_start_date = (SELECT network_access_start_date FROM hr_extension_data WHERE user_id = :NEW.user_id)
WHEN NOT MATCHED THEN
INSERT (intg.user_id, intg.start_day_of_employment, intg.end_of_employment, intg.manager_status, intg.pid, intg.network_access_start_date
VALUES (:NEW.user_id, :NEW.start_day_of_employment, :NEW.end_of_employment, :NEW.manager_status, (SELECT pid FROM arc.user_info WHERE user_id = :NEW.user_id), (SELECT network_access_start_date FROM hr_extension_data WHERE user_id = :NEW.user_id));
END IF;
END HR_ADINTEGRATION_EMPLOYMENT;
Is it because of using DUAL or something am I missing?
Cheers! :-)
If you want to leave the structure as is and only process the trigger when the specifc fields change, then just do a quick compare (new code lines 7 and 8):
CREATE OR REPLACE TRIGGER INTEGRATION_EMPLOYMENT
AFTER UPDATE OF start_day_of_employment, end_of_employment ON hr_employment_data
FOR EACH ROW
DECLARE
BEGIN
IF UPDATING
AND (:NEW.start_day_of_employment <> :OLD.start_day_of_employment
OR :NEW.end_of_employment <> :OLD.end_of_employment) THEN
MERGE INTO ad_integration intg USING dual ON (intg.user_id = :NEW.user_id AND intg.integrated = 'NO')
WHEN MATCHED THEN
UPDATE SET
intg.start_day_of_employment = decode(:NEW.start_day_of_employment, NULL, ' ', :NEW.start_day_of_employment),
intg.end_of_employment = decode(:NEW.end_of_employment, NULL, ' ', :NEW.end_of_employment),
intg.manager_status = :NEW.manager_status,
intg.pid = (SELECT pid FROM arc.user_info WHERE user_id = :NEW.user_id),
intg.network_access_start_date = (SELECT network_access_start_date FROM hr_extension_data WHERE user_id = :NEW.user_id)
WHEN NOT MATCHED THEN
INSERT (intg.user_id, intg.start_day_of_employment, intg.end_of_employment, intg.manager_status, intg.pid, intg.network_access_start_date
VALUES (:NEW.user_id, :NEW.start_day_of_employment, :NEW.end_of_employment, :NEW.manager_status, (SELECT pid FROM arc.user_info WHERE user_id = :NEW.user_id), (SELECT network_access_start_date FROM hr_extension_data WHERE user_id = :NEW.user_id));
END IF;
END HR_ADINTEGRATION_EMPLOYMENT;

How to return all rows if IN clause has no value?

Following is sample query.
CREATE PROCEDURE GetModel
(
#brandids varchar(100), -- brandid="1,2,3"
#bodystyleid varchar(100) -- bodystyleid="1,2,3"
)
AS
select * from model
where brandid in (#brandids) -- use a UDF to return table for comma delimited string
and bodystyleid in (#bodystyleid)
My requirement is that if #brandids or #bodystyleid is blank, query should return all rows for that condition.
Please guide me how to do this? Also suggest how to write this query to optimize performance.
You'll need dynamic SQL or a split function for this anyway, since IN ('1,2,3') is not the same as IN (1,2,3).
Split function:
CREATE FUNCTION dbo.SplitInts
(
#List VARCHAR(MAX),
#Delimiter CHAR(1)
)
RETURNS TABLE
AS
RETURN ( SELECT Item = CONVERT(INT, Item) FROM (
SELECT Item = x.i.value('(./text())[1]', 'int') FROM (
SELECT [XML] = CONVERT(XML, '<i>' + REPLACE(#List, #Delimiter, '</i><i>')
+ '</i>').query('.') ) AS a CROSS APPLY [XML].nodes('i') AS x(i)) AS y
WHERE Item IS NOT NULL
);
Code becomes something like:
SELECT m.col1, m.col2 FROM dbo.model AS m
LEFT OUTER JOIN dbo.SplitInts(NULLIF(#brandids, ''), ',') AS br
ON m.brandid = COALESCE(br.Item, m.brandid)
LEFT OUTER JOIN dbo.SplitInts(NULLIF(#bodystyleid, ''), ',') AS bs
ON m.bodystyleid = COALESCE(bs.Item, m.bodystyleid)
WHERE (NULLIF(#brandids, '') IS NULL OR br.Item IS NOT NULL)
AND (NULLIF(#bodystyleid, '') IS NULL OR bs.Item IS NOT NULL);
(Note that I added a lot of NULLIF handling here... if these parameters don't have a value, you should be passing NULL, not "blank".)
Dynamic SQL, which will have much less chance of leading to bad plans due to parameter sniffing, would be:
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'SELECT columns FROM dbo.model
WHERE 1 = 1 '
+ COALESCE(' AND brandid IN (' + #brandids + ')', '')
+ COALESCE(' AND bodystyleid IN (' + #bodystyleid + ')', '');
EXEC sp_executesql #sql;
Of course as #JamieCee points out, dynamic SQL could be vulnerable to injection, as you'll discover if you search for dynamic SQL anywhere. So if you don't trust your input, you'll want to guard against potential injection attacks. Just like you would if you were assembling ad hoc SQL inside your application code.
When you move to SQL Server 2008 or better, you should look at table-valued parameters (example here).
if(#brandids = '' or #brandids is null)
Begin
Set #brandids = 'brandid'
End
if(#bodystyleid = '' or #bodystyleid is null)
Begin
Set #bodystyleid = 'bodystyleid'
End
Exec('select * from model where brandid in (' + #brandids + ')
and bodystyleid in (' + #bodystyleid + ')')

Resources