PostgreSQL Conditional selects - postgresql

I have written a recursive function and depending on the output I need to select different fields. My question is now, how can I do this multiple times without having to call the function more then once? What I'm doing right now is just using the CASE WHEN... condition and checking every time what the functions return. (This is only a pseudo code and doesn't do anything real, it's just for understanding)
SELECT
id,
(CASE WHEN (function(id) > 0)
THEN field1
ELSE field2
END) as value1,
(CASE WHEN (function(id) > 0)
THEN field3
ELSE field4
END) as value2,
(CASE WHEN (function(id) > 0)
THEN field5
ELSE field6
END) as value3
FROM table1
...
How can I optimize this query and call the function only once?
Thanks in advance!

If the function is declared IMMUTABLE, it is safe to call it many times, as it will not be reevaluated.
From the docs:
IMMUTABLE indicates that the function cannot modify the database and always returns the same result when given the same argument values; that is, it does not do database lookups or otherwise use information not directly present in its argument list. If this option is given, any call of the function with all-constant arguments can be immediately replaced with the function value.

use a subquery :
SELECT foo, bar, result
FROM (
SELECT ..., function(id) AS result
....
) as tmp

You may be able to use some funky tuple thing like:
SELECT id,
CASE WHEN function(id) > 0
THEN (field1, field3, field5)
ELSE (field2, field4, field6)
END as (value1, value2, value3)
but I have no experience with this syntax

Related

Returning values based on delimited string entries

In TSQL, the string in the database record is 'A/A/A' or 'A/B/A' (examples). I want to parse the string and for the first instance return '1'; in the 2nd instance, return '2'. That is, if all the values between the separators are the same, return a value; otherwise return another value. What is the best way to do this?
A bit blind answer:
Read the whole value in a variable. Read the first value part in another:
declare #entire nvarchar(max), #single nvarchar(max)
select/set #entire=....
set #single=left(#entire,charindex('/',#entire)-1)
Compare entire with #single replicated after removing slashes:
set #entire=replace(#entire,'/','')
select case when replicate(#single,len(#entire)/len(#single))=#entire
then 1 else 0 end as [What you want]
Something like this should work:
SELECT
x.*,
CASE
WHEN N > 1 THEN 0
ELSE 1
END Result
FROM (
SELECT
t.Column1,
t.Column2,
t.Column3,
t.SomeColumn,
COUNT(DISTINCT s.value) N
FROM dbo.YourTable t
OUTER APPLY STRING_SPLIT(t.SomeColumn,'/') s
GROUP BY
t.Column1,
t.Column2,
t.Column3,
t.SomeColumn
) x
;
Based on your simple example (no edge cases accounted for) the following should work for you:
select string, iif(replace(s,v,'')='',1,0) as Result
from t
cross apply (
values(left(string,charindex('/', string)-1),(replace(string,'/','')))
)s(v,s);
Example Fiddle

postgres case statement with subquery

I have a subquery like this
with subquery as (select host from table_A where << some condition >>)
and in my main query, I am querying data from another table called table_B, and one of the columns is called destination_host. Now I need to check if the destination_host is in the list returned from my subquery, then I want to output TypeA in my select statement or else TypeB. My select statement looks something like
select name, place, destination_host
from table_B
where <<some condition>>
I want to output a fourth column that is based on a condition check, let's say we call this host_category and if the destination_host value exists in the subquery then I want to add value typeA or else typeB. Please can you help me understand how to write this. I understand that it is hard to provide guidance if you don't have actual data to work with.
I tried using case statements such as this one:
when (destination_host in (select host from subquery)) THEN 'typeA'
when (destination_host not in (select host from subquery)) THEN 'typeB'
end as host_category
but I don't think this is the way to solve this problem.
I would use EXISTS:
WITH subquery AS (...)
SELECT CASE WHEN EXISTS (SELECT 1 FROM subquery
WHERE subquery.host = table_b.destination_host)
THEN 'typeA'
ELSE 'typeB'
END
FROM table_b;
With queries like that, you have to take care of NULL values. If table_b.destination_host is NULL, the row will always show up as typeB, because NULL = NULL is not TRUE in SQL.

Detect not contemplated values in a CASE statement evaluation

Is there a way in T-SQL to collect all not contemplated values in a CASE condition and insert them in a table?
For example:
A SELECT that reads a table that has in Col1 the values A,B,C. This SELECT has a CASE that goes like this: CASE WHEN Col1 = 1 THEN ... WHEN Col1 = B THEN ... ELSE NULL END AS NewCol1
I would like to detect values like C, values that are not contemplated in Col1.
I could get them like this: (...) ELSE Tabl1.Col1 but I need the CASE statement to end with ELSE NULL.
You can get a list of these values like this:
SELECT DISTINCT Col1
FROM Table
WHERE Col1 not in (1,...,B)
As #avery_larry suggested, I used a debug flag, giving my query two behaviours. I could call a function/stored with the parameter and if it's up INSERT the values into a desired output.

how to put nested case-when condition in postgresql query

i want to write nested case when condition in query to store the value that will come from one case when condition and another case when condition into same new column.to get this kind of result i am writing the query as:
(case when sq_name_new1 like format('%%%s%%',demo.name) THEN count(sq_name_new1) else (when demo.empcode is not null then count(demo.id) End) END) AS indivisual from res_scheduledjobs
in the above query demo.name column comes from CTE.so my whole query look like:
with demo(empcode,id,name) as
(select hr_employee.emp_code,hr_employee.id,concat(resource_resource.name,' ',hr_employee.middle_name,' ',hr_employee.last_name) as name from hr_employee inner join resource_resource on resource_resource.id=hr_employee.resource_id)
select demo.empcode,demo.name,sq_name_new1,(case when sq_name_new1 like format('%%%s%%',demo.name) THEN count(sq_name_new1) else (when demo.empcode is not null then count(demo.id) End) END) AS indivisual from res_scheduledjobs LEFT JOIN demo on demo.id=res_scheduledjobs.assigned_technician group by res_scheduledjobs.assigned_technician,sq_name_new1,demo.empcode,demo.name ;
i just want to store the count of (sq_name_new1) column into INDIVISUAL Column and the count of (demo.id) column into same column,that is in INDIVISUAL,if the first case condition does not match.
but when i am executing my query it throw an error.that is,something is wrong in the syntax of case when condition.
please help me yo write the correct nested case-when condition.
CASE ... WHEN ... END is an expression. It can be nested like any other expression.
CASE
WHEN condition THEN
CASE
WHEN othercondition THEN
....
END
END
The first semicolon ; should be removed as in #Craig Ringer's answer.
SELECT
CASE WHEN condition1 THEN
CASE
WHEN condition1.1 THEN
...
END
END AS column_name
FROM table_name;

Sorting selection results using a bound parameter in sqlite with the C/C++ API

I'm wondering if it's possible to parameterize the sort column in sqlite.
I'd like to prepare a single sqlite3_stmt like this (omitting checking the return codes for simplicity's sake).
sqlite3_stmt* the_statement;
const char *sql = "SELECT column1, column2, column3 FROM table1 WHERE column4 = ? ORDER BY ? ASC"
sqlite3_prepare_v2(database, sql, -1, &the_statement, NULL)
and use it like this
sqlite3_bind_int(the_statement, 1, 1);
sqlite3_bind_int(the_statement, 2, COLUMN_TO_SORT_BY);
while (sqlite3_step(the_statement) == SQLITE_ROW){
//Do something with each row.
}
sqlite3_reset()
When I execute this code changing the value of COLUMN_TO_SORT_BY from 1 to 3 my results are always returned in the same order (I think the order they are stored in the table, but it could also be as sorted by column1).
So, my question is: Can you parameterize the ORDER BY argument in a sqlite expression when using the C API?
The problem is that the value you pass in is being treated as an expression, which evaluates to a fixed value - '1' in the first case, '3' in the second. You could compose a CASE statement to order by, but it could get unwieldy quickly. Perhaps something like:
ORDER BY
CASE ?
WHEN 1 THEN column1
WHEN 2 THEN column2
WHEN 3 THEN column3
END
The CASE ... END expression isn't necessary, since the SQLite SELECT docs mention:
If the ORDER BY expression is a
constant integer K then the expression
is considered an alias for the K-th
column of the result set (columns are
numbered from left to right starting
with 1).
So simply use the following statement:
SELECT column1, column2, column3 FROM sometable ORDER BY ?
And bind the column index:
sqlite3_bind_int(stmt, 1, col_index);