to write case when to another case when in one select Google Big Query - google-bigquery

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

Related

How to use Postgres CASE simple/short-hand syntax with multiple conditions?

I know with Postgres CASE expression, you can simplify it down to:
SELECT a,
CASE a WHEN 1 THEN 'one'
WHEN 2 THEN 'two'
ELSE 'other'
END
FROM test;
...so you don't have to write etc...
CASE
WHEN a = 1 THEN ''
WHEN a = 2 THEN ''
.
..
...
WHEN a = 99 or a = 100 THEN ''
ELSE '' END
But is there a way to do this on multiple conditions with a keyword like ILIKE or LIKE? i.e.
SELECT a,
CASE a WHEN LIKE '1' or LIKE 'one' THEN 'one'
WHEN LIKE '2' and (LIKE 'two' or LIKE 'too') THEN 'two'
ELSE 'other'
END
FROM test;
Obviously this above doesn't work and I was trying some other variations but could not get it to work (if its possible)?
No, the short CASE syntax only works for a single condition per branch, and the comparison must be with the = operator. Use the other syntax for what you want.
You could use Postgres' regex operator here:
SELECT a,
CASE WHEN a ~ '^(1|one)$' THEN 'one'
WHEN a ~ '^(2|two)$' THEN 'two'
ELSE 'other'
END
FROM test;

Identify last record in CASE

Probably an easy one... I have a SQL query along the lines...
SELECT a,
CASE WHEN a=1 THEN 'one'
WHEN a=2 THEN 'two'
ELSE 'other'
END
FROM test;
(from the docs)
I want to identify the last record in the set and act on that condition.
There are two possible scenarios from what you have explained in your question.
One of them is the one in which for the max value found in column a you want to display a certain message:
SELECT
a
, CASE
WHEN a = 1 THEN 'ONE'
WHEN a = 2 THEN 'TWO'
WHEN a = (SELECT MAX(a) FROM test) THEN 'MAX'
ELSE 'OTHER'
END
FROM TEST;
The other possible scenario is that only for the last record in the table you want to display that certain message. And in that scenario your query needs to change to:
SELECT
a
, CASE
WHEN a = 1 THEN 'ONE'
WHEN a = 2 THEN 'TWO'
WHEN a = (SELECT TOP 1 a FROM TEST ORDER BY a DESC) THEN 'MAX'
ELSE 'OTHER'
END
FROM TEST
ORDER BY A;

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.

SQL Server - Case Statement

I'm almost certain you cannot do this within the context of the case statement, and I haven't been able to find any documentation about it, but is it possible to do the following:
SELECT CASE WHEN testValue > 2
THEN testValue(Without Repeating it) ELSE FailValue)
END
FROM Table
A better more thorough example:
Select CASE WHEN (Foo-stuff+bar) > 2
THEN Conditional statement without >2 Else "Fail"
END
FROM TABLE
I am looking for a way to create a select without repeating the conditional query.
EDIT: Due to a poor example on my part, and the lack of answers I was looking for:
testValue = (Table.A / Table.B) * Table.C Table.D
SELECT CASE WHEN testValue > 2
THEN testValue ELSE FailValue)
END
FROM Table
Like so
DECLARE #t INT=1
SELECT CASE
WHEN #t>0 THEN
CASE
WHEN #t=1 THEN 'one'
ELSE 'not one'
END
ELSE 'less than one'
END
EDIT:
After looking more at the question, I think the best option is to create a function that calculates the value. That way, if you end up having multiple places where the calculation needs done, you only have one point to maintain the logic.
The query can be written slightly simpler, like this:
DECLARE #T INT = 2
SELECT CASE
WHEN #T < 1 THEN 'less than one'
WHEN #T = 1 THEN 'one'
ELSE 'greater than one'
END T
I am looking for a way to create a select without repeating the conditional query.
I'm assuming that you don't want to repeat Foo-stuff+bar. You could put your calculation into a derived table:
SELECT CASE WHEN a.TestValue > 2 THEN a.TestValue ELSE 'Fail' END
FROM (SELECT (Foo-stuff+bar) AS TestValue FROM MyTable) AS a
A common table expression would work just as well:
WITH a AS (SELECT (Foo-stuff+bar) AS TestValue FROM MyTable)
SELECT CASE WHEN a.TestValue > 2 THEN a.TestValue ELSE 'Fail' END
FROM a
Also, each part of your switch should return the same datatype, so you may have to cast one or more cases.
We can use case statement Like this
select Name,EmailId,gender=case
when gender='M' then 'F'
when gender='F' then 'M'
end
from [dbo].[Employees]
WE can also it as follow.
select Name,EmailId,case gender
when 'M' then 'F'
when 'F' then 'M'
end
from [dbo].[Employees]

SQL Case Statment

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