Function which returns type runs multiple times - sql

This is my first question here so sorry if I'm doing something wrong.
I have a function in PostgreSQL which returns a type and I want to display all fields from that type.
At first I was doing the following SQL:
SELECT (FC_FUNCTION(FIELD_A, FIELD_B, FIELD_C)).*
FROM TABLE
But I noticed that it was running way too slow. After checking it looked like it was running the function again for each field the type had. Changing the SQL to the following not only returned the same results, but was way faster:
SELECT (X).*
FROM (SELECT FC_FUNCTION(FIELD_A, FIELD_B, FIELD_C) AS X FROM TABLE) A
Is this the correct way of doing it? It feels to me more of a work around than a solution. Thanks!

This is documented:
[...] these two queries have the same result:
SELECT (myfunc(x)).* FROM some_table;
SELECT (myfunc(x)).a, (myfunc(x)).b, (myfunc(x)).c FROM some_table;
Tip
PostgreSQL handles column expansion by actually transforming the first form into the second. So, in this example, myfunc() would get invoked three times per row with either syntax. If it's an expensive function you may wish to avoid that, which you can do with a query like:
SELECT m.* FROM some_table, LATERAL myfunc(x) AS m;
Placing the function in a LATERAL FROM item keeps it from being invoked more than once per row. m.* is still expanded into m.a, m.b, m.c, but now those variables are just references to the output of the FROM item. (The LATERAL keyword is optional here, but we show it to clarify that the function is getting x from some_table.)

Related

Ordering output of LIST in Snowflake

I've been using the LIST command to check the files staged to a table in Snowflake. However, the data is unordered and I'd like to order it by last_modified. I tried embedding it into a SELECT query like this:
SELECT *
FROM LIST #MY_DATABASE.MY_SCHEMA.%my_table/path/to/data PATTERN = '.*[.]csv.*'
However, this query fails to compile. I've tried preceding LIST with the CALL keyword as well, but no luck there. I've even tried assigning it to a local variable, but that doesn't work either. The data appears to be tabular so I'm not sure why I can't work with it.
How can I query on the output of LIST?
I am personally using the following "hacky" solution:
Start by executing the "list" command.
I Then use the result_scan function combined with last_query_id function to fetch the results of that query, as this point I can start querying the data, here's how it looks:
LIST #MY_DATABASE.MY_SCHEMA.%my_table/path/to/data PATTERN = '.*[.]csv.*'
WITH data(name, size, md5, last_modified) as (
SELECT * FROM table(result_scan(last_query_id()))
)
select *
from data
order by last_modified desc;
Obviously this is a manual hack as I retrieve the last query id, if you can't ensure this property you need to get the actual query id and use that explicitly instead.

Sql Limit clause based in input Parameter

I have been trying to find a solution for a limit-clause based on an input parameter from a Json-File. The current code looks somewhat like this
With myJsonTable (JsonText)
as (
Select JsonText)
Select * from Data
Where...
Limit
Case
WHEN (Select JSON_VALUE(JsonText, '$."Amount"') From myJsonTable is not null
THEN (Select JSON_VALUE(JsonText, '$."Amount"') From myJsonTable)
ELSE (10000000)
END
Which I cant seem to get work. The Output I am getting is
Non-negative integeter value expected in LIMIT clause
Is there a way to cast the select done? Trying different Selects anywhere in the Case clause caused the same error.
Exasol only allows constant expression in the limit clause, so it's not directly possible to specify a select statement that references myJsonTable there.
However, you can workaround this issue by using a approach similar to SQL query for top 5 results without the use of LIMIT/ROWNUM/TOP

PostgreSQL: Meaning of 'AS f(x)' Clause in SELECT Statement

In a presentation on Window functions made by EDB (https://youtu.be/XO1WnmJs9RI), they start out with what they call the simplest form of a window function as this:
SELECT *
FROM generate_series(1, 10) AS f(x);
What is the meaning of the AS f(x) clause at the end of this statement? I searched the documentation under both the SELECT command and the window function, and cannot find any explanation for this syntax. I know that the AS portion allows us to rename the column, but I am clueless on the f(x) part.
This is simply a table alias that defines the result of generate_series():
The table reference is f.
The column reference is x.
The as is optional (and I leave it out of table aliases).
So, you could write the select as:
select f.x
This is handy when you want to use the value for other purposes, such as calculations and joins.

VBA/SQL: Nested Query, Baffling Data Mismatch

The basic idea: I want a list of all of the processes that exist within a certain division. Processes are related to OperationalUnits, which are related to Divisions.
The query I want:
SELECT ID, ProcessName FROM Processes WHERE Unit IN (SELECT ID FROM OperationalUnits WHERE Division='1');
This always throws me a "type mismatch in expression" error.
I've tested by breaking the query down into the two component queries:
SELECT ID FROM OperationalUnits WHERE Division='1';
This returns a single ID, 2, which is what I expect from my test data.
SELECT ID, ProcessName FROM Processes WHERE Unit IN ('2');
This returns a single process, which is again exactly what I expect.
But if I combine them back together into the main query? Nope. It appears that the issue is that the inside query returns [2], while the outside query only works if it returns ['2'], but that doesn't seem like it can be right to me. Any help is appreciated!
Access doesn't automatically cast types, unless in specific situations. As discussed in the comments, since your fields have different types, you can do two things: cast using a function, or change the type.
To cast, you can use the following:
SELECT ID, ProcessName FROM Processes WHERE Unit IN (SELECT CStr(ID) FROM OperationalUnits WHERE Division='1');
You could change the data type within the SQL, although it would be better to have matching data types to start with.
Access won't be able to represent the join in Design View, but it will execute it just fine:
SELECT Processes.ID
, ProcessName
FROM Processes INNER JOIN OperationalUnits ON CLNG(Processes.Unit) = OperationalUnits.ID

How to cast entity to set in PostgreSQL

Using Postgres 9.3, I found out that I can perform something like this:
SELECT generate_series(1,10);
But I can't do this:
SELECT (SELECT generate_series(1,10));
Can I somehow cast SELECT result to setof int to use it same as result from generate_series()?
What exactly is happening there why I can use result from function but not from SELECT?
Your first form is a non-standard feature of Postgres. It allows SRF (Set Returning Functions) in the SELECT list, which are expanded to multiple rows:
Is there something like a zip() function in PostgreSQL that combines two arrays?
Note: that's working for functions, not for sub-selects. That's why your second SELECT is simply invalid syntax.
Standard SQL does not have a provision for that at all, so the feature is frowned upon by some and clean alternatives have been provided (thanks to improvements in the SQL standard). It is largely superseded by the LATERAL feature in Postgres 9.3+:
What is the difference between LATERAL and a subquery in PostgreSQL?
The simple form can be replaced by:
SELECT g
FROM generate_series(1,10) g;
Whenever possible move SRF to the FROM clause and treat them like tables - since version 9.3 that's almost always possible.
Note that g serves as table and column alias automatically in the example. g in SELECT g binds to a column name first. More explicit syntax:
SELECT g
FROM generate_series(1,10) AS t(g); -- table_alias(column_alias)
You need to understand the difference between a row, a set of rows (~ a table) and an array. This would give you an array of integer:
SELECT ARRAY(SELECT g FROM generate_series(1,10) g) AS g_arr;
Browse the tags generate-series and set-returning-functions for many related answers with code examples.