Oracle ORA-12704 with case expression on CLOB - sql

I have an Oracle update statement with a case that is trying to either set or ignore a value (leave original value the same ).
With this code, either of the two individual sets compile on their own ( the two commented out ones ).
But when combined in a case statement, I get "PL/SQL: ORA-12704: character set mismatch"
The column is a CLOB column.
Alternatively is there a way to conditionally not do a set in an update statement?
LONGDESCRIPT = ( CASE v_CanUpdateAssetDescription WHEN 1 THEN p_description ELSE LONGDESCRIPT END ),
-- LONGDESCRIPT = LONGDESCRIPT,
--LONGDESCRIPT = p_description,

Apparently the character set of p_description is not the same as that of LONGDESCRIPT. In a simple assignment Oracle can work with this, but in a CASE expression all values returned from the different paths through the CASE expression must be of exactly the same type. As it appears you're doing this in PL/SQL you might try doing something like the following:
DECLARE
cCLOB_var YOUR_TABLE.LONGDESCRIPT%TYPE;
BEGIN
cCLOB_var := p_description;
UPDATE YOUR_TABLE
SET LONGDESCRIPT = CASE v_CanUpdateAssetDescription
WHEN 1 THEN cCLOB_var
ELSE LONGDESCRIPT
END
...etc...
END;
You might also try using a CAST:
UPDATE YOUR_TABLE
SET LONGDESCRIPT = CASE v_CanUpdateAssetDescription
WHEN 1 THEN CAST(p_description AS YOUR_TABLE.LONGDESCRIPT%TYPE)
ELSE LONGDESCRIPT
END
Not sure if the latter will work or not, but it might be worth a shot.

Oddly I found that to_clob did the trick.
And even more oddly, I only needed TO_CLOB for the LONGDESCRIPT value.
LONGDESCRIPT = ( CASE v_CanUpdateAssetDescription WHEN 1 THEN p_description ELSE to_clob(LONGDESCRIPT) END ),

Related

Update Column: Case With Concat

I am have a blank column, it is called column_blank. I want to concat two other columns (concat1, concat2) and based on the concat value, add a value into column_blank. I am extremely green and appreciate your help.
This is what I am thinking. I am not too confident about the DECLARE statement
DECLARE DIRECTION CONCAT := (CONCAT1, CONCAT2);
INSERT INTO
MYDATA_EXTRACT_DATA.COLUMN_BLANK
SELECT
CASE COLUMN_BLANK
WHEN (DIRECTION) IS '123456', THEN ('654321'),
WHEN (DIRECTION) IS '789101', THEN ('654321'),
ELSE '000'
END CASE
FROM MYDATA_EXTRACT_DATA
That's just an ordinary update statement:
update mydata_extract_data set
column_blank = case when concat1 || concat2 in ('123456', '789101') then '654321'
else '000'
end;

If-Then Statement In A SQL Query Insists On Trying To Convert To Wrong Type, Then Fails

I have a SQL query, linking table 1 to table 2 via an inner join, containing this part in the select part of the statement:
select
table1.field1,
table2.field1,
CASE (table2.field1)
WHEN -2 THEN ''
ELSE table2.field2
END as table2Field2,
table3.field4
from...
I want to be able to return table2Field2 when it has a relevant value, ie: when the object represented in table2 is not null, so that table2.field1 does not have a value of -2. In this case, the value of table2Field2 should be blank instead of a meaningless value.
However, this returns 0 instead of the blank text. If I change this line:
WHEN -2 THEN ''
to this:
WHEN -2 THEN 'someText'
then it complains at me that it's trying to convert an int to a string, which I'm not. table2field1 is an int, but table2Field2 is a string, which is what we're actually returning here.
How do I state (even more specifically) in this query that I'm returning the string field as a string, and not something else as a string that isn't (a) a string, and (b) the thing I specified I'm returning please?
All suggestions welcome, many thanks in advance for any help :)
In a CASE expression, all of the possible return values must be of the same data type. As written, the expression is trying to return one string and one integer.
If you want an empty string for your first output, you can CAST or CONVERT your second output to a character type value:
select
table1.field1,
table2.field1,
CASE (table2.field1)
WHEN -2 THEN ''
ELSE CAST(table2.field2 AS varchar(12)) --< 12 will cover any value of integer.
END as table2Field2,
table3.field4
from...
Is it possible you have your as table2field2 in the wrong location?
maybe try:
select
table1.field1,
table2.field1,
CASE (table2.field1)
WHEN -2 THEN ''
ELSE table2.field2
END as table2Field2,
table3.field4
from...
Because you do not want to answer me what is the database you use then I have to do it like this hehehe:
SQL Server: DEMO
select
t.col1,
CASE
WHEN convert(char,t.col1) = '-2' THEN 'aaa'
ELSE convert(char,(t.col2))
END test
from Tab1 t;
Oracle DEMO
select
t.col1,
CASE
WHEN to_char(t.col1) = '-2' THEN 'aaa'
ELSE to_char(t.col2)
END test
from tab1 t;

Problem with field not equal to null in case statement

So I have EXISTS in huge query which looks like this:
EXISTS(
SELECT
*
FROM
ExistTable
WHERE
ExTableFieldA = #SomeGuid AND
ExTableFieldB = MainTableFieldB AND
ExTableFieldA <> (
CASE
WHEN MainTableFieldZ = 10 THEN MainTableFieldYYY
ELSE NULL
END
)
)
The problem comes from ELSE part of CASE statement, this ExTableFieldA <> NULL will be always false. I could easily write another parameter #EmptyGuid and make it equal to '00000000-0000-0000-0000-000000000000' and everything will work but is this the best approach ?
Pretty much I want to execute another check into the exist for the small size of the records which return the "main" query.
How about removing the case and just using boolean logic?
WHERE ExTableFieldA = #SomeGuid AND
ExTableFieldB = MainTableFieldB AND
(MainTableFieldZ <> 10 OR ExTableFieldA <> MainTableFieldYYY)
I would also recommend that you qualify the column names by including the table alias.
Note: This does assume that MainTableFieldZ is not NULL. If that is a possibility than that logic can easily be incorporated.
ELSE NULL is implied even if you don't list it, but you could use ISNULL here.
ISNULL(ExTableFieldA,'') <> (
CASE
WHEN MainTableFieldZ = 10 THEN MainTableFieldYYY
ELSE ''
END
)
You may need to use some other value like 9999 instead of ''

How do I use a multi-value parameter with a CASE expression in SSRS?

I am trying to use a case expression to flag which records have any of the ID's listed in my parameter. My code is something like this:
SELECT
TRANSACTION_ID,
CASE WHEN CUSTOMER_ID IN (#PARAMETER) THEN 1 ELSE 0 END AS CUSTOMER_CLASS
It works fine if I only use one value when it asks for a parameter, but if I put more than one I get : An Expression of non-boolean type specified in a context where a condition is expected, near ','.
I've tried doing this several ways, including treating the parameter like it was a comma seperated string and trying to parse the substring. I can't figure out how the parameter is passed, but I keep getting problems.
I'm at wits end. Can anyone point me in the right direction?
As per your requirement, you should go for Dynamic query.
Below code is working perfect.
Declare #sql varchar(max),
#PARAMETER varchar(100) = '1,2,3,4' //For ex
set #sql =
'SELECT
TRANSACTION_ID,
CASE WHEN CUSTOMER_ID IN ('+#PARAMETER+') THEN 1 ELSE 0 END AS CUSTOMER_CLASS';
Execute(#sql)
case when [ReturnedBy] IN (SELECT Split FROM [dbo].[ufn_Split](#param_1, ',')) then 1 else 0 end

Is that possible to have an IF statement inside a SET?

I have a table in Oracle with a column named ERROR_CODE (which is a VARCHAR2) initially set to NULL for every value. I would like to update it with an UPDATE statement like in the following statement:
UPDATE SNAPSHOT_TEST
SET ERROR_CODE =
IF(...) THEN NVL2(ERROR_CODE, CONCAT(ERROR_CODE, ',8'), '9')
ELIF(...) THEN NVL2(ERROR_CODE, CONCAT(ERROR_CODE, ',9'), '9')
ELIF(...) ...
END IF;
I tried to use a CASE statement to achieve this result and it works but it's not what I need, because multiple conditions can match at the same time and if that happens I need to concatenate the error code as in the statement I inserted before, having '8,9' in the end, for example.
is there a way to achieve this in Oracle?
You could use CASE expression:
UPDATE SNAPSHOT_TEST
SET ERROR_CODE =
CASE WHEN ... THEN NVL2(ERROR_CODE, CONCAT(ERROR_CODE, ',8'), '9')
WHEN ... THEN NVL2(ERROR_CODE, CONCAT(ERROR_CODE, ',9'), '9')
ELSE ...
END;
having '8,9' in the end
UPDATE SNAPSHOT_TEST
SET ERROR_CODE =
ERROR_CODE || CASE WHEN ... THEN '8' END || CASE WHEN ... THEN '9' END
As the other answerers said, we would need some minimal sample data and sample conditions to recommend a solution.
For instance, reading "... multiple conditions ... having 8,9 in the end ..." makes me think of LISTAGG, but I cannot formulate this as an answer because I have not the slightest clue about the conditions.
multiple conditions can match at the same time and if that happens I need to concatenate the error code
So, concatenate the error codes, with a case expression deciding if each is needed:
update snapshot_test
set error_code =
ltrim(
case when (...) then ',8' end
|| case when (...) then ',9' end
|| case when (...) then ',10' end
...
, ',');
As they all add a comma, the ltrim removes the extra one created by the first match.
db<>fiddle demo with completely arbitrary and artificial conditions, since we have nothing real to work with.
(Rather belatedly, I realise this is pretty much what #LukaszSzozda's edit is doing; except this includes the commas.)
I managed to find a solution on my own: even if Lukasz's question, after his edit, may actually work, it is more performing in this case to have separate UPDATE in cascade as in the following snippet:
UPDATE SNAPSHOT_TEST
SET ERROR_CODE = NVL2(ERROR_CODE, CONCAT(ERROR_CODE, ',8'), '8')
WHERE (...);
UPDATE SNAPSHOT_TEST
SET ERROR_CODE = NVL2(ERROR_CODE, CONCAT(ERROR_CODE, ',9'), '9')
WHERE (...);
In this way, if the ERROR_CODE is NULL it will be set for the first time with the first value matched, otherwise another error code will be added with a comma.