Can I use the values from CASE expressions in other CASE expressions? - postgresql

SELECT
CASE -- result#1
WHEN .. then 'a'
WHEN .. then 'b'
END,
CASE -- result#2
WHEN .. then 'c'
WHEN .. then 'd'
END,
FROM table1
I have 2 CASE expressions above, can I use the result of both CASE expressions and create another CASE expression based on the values from both CASE expressions?
CASE
WHEN result1 IS NOT NULL and result2 IS NOT NULL THEN '...'
ELSE NULL
END

You cannot use the result of a case expression at the same "block" that it is developed in. You need a sub select or a CTE.
select case
when result1 is not null
and result2 is not null
then '...'
else null
end "Final Result"
from ( select case
when .. then 'a'
when .. then 'b'
else null
end result1
, case
when .. then 'c'
when .. then 'd'
else null
end result2
from table1
) sq
OR
with first_case (result11, result22) as
( select case
when .. then 'a'
when .. then 'b'
else null
end
, case
when .. then 'c'
when .. then 'd'
else null
end
from table1
)
select case
when result1 is not null
and result2 is not null
then '...'
else null
end "Final Result"
from first_case;

Related

Postgres CASE expression then null

The below query is part of a select query which I have got in my application
where
case when o.tracking_id <> '0' then a.account_id is null
and
o.status = 'N'
else
(
o.tracking_id = '0'
and
o.status = 'N'
)
END
I am having hardtime to understand the below line
Can you please tell me what does this exactly mean ?
case when o.tracking_id <> '0' then a.account_id is null
I wouldn't use a CASE expression here but instead would use the following logic:
WHERE
(o.tracking_id <> '0' AND a.account_id IS NULL AND o.status = 'N')
OR
(o.tracking_id = '0' AND o.status = 'N')
The condition is written somewhat clumsily. It is equivalent to this more readable expression:
where (o.tracking_id = '0' or a.account is null)
and o.status = 'N';

Multiple case in update postgres

I need to update 2 columns in table with same conditions. I know, that each of them would take a lot of time. How can I concatenate 2 updates into 1, which can be faster?
-- first update
update t1
set col1 =
case when cc1 is not NULL and cc1 <> 0 then 'A'
when cc2 is not NULL and cc2 <> 0 then 'B'
when cc3 is not NULL and cc3 <> 0 then 'C'
else null
end;
-- with same cond
update t1
set col2 =
case when cc1 is not NULL and cc1 <> 0 then 'qwe rty'
when cc2 is not NULL and cc2 <> 0 then 'qzaz wsx'
when cc3 is not NULL and cc3 <> 0 then 'zxcv asdf'
else 'pl ok'
end;
-- my effort to concatenate, dont work
update t1
set (col1, col2) =
(select c1, c2 from
(select case when t2.cc1 is not NULL and t2.cc1 <> 0 then 'A' as c1, 'qwe rty' as c2
when t2.cc2 is not NULL and t2.cc2 <> 0 then ('B', 'qaz wsx')
when t2.cc3 is not NULL and t2.cc3 <> 0 then ('C', ' zxcv asdf')
else (null, 'pl ok')
end
from t1 as t2 where t1.key_column1 = t2.key_column1 and t1.key_column2 = t2.key_column2 and t1.key_column3 = t2.key_column3) f)
;
This is the way I would do it.
WITH cte AS (SELECT * FROM
(VALUES(1, 'A', 'qwe rty'),(2, 'B', 'qaz wsx'),(3, 'C', 'zxcv asdf'),(4, NULL, 'pl ok')) v (id,c1,c2))
UPDATE so_demo
SET col1 = cte.c1, col2 = cte.c2
FROM cte WHERE cte.id = CASE WHEN COALESCE(cc1, 0) <> 0 THEN 1
WHEN COALESCE(cc2, 0) <> 0 THEN 2
WHEN COALESCE(cc3, 0) <> 0 THEN 3
ELSE 4 END;
By way of explanation, I have put the possible values into a cte assigning them an id in addition to the values. I can then put the case statement in the where clause generating the necessary id. Note the use of COALESCE to make the WHENs simpler to read.
One way is to use arrays.
UPDATE t1
SET (col1,
col2) = (SELECT x[1],
x[2]
FROM (SELECT CASE
WHEN cc1 IS NOT NULL
AND cc1 <> 0 THEN
ARRAY['A',
'qwe rty']
WHEN cc2 IS NOT NULL
AND cc2 <> 0 THEN
ARRAY['B',
'qzaz wsx']
...
ELSE
ARRAY[NULL,
'pl ok']
END) AS x
(x));
But in terms of runtime optimization the gain compared to just UPDATE ... SET col1 = CASE ..., col2 = CASE ... should be neglectable, if any.

How do I add a where clause <> 0 for case statement in postgresql?

I have a case statement where I am trying to add a where clause <> 0 for the case statement . However, I am not able to do as the error is saying the column name is not existed. This is the current code:
SELECT *,
CASE
when A.TestValue is null then
B.Collected
when B.Collected is null then
A.TestValue
END
as Actual_Value
FROM test_Table
where Actual_Value <> 0
CASE
when A.TestValue is null then B.Collected
when B.Collected is null then A.TestValue
END <> 0

NULLS LAST not working in ORDER BY with CASE

I faced strange problem.
Here is a PostgreSQL function:
CREATE FUNCTION public.search_companies_ordered(name character varying DEFAULT NULL::character varying, "categoryIds" integer[] DEFAULT NULL::integer[], "cityIds" integer[] DEFAULT NULL::integer[], departments public.department[] DEFAULT NULL::public.department[], "stockTemperatures" public.stock_temperature[] DEFAULT NULL::public.stock_temperature[], "order" public.search_companies_order DEFAULT 'createdAt'::public.search_companies_order, order_type public.order_type DEFAULT 'desc'::public.order_type) RETURNS SETOF public.company
LANGUAGE plpgsql STABLE
AS $$
begin
IF "search_companies_ordered"."order_type" = 'asc'::order_type THEN
return query
SELECT * FROM "search_companies"(
name := search_companies_ordered."name",
"categoryIds" := search_companies_ordered."categoryIds",
"cityIds" := search_companies_ordered."cityIds",
departments := search_companies_ordered.departments,
"stockTemperatures" := search_companies_ordered."stockTemperatures"
) AS c
ORDER BY (
CASE WHEN "search_companies_ordered"."order" = 'id'::search_companies_order THEN
c."id"
END,
CASE WHEN "search_companies_ordered"."order" = 'name'::search_companies_order THEN
c."name"
END,
CASE WHEN "search_companies_ordered"."order" = 'createdAt'::search_companies_order THEN
c."createdAt"
END,
CASE WHEN "search_companies_ordered"."order" = 'updatedAt'::search_companies_order THEN
c."updatedAt"
END,
CASE WHEN "search_companies_ordered"."order" = 'lastCommentAt'::search_companies_order THEN
c."lastCommentAt"
END,
CASE WHEN "search_companies_ordered"."order" = 'commentsCount'::search_companies_order THEN
c."commentsCount"
END
) ASC NULLS LAST;
ELSE
return query
SELECT * FROM "search_companies"(
name := search_companies_ordered."name",
"categoryIds" := search_companies_ordered."categoryIds",
"cityIds" := search_companies_ordered."cityIds",
departments := search_companies_ordered.departments,
"stockTemperatures" := search_companies_ordered."stockTemperatures"
) AS c
ORDER BY (
CASE WHEN "search_companies_ordered"."order" = 'id'::search_companies_order THEN
c."id"
END,
CASE WHEN "search_companies_ordered"."order" = 'name'::search_companies_order THEN
c."name"
END,
CASE WHEN "search_companies_ordered"."order" = 'createdAt'::search_companies_order THEN
c."createdAt"
END,
CASE WHEN "search_companies_ordered"."order" = 'updatedAt'::search_companies_order THEN
c."updatedAt"
END,
CASE WHEN "search_companies_ordered"."order" = 'lastCommentAt'::search_companies_order THEN
c."lastCommentAt"
END,
CASE WHEN "search_companies_ordered"."order" = 'commentsCount'::search_companies_order THEN
c."commentsCount"
END
) DESC NULLS LAST;
END IF;
return;
end;
$$;
Everything working fine, except NULLS LAST, that does't takes any effect on resulting records order.
I've tried to omit brackets in ORDER BY – no effect:
ORDER BY
CASE WHEN "search_companies_ordered"."order" = 'id'::search_companies_order THEN
c."id"
END,
CASE WHEN "search_companies_ordered"."order" = 'name'::search_companies_order THEN
c."name"
END,
CASE WHEN "search_companies_ordered"."order" = 'createdAt'::search_companies_order THEN
c."createdAt"
END,
CASE WHEN "search_companies_ordered"."order" = 'updatedAt'::search_companies_order THEN
c."updatedAt"
END,
CASE WHEN "search_companies_ordered"."order" = 'lastCommentAt'::search_companies_order THEN
c."lastCommentAt"
END,
CASE WHEN "search_companies_ordered"."order" = 'commentsCount'::search_companies_order THEN
c."commentsCount"
END
ASC NULLS LAST;
search_companies function is following:
CREATE FUNCTION public.search_companies(name character varying DEFAULT NULL::character varying, "categoryIds" integer[] DEFAULT NULL::integer[], "cityIds" integer[] DEFAULT NULL::integer[], departments public.department[] DEFAULT NULL::public.department[], "stockTemperatures" public.stock_temperature[] DEFAULT NULL::public.stock_temperature[]) RETURNS SETOF public.company
LANGUAGE sql STABLE
AS $$
SELECT DISTINCT ON (c."id")
c.*
FROM
public.company AS c
LEFT JOIN
"companyCities" cC ON c.id = cC."companyId"
LEFT JOIN
"companyCategories" cCat ON c.id = cCat."companyId"
LEFT JOIN
"companyVisit" cv ON c.id = cv."companyId"
WHERE (
CASE WHEN "search_companies"."name" is not null THEN
c.name ILIKE "search_companies"."name"
ELSE true END
) AND (
CASE WHEN "search_companies"."cityIds" is not null THEN
"search_companies"."cityIds" #> array[cC."cityId"]
ELSE true END
) AND (
CASE WHEN "search_companies"."categoryIds" is not null THEN
"search_companies"."categoryIds" #> array[cCat."categoryId"]
ELSE true END
) AND (
CASE WHEN "search_companies"."departments" is not null THEN
"search_companies"."departments" #> array[cCat.department]
ELSE true END
) AND (
CASE WHEN "search_companies"."stockTemperatures" is not null THEN
c."stockTemperatures" && "search_companies"."stockTemperatures"
ELSE true END
)
ORDER BY c."id";
$$;
Function search_companies is working.
select id, name, "lastCommentAt" from search_companies() order by "lastCommentAt" desc nulls last limit 100;
Where the problem is?
You're ENDing the CASEs early which creates multiple cases and that doesn't work well with order by.
Instead of:
ORDER BY (
CASE WHEN "search_companies_ordered"."order" = 'id'::search_companies_order THEN
c."id"
END,
CASE WHEN "search_companies_ordered"."order" = 'name'::search_companies_order THEN
c."name"
END,
CASE WHEN "search_companies_ordered"."order" = 'createdAt'::search_companies_order THEN
c."createdAt"
END,
CASE WHEN "search_companies_ordered"."order" = 'updatedAt'::search_companies_order THEN
c."updatedAt"
END,
CASE WHEN "search_companies_ordered"."order" = 'lastCommentAt'::search_companies_order THEN
c."lastCommentAt"
END,
CASE WHEN "search_companies_ordered"."order" = 'commentsCount'::search_companies_order THEN
c."commentsCount"
END
) ASC NULLS LAST;
Try:
ORDER BY
CASE WHEN "search_companies_ordered"."order" = 'id'::search_companies_order THEN
c."id"
WHEN "search_companies_ordered"."order" = 'name'::search_companies_order THEN
c."name"
WHEN "search_companies_ordered"."order" = 'createdAt'::search_companies_order THEN
c."createdAt"
WHEN "search_companies_ordered"."order" = 'updatedAt'::search_companies_order THEN
c."updatedAt"
WHEN "search_companies_ordered"."order" = 'lastCommentAt'::search_companies_order THEN
c."lastCommentAt"
WHEN "search_companies_ordered"."order" = 'commentsCount'::search_companies_order THEN
c."commentsCount"
END
ASC NULLS LAST;
ASC/DESC and NULLS FIRST/NULLS LAST do not affect all (comma separated) expressions in the ORDER BY clause, only the one where they stand.
So
... ORDER BY a, b, c DESC NULLS LAST
is the same as
... ORDER BY a ASC NULLS LAST,
b ASC NULLS LAST,
c DESC NULLS LAST
If you want all expressions sorted descending with the NULLs in the end, you'll have to append DESC NULLS LAST to each of the ORDER BY expressions.

SQL Statement with IN CASE

SELECT user
FROM userlist zH with(nolock)
where zH.user in (case when zh.trait='1' then ('B', 'HO', 'KO', 'PL','APP','2A','2B') else ('O') end)
can this statement with the where-in-case work? i hope you get what i meant. thanks.
You can use nested case statement, like
SELECT user
FROM userlist zH with(nolock)
where 'true' =
(case when zh.trait = '1'
then
case when zH.user in ('B', 'HO', 'KO', 'PL','APP','2A','2B')
then 'true'
else 'false'
end
else
case when zH.user = 'O'
then 'true'
else 'false'
end
end)
SELECT [user]
FROM userlist zH WITH ( NOLOCK )
WHERE ( zh.trait = '1'
AND zH.[user] IN ( 'B', 'HO', 'KO', 'PL', 'APP', '2A', '2B' )
)
OR ( zh.trait <> '1'
AND zH.[user] IN ( 'O' )
)