SQL Case Statment - sql

How do I write a CASE statement within my SELECT to do the following:
I have a column called Values. This column can have the value b, c, or a. If it has the value b, I want the SELECT to return big; if c return small, and if a return large

Case [Values]
When 'a' Then 'large'
When 'b' Then 'big'
When 'c' Then 'small'
End

select
case values
when 'a' then 'large'
when 'b' then 'big'
when 'c' then 'small'
end as values_decoded
from table

Another approach that can give you similar performance is this, which takes advantage of comparing single character strings:
SELECT
SUBSTRING('large', 1, DATALENGTH('large')*(1-abs(sign(ASCII([Values]) - ASCII('a'))))) +
SUBSTRING('big', 1, DATALENGTH('big')*(1-abs(sign(ASCII([Values]) - ASCII('b'))))) +
SUBSTRING('small', 1, DATALENGTH('small')*(1-abs(sign(ASCII([Values]) - ASCII('c')))))
FROM table

Related

to write case when to another case when in one select Google Big Query

I'm a new user in Google Big Query and I want to write two "Case when...." in one select, and they should be connected to each other
For example:
Case when number = 1 then 'one' when number=2 then 'two' else 'other' end as mark
Case when mark = 'one' then 'red' when mark='two' then 'orange' else 'other' end as color
But I have mistake like 'Unrecognized name: mark at [8:14]'
I used all the options with apostrophe but still have the same result.
I also try to find answer in BigQuery Documentation but it was unsuccessfully.
Is it even possible to do this?
I assume you're using Google BigQuery's current SQL syntax support, as opposed to their older SQL implementation.
SQL does not allow column expressions to refer to other column aliases in the same level, so you will need to use an outer-query. Yes, it's dumb, blame the ISO SQL committee for creating such a terribly unergonomic language.
You'll want something like this:
I'm not a BigQuery user so I don't know if this syntax is fully supported, but I believe the query below is ISO SQL-compliant).
Note the use of CASE <expr> WHEN <value> instead of CASE WHEN <expr> = <value> btw.
SELECT
t.*
t.number,
CASE t.mark
WHEN 'one' THEN 'red'
WHEN 'two' THEN 'orange' ELSE 'other'
END AS color
FROM
(
SELECT
y.*,
CASE y.number
WHEN 1 THEN 'one'
WHEN 2 THEN 'two' ELSE 'other'
END AS mark
FROM
someTable AS y
) AS t
Another alternative is to use a CTE, which is essentially the same as the above but the inner-query is expressed above the outer-query instead of inside it (and it can be reused more easily in the same query):
WITH t AS (
SELECT
y.*,
CASE y.number
WHEN 1 THEN 'one'
WHEN 2 THEN 'two' ELSE 'other'
END AS mark
FROM
someTable AS y
)
SELECT
t.*
t.number,
CASE t.mark
WHEN 'one' THEN 'red'
WHEN 'two' THEN 'orange' ELSE 'other'
END AS color
FROM
t;
Consider also below option (BigQuery)
select *,
Case mark when 'one' then 'red' when 'two' then 'orange' else 'other' end as color
from data, unnest([
struct(Case number when 1 then 'one' when 2 then 'two' else 'other' end as mark)
])
Obviously this is a matter of preferences, but in my practice, I am using above approach much more frequently than subquery and/or cte
You can test it using dummy data as in below example
with data as (
select 1 number union all
select 2 union all
select 3
)
select *,
Case mark when 'one' then 'red' when 'two' then 'orange' else 'other' end as color
from data, unnest([
struct(Case number when 1 then 'one' when 2 then 'two' else 'other' end as mark)
])
with output

Suggested sequence of responses in query

I have such values in the letter column:
A, B, C, D, E, **X**.
I would like the select to return to me such an order of
A, B, **X**, C, D, E.
I tried with ORDER BY, but I don't know if it's a good way, or it should be SELECT Top 2 and next...
If it's only one character:
order by case when MyColumn < 'C' then 1
when MyColumn = 'X' then 2
else 3
end,
MyColumn
In this case you should assign a numeric value to each of the possible values in order to get them in the desired way. It could be something like
order by case when column = 'A' then 1
when column = 'B' then 2
when column = 'C' then 3
when column = 'X' then 4
...
else 99999999
end
This can be done using a case expression to re-position the 'X' between 'B' and 'C' as follows.
order by case when MyColumn = 'X' then 'BB' else MyColumn end

PostgreSQL, SELECT CASE COALESCE

I need to 'name' categories: mycat is a text column with possible values '0' to '4'.
SELECT CASE mycat
WHEN '0' THEN 'ZERO'
WHEN '1' THEN 'ONE'
WHEN '2' THEN 'TWO'
WHEN '3' THEN 'THREE'
WHEN '4' THEN 'OTHER'
END AS my_category,
COALESCE(SUM(col1), 0),
COALESCE(SUM(col2), 0),
COALESCE(SUM(col3), 0)
FROM mytable
GROUP BY mycat
ORDER BY mycat;
That works OK, but I have some an error in my program which very rarely writes null (or '' as I can see in pgAdmin). In such cases I have to treat that '' the same as '0'.
But I can't get that!
I try like this:
SELECT CASE COALESCE(mycat, '0')
But this doesn't solve it at all.
How to get that '' will be summed and grouped together with '0' category?
PostgreSQL 9.3, Windows.
you need to use COALESCE in the group by and order by also similar to how you planned to change the case expression, but postgres is giving error , so another option is to wrap your statement in a subquery and do group by
SELECT my_category,
COALESCE(SUM(col1), 0),
COALESCE(SUM(col2), 0),
COALESCE(SUM(col3), 0)
FROM
(
SELECT CASE coalesce(mycat ,'0')
WHEN '0' THEN 'ZERO'
WHEN '1' THEN 'ONE'
WHEN '2' THEN 'TWO'
WHEN '3' THEN 'THREE'
WHEN '4' THEN 'OTHER'
WHEN '' THEN 'ZERO'
END AS my_category,
col1,
col2,
col3
FROM mytable
) T
GROUP BY my_category
ORDER BY my_category
You can have this without subquery. You could repeat the expression in the GROUP BY and ORDER BY clause. But it's much simpler to use the ordinal number of the output column instead:
SELECT CASE mycat
WHEN '1' THEN 'ONE'
WHEN '2' THEN 'TWO'
WHEN '3' THEN 'THREE'
WHEN '4' THEN 'OTHER'
ELSE 'ZERO' -- catches all other values
END AS my_category
, COALESCE(SUM(col1), 0) AS sum1
, COALESCE(SUM(col2), 0) AS sum2
, COALESCE(SUM(col3), 0) AS sum3
FROM mytable
GROUP BY 1
ORDER BY 1;
I chose the simplest and fastest code. The ELSE branch catches 0, '' and NULL - or any other value not yet filtered! But you say there are no others.
A couple of rants:
mycat is 'text' column with possible values '0' to '4'.
This is wrong in two ways.
Obviously, there are empty strings ('') and / or NULL values, too.
With that fixed, integer, smallint, of "char" with a CHECK cnstraint would be sensible choices for the data type. (Maybe even enum.) text, not so much.
To find out your actual range of values:
SELECT mycat, count(*) AS ct
FROM mytable
GROUP BY 1
ORDER BY 2 DESC;
If your client obfuscates NULL and empty values, test with mycat IS NULL. You need to know and understand the difference in many situations.
This orders by the resulting text in my_category like: ONE, OTHER, THREE, TWO, ZERO? I doubt you want that.

oracle adding, then avg with null

I have sql like:
select avg(decode(type, 'A', value, null) + decode(type, 'B', value, null)) from table;
The problem with this is some of these types can be null, so the addition part will result in null because adding anything to null makes it null. So you might think I could change the decode from null to 0, but that seems to make the avg() count it as part of it's averaging, but it shouldn't/I don't want it counted as part of the average.
Ideally the addition would just ignore the nulls and just not try to add them to the rest of the values.
So let's say my numbers are:
5 + 6 + 5
3 + 2 + 1
4 + null + 2
They total 28 and I'd want to divide by 8 (ignore the null), but if I change the null to 0 in the decode, the avg will then divide by 9 which isn't what I want.
As written, your code should always return null, since if the first decode returns value, then the second decode must always return null. I'm going to assume that you made an error in genericizing your code and that what you really meant was this:
avg(decode(type1, 'A', value1, null) + decode(type2, 'B', value2, null))
(Or, instead of type1, it could be a.type. The point is that the fields in the two decodes are meant to be separate fields)
In this case, I think the easisest thing to do is check for nulls first:
avg(case when type1 is null and type2 is null then null
else case type1 when 'A' then value1 else 0 end
+ case type2 when 'B' then value2 else 0 end
end)
(I replaced decode with case because I find it easier to read, but, in this case decode would work just as well.)
This is overcomplicated to do a sum here. Juste output the values with a CASE, and you are done.
SELECT AVG(
CASE WHEN type = 'A' OR type = 'B'
THEN value
ELSE null
END
)
FROM table
A simple workaround would be to calculate the average yourself:
select
-- The sum of all values with type 'A' or 'B'
sum(decode(type, 'A', value, 'B', value, 0)) /
-- ... divided by the "count" of all values with type 'A' or 'B'
sum(decode(type, 'A', 1, 'B', 1, 0))
from table;
A SQLFiddle example
But the way AVG() works, it would probably be sufficient, if you just removed the addition and put everything in a single DECODE()
select avg(decode(type, 'A', value, 'B', value, null)) from table
The logic here is a bit complicated:
select avg((case when type = 'A' then value else 0 end) + (case when type = 'B' then value else 0 end))
from table
where type in ('A', 'B')
The where clause guarantees that you have at least one "A" or "B". The problem is arising when you have no examples of "A" or "B".

SQL: Alias Column Name for Use in CASE Statement

Is it possible to alias a column name and then use that in a CASE statement? For example,
SELECT col1 as a, CASE WHEN a = 'test' THEN 'yes' END as value FROM table;
I am trying to alias the column because actually my CASE statement would be generated programmatically, and I want the column that the case statement uses to be specified in the SQL instead of having to pass another parameter to the program.
This:
SELECT col1 as a,
CASE WHEN a = 'test' THEN 'yes' END as value
FROM table;
...will not work. This will:
SELECT CASE WHEN a = 'test' THEN 'yes' END as value
FROM (SELECT col1 AS a
FROM TABLE)
Why you wouldn't use:
SELECT t.col1 as a,
CASE WHEN t.col1 = 'test' THEN 'yes' END as value
FROM TABLE t;
...I don't know.
I think that MySql and MsSql won't allow this because they will try to find all columns in the CASE clause as columns of the tables in the WHERE clause.
I don't know what DBMS you are talking about, but I guess you could do something like this in any DBMS:
SELECT *, CASE WHEN a = 'test' THEN 'yes' END as value FROM (
SELECT col1 as a FROM table
) q
#OMG Ponies - One of my reasons of not using the following code
SELECT t.col1 as a,
CASE WHEN t.col1 = 'test' THEN 'yes' END as value
FROM TABLE t;
can be that the t.col1 is not an actual column in the table. For example, it can be a value from a XML column like
Select XMLColumnName.value('(XMLPathOfTag)[1]', 'varchar(max)')
as XMLTagAlias from Table
It should work. Try this
Select * from
(select col1, col2, case when 1=1 then 'ok' end as alias_col
from table)
as tmp_table
order by
case when #sortBy = 1 then tmp_table.alias_col end asc
I use CTEs to help compose complicated SQL queries but not all RDBMS' support them. You can think of them as query scope views. Here is an example in t-sql on SQL server.
With localView1 as (
select c1,
c2,
c3,
c4,
((c2-c4)*(3))+c1 as "complex"
from realTable1)
, localView2 as (
select case complex WHEN 0 THEN 'Empty' ELSE 'Not Empty' end as formula1,
complex * complex as formula2
from localView1)
select *
from localView2
Nor in MsSql
SELECT col1 AS o, e = CASE WHEN o < GETDATE() THEN o ELSE GETDATE() END
FROM Table1
Returns:
Msg 207, Level 16, State 3, Line 1
Invalid column name 'o'.
Msg 207, Level 16, State 3, Line 1
Invalid column name 'o'.
However if I change to CASE WHEN col1... THEN col1 it works
If you write only equal condition just:
Select Case columns1 When 0 then 'Value1'
when 1 then 'Value2' else 'Unknown' End
If you want to write greater , Less then or equal you must do like this:
Select Case When [ColumnsName] >0 then 'value1' When [ColumnsName]=0 Or [ColumnsName]<0 then
'value2'
Else
'Unkownvalue' End
From tablename
Thanks
Mr.Buntha Khin
SELECT
a AS [blabla a],
b [blabla b],
CASE c
WHEN 1 THEN 'aaa'
WHEN 2 THEN 'bbb'
ELSE 'unknown'
END AS [my alias],
d AS [blabla d]
FROM mytable
Not in MySQL. I tried it and I get the following error:
ERROR 1054 (42S22): Unknown column 'a' in 'field list'
In MySql, alice name may not work, therefore put the original column name in the CASE statement
SELECT col1 as a, CASE WHEN col1 = 'test' THEN 'yes' END as value FROM table;
Sometimes above query also may return error, I don`t know why (I faced this problem in my two different development machine). Therefore put the CASE statement into the "(...)" as below:
SELECT col1 as a, (CASE WHEN col1 = 'test' THEN 'yes' END) as value FROM table;
Yes, you just need to add a parenthesis :
SELECT col1 as a, (CASE WHEN a = 'test' THEN 'yes' END) as value FROM table;
make it so easy.
select columnnameshow = (CASE tipoventa
when 'CONTADO' then 'contadito'
when 'CREDITO' then 'cred'
else 'no result'
end) from Promocion.Promocion