How to conditionally select a column in an Oracle query - sql

I want to do something like:
select (if lookup = 8 then 08 else lookup) lookup
, //more columns
from lookup_table
order by lookup
Unfortunately, Oracle doesn't seem to like this syntax, and I am failing to discover why or find what other function I should be using.
Basically, if the lookup value is 8, I want to get 08, otherwise I want the value of lookup. I'm sure I'm just being stupid.

You want a case statement:
select (case when lookup = 8 then 8 else lookup end) as lookup
If lookup is a character string, you probably want:
select (case when lookup = '08' then '08' else lookup end) as lookup
If lookup is an integer and you want to convert it to a string, then:
select (case when lookup = 8 then to_char(lookup, '00') else to_char(lookup, '00') end) as lookup
However, that would seem redundant to me.

Related

How to write case condition to check particular value exist among multiple values in sql?

I have a column in table which is having single/multiple value. I have to convert it yes/no based on condition.
example:
rendition_type_sys
distribution
uploaded, distribution
uploaded
single
I need to change the value based on condition. If column having distribution then value should convert as 'Yes' otherwise 'No'
Final Output:
rendition_type_sys
Yes
Yes
No
No
I tried one case statement but that is working for single value not multiple value-
case when ren.rendition_type__sys='distribution' then 'Yes' else 'No' end as rendition_type__sys
First, you should fix your data model so you are not storing multiple values in a string.
In the meantime, like should do what you want. For your example:
(case when ren.rendition_type__sys like '%distribution%'
then 'Yes' else 'No'
end) as rendition_type__sys
Note: In case "distribution" is part of an element name and you don't want that, you can check for delimiters. In Standard SQL, this would be:
(case when ', ' || ren.rendition_type__sys || ', ' like '%, distribution, %'
then 'Yes' else 'No'
end) as rendition_type__sys
The string concatenation operator may vary depending on the database you are using.
This below code would work assuming distribution is not part of any other discrete value; here is the code in a sample form:
WITH rt AS (
SELECT 'distribution' AS rendition_type_sys
UNION SELECT 'uploaded, distribution'
UNION SELECT 'uploaded'
UNION SELECT 'single'
)
SELECT CASE WHEN rt.rendition_type_sys LIKE 'distribution' THEN 'Yes' ELSE 'No' END AS Col
FROM rt
You might consider adding a table with for these "tags" so that they are discrete.

Using BETWEEN function

I have this query, using which I am trying to categorize my data. If the first character is between 0 and 9, I want to categorize it with the first character. If it is anything else including special characters or alphabets, then I want to use 10.
select CUSTOMER_ID, CASE
WHEN LEFT(CUSTOMER_ID, 1) BETWEEN 0 AND 9 THEN LEFT(CUSTOMER_ID, 1)
ELSE '10'
END
AS CUST_DIGIT
from CUSTOMER
I get this error when I run the above query:
Conversion failed when converting the nvarchar value 'A' to data type
int.
This is what my data looks like. Could you please help point what I could change.
Update your between values to string as '0' AND '9' then it will work.
Reason you are getting error is when you perform LEFT it will return string and you are comparing it with int as 0 AND 9 are int, So it will try to convert your result value from LEFT to int.
Your some of the record have digit at beginning of value those will work fine but when record comes like A46564 it won't be able to cast A to int and throw error.
SELECT CUSTOMER_ID, CASE
WHEN LEFT(CUSTOMER_ID, 1) BETWEEN '0' AND '9' THEN LEFT(CUSTOMER_ID, 1)
ELSE '10'
END AS CUST_DIGIT
FROM CUSTOMER
I would initially answer the same as #Karan.
Just for completeness... In your case, a possible alternative would be to use ISNUMERIC:
select
CUSTOMER_ID,
CASE
WHEN ISNUMERIC(LEFT(CUSTOMER_ID, 1)) = 1 THEN LEFT(CUSTOMER_ID, 1)
ELSE '10'
END AS CUST_DIGIT
from
CUSTOMER
And yet another approach would be to use the LIKE operator:
select
CUSTOMER_ID,
CASE
WHEN CUSTOMER_ID LIKE '[0-9]%' THEN LEFT(CUSTOMER_ID, 1)
ELSE '10'
END AS CUST_DIGIT
from
CUSTOMER

Forcing the color_code output to be a different string using CASE

So I was successfully able to pull the data that I need, however the issue now is that the color_code is a 2-digit number that not everyone knows. So, to rectify, I'd like to create a CASE statement that would replace each of these 84 unique color codes to a particular color (ex. 69 = Navy). To get the color code, I'm using a SUBSTRING on product_sku.
The real issue I'm having here is that I'm trying to paste this CASE statement I made into my query, but keep getting syntax errors at or near CASE:
(CASE
WHEN SUBSTRING(product_sku,10,2) = 09 THEN SUBSTRING(product_sku,10,2) = 'Black'
ELSE 'CHECK THIS SHIET FOO'
FROM l_nvr_ec_returns
END)
This is just for one color for testing purposes, of course, but what am I doing wrong? Or perhaps more importantly, where exactly does this snippet even go? After my initial SELECT clause? SOS!
Thank you,
Z
After some help from Caius Jard below, this is where I'm at. But getting an "INVALID SYNTAX" error
SELECT
item_name,
(SELECT
CASE SUBSTRING(product_sku,10,2)
WHEN '09' THEN 'Black'
WHEN '69' THEN 'Navy'
ELSE 'Unknown Color'
END as color
FROM l_nvr_ec_returns) color,
SUM(return_qty) number_of_returns,
number_of_returns/
(SELECT
SUM(return_qty)
FROM
l_nvr_ec_returns
WHERE
return_created_date BETWEEN '2019-10-01' AND '2019-10-31'
AND return_status NOT IN ('Cancelled', 'cancelled')
AND return_qty > 0
AND return_reason_desc = 'Color Not As Expected'
) return_rate
FROM
l_nvr_ec_returns
WHERE
return_created_date BETWEEN '2019-10-01' AND '2019-10-31'
AND return_status NOT IN ('Cancelled', 'cancelled')
AND return_qty > 0
AND return_reason_desc = 'Color Not As Expected'
GROUP BY item_name, color
ORDER BY color
Carefully edit your query to remove the characters obscured by red, leaving a trailing comma:
CASE is an expression that is supposed to be used in the select list, to convert a single SKU to a single color, per row of l_nvr_ec_returns
I was also going to add some detail along the lines of alexherm's comment.. I would seriously consider making a table with the 84 values for colors, if you can.. For example like:
--make a table of all our colors
SELECT DISTINCT
SUBSTRING(product_sku,10,2) as ColorCode,
'xxxxxxxxxxxxxxxxxxxxx' as ColorName
INTO ColorTable
FROM l_nvr_ec_returns
Now go and edit all the xxxxxxxxx to be proper color names, in every row
OR
Put your massive CASE in this query:
SELECT DISTINCT
SUBSTRING(product_sku,10,2) as ColorCode,
CASE SUBSTRING(product_sku,10,2)
WHEN '01' THEN 'Pink'
WHEN '02' THEN 'Green'
...
WHEN '84' THEN 'Silver'
END as ColorName
INTO ColorTable
FROM l_nvr_ec_returns
This will create all the correct color names from the get-go without needing to edit the table later
Then use it like:
SELECT *
FROM
l_nvr_ec_returns r
INNER JOIN colortable c ON SUBSTRING(r.product_sku,10,2) = c.colorcode
I'm not totally familiar with redshift, but I think it's postgres based. I would expect your case to work if it looks like:
SELECT
CASE SUBSTRING(product_sku,10,2)
WHEN '09' THEN 'Black'
WHEN '69' THEN 'Navy'
WHEN ... THEN ...
ELSE 'Unknown Color'
END as color
FROM l_nvr_ec_returns
CASE can have two forms:
CASE something
WHEN another_value_matches_something THEN return_value
WHEN anotheranother_value_matches_something THEN returnanother_value
...
CASE
WHEN something = another_value_matches_something THEN return_value
WHEN something = anotheranother_value_matches_something THEN returnanother_value
Which you choose depends on whether youre testing the same something or whether youre running different truth tests, like
CASE
WHEN name = 'John' THEN ...
WHEN age = 20 THEN ....
CASE typically has to have a single value expressed after its THEN. CASE in most DB cannot be used with expressions that do not produce a value
This could work:
WHERE
name =
CASE WHEN age = 2 THEN (SELECT MAX(petname) FROM pets) ELSE 'noname' END
This probably won't:
WHERE
name IN
CASE WHEN age = 2 THEN (SELECT name FROM pets) ELSE (SELECT 'noname') END
This is probably a syntax error:
WHERE
CASE WHEN SUBSTRING(x, 1, 2) = 'ab' THEN SUBSTRING(x, 5, 2) = 'cd'
I say probably because MySQL would probably evaluate SUBSTRING(x, 5, 6) = 'cd' as a boolean and return true or false depending on whether chars 5 and 6 of x were cd, but most major DBs wouldn't evaluate it as a boolean

Replacing a word with a number in SQL Server

I have a table which has 12 columns containing a word, I want to change this to a number. For instance: each of these 12 columns can have one of 5 pre-specified possible values of:
highly agree
agree
no opinion
disagree
highly disagree
I want to change these words with a number, the problem is the data type, it does not allow me to change a nvarchar data type to number, I even tried text data type to contain { highly agree, agree , no opinion , disagree, highly disagree } and then changed them to numbers but this error appeared:
Msg 402, Level 16, State 1, Line 1
The data types text and varchar are incompatible in the equal to operator.
The query I used was this:
[A1]= (case when [A1]='highly agree' then 1
when [A1]='agree' then 4
when [a1]='نظری ندارم' then 9
when [a1]='موافقم' then 16
when [a1]='کاملا موافقم' then 25
else [A1] end )
You dont need to convert your column to text data type, but you have to use your numbers as varchar in your case statement. You cannot mix up data types in the case statement
[A1]= (case when [A1]='highly agree' then '1' when [A1]='agree' then '4' when [a1]='نظری ندارم' then '9' when [a1]='موافقم' then '16' when [a1]='کاملا موافقم' then '25' else [A1] end )
Further to your question, if you want to keep the calculation on this field then you have to cast the whole column to Number. As an example you can use this query
[CalculatedColumn]= CAST(case when [A1]='highly agree' then '1'
when [A1]='agree' then '4'
when [a1]='نظری ندارم' then '9'
when [a1]='موافقم' then '16'
when [a1]='کاملا موافقم' then '25'
else '999' end ) AS INT) -- Any other number which can cast to integer
Try this:
SELECT (CASE A1 WHEN 'highly agree' THEN '1'
WHEN 'agree' THEN '4'
WHEN 'نظری ندارم' THEN '9'
WHEN 'موافقم' THEN '16'
WHEN 'کاملا موافقم' THEN '25'
ELSE A1
END) AS A1

Only select type int in a column?

I'm looking to select only the columns that I can average. (Int is the only I'm aware of, but if there are others, I would like to know.
select avg(case when <column> = int then <column> else 0 end)
This is what I would try, but it doesn't seem to work. When I try this:
Select Avg(<column>) as <alias>
It says:
ERROR: function avg(double precision) does not exist
I'm thinking I may need to add this to the from clause in a join statement, but I'm not exactly certain on how to do that.
The Postgres aggregate function for average is avg() and works for a range of numeric types including double precision. In particular, per documentation:
smallint, int, bigint, real, double precision, numeric, or interval
You can use pg_typeof() to determine the actual data type of any value (or column).
Identify columns
To ... select only the columns that I can average:
SELECT attname, atttypid::regtype::text
FROM pg_attribute
WHERE attrelid = 'tbl'::regclass
AND atttypid = ANY ('{int2,int,int8,real,float8,numeric,interval}'::regtype[])
AND attnum > 0
AND NOT attisdropped
ORDER BY attnum;
Dynamic computation
It's not a trivial task to dynamically determine the type of a column have the aggregation depend on it.
This would work (excluding the special case interval):
SELECT avg(CASE WHEN pg_typeof(t_int) = ANY ('{int2,int,int8,real,float8,numeric}'::regtype[])
THEN t_int::numeric ELSE NULL::numeric END) AS avg_t_int
,avg(CASE WHEN pg_typeof(t_num) = ANY ('{int2,int,int8,real,float8,numeric}'::regtype[])
THEN t_num::numeric ELSE NULL::numeric END) AS avg_t_num
,avg(CASE WHEN pg_typeof(t_txt) = ANY ('{int2,int,int8,real,float8,numeric}'::regtype[])
THEN t_txt::numeric ELSE NULL::numeric END) AS avg_t_txt
FROM tbl;
SQL Fiddle demonstrating both.
For big tables it will be more efficient, to check the column type before you assemble your statement dynamically ...
Expression
regexp_replace(val, '\d', '', 'g')
gives empty string if val contains only digits, so
select case regexp_replace(val, '\d', '', 'g')
when '' then val::int
else null end
gives integer value if val represents unsigned integer, null otherwise.