WITH RECURSIVE in bigquery udf - google-bigquery

I try to write bigquery udf with recursive cte as following code:
create or replace function accounting.monthly_sum(arr array<struct<aq numeric,ap numeric,m int64>>) returns numeric
as (
(
WITH RECURSIVE
rec AS (
SELECT arr[0].aq, arr[0].m,least(arr[0].aq,arr[0].ap) ar
UNION ALL
SELECT series.aq,series.m, least(series.aq + rec.ar, series.ap)
FROM UNNEST(arr) series
JOIN rec ON series.m = rec.m + 1
)
SELECT ar
from rec
order by m desc
limit 1
)
);
This returns an error:
SQL Error [100032] [HY000]: [Simba]BigQueryJDBCDriver Error executing query job. Message: WITH RECURSIVE is only allowed at the top level of the SELECT, CREATE TABLE AS SELECT, CREATE VIEW, INSERT, EXPORT DATA statements.
I cannot find what is the problem.

It seems there are some limitations using RECURSIVE CTEs:
WITH RECURSIVE is not allowed in functions.
WITH RECURSIVE is not allowed in materialized views.
https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#cte_rules

Related

Recursive Query: "Table Doesn't Exist" inside function, but does outside function

I'm trying to wrap a recursive temporary table query inside a function on MariaDB 10.3.7 on Ubuntu 18.04. I've tried breaking the statement down to the more basic parts but it all works correctly until I put it all together.
This is an example of the statement I want to turn into a function:
with recursive Descendants as (
select * from Characters where id = 91402
union
select c.* from Characters as c, Descendants as d
where d.id = c.mother_id or d.id = c.real_father_id
) select count(distinct(id)) from Descendants
It print out the number of descendant characters, which is what I want.
And here is my attempt so far at turning it into a function:
create function count_descendants(cid int unsigned) returns int unsigned return (
with recursive Descendants as (
select * from Characters where id = cid
union
select c.* from Characters as c, Descendants as d
where d.id = c.mother_id or d.id = c.real_father_id
) select count(distinct(id)) from Descendants
);
Maria accepts this, but if I try to use it:
select count_descendants(91402);
It prints this error message:
ERROR 1146 (42S02) at line 12: Table 'ck2.Characters' doesn't exist
"ck2" being the name of the database being used. I can post the schema if something would like to see that.
Edit: I have submitted it as a bug on MariaDB's bug tracker: MDEV-16629
This was a bug with recursive CTE queries in MariaDB, has been confirmed, and was fixed.

Getting error ORA-00909: invalid number of arguments

CREATE VIEW ITCC.release_testcase_count
AS
(
SELECT CONCAT(rtm.requirement_id,'-',tct.release_id) AS id,
rtm.requirement_id AS requirement_id,
tct.release_id AS release_id,
COUNT(tct.release_id) AS testcase_count
from testcase_version tcv
INNER JOIN tcr_catalog_tree_testcase tct ON tcv.id = tct.testcase_version_id
LEFT JOIN requirement_testcase_mapping rtm ON rtm.testcase_id=tcv.testcase_id
GROUP BY tct.release_id , rtm.requirement_id
);
same query is working for ms sql and my sql without any syntax error. i want to execute it in oracle as well but i am getting error for the same
The Oracle CONCAT function only takes two, not three or more, parameters. Instead of using CONCAT, just use the concatenation operator:
CREATE VIEW ITCC.release_testcase_count AS (
SELECT rtm.requirement_id || '-' || tct.release_id AS id,
...
)
Or, if you really want to use CONCAT here, then you may chain them together:
CREATE VIEW ITCC.release_testcase_count AS (
SELECT CONCAT(rtm.requirement_id, CONCAT('-', tct.release_id)) AS id,
...
)

sql temporary tables in rstudio notebook's sql chunks?

I am trying to use temp tables in an sql codechunk in rstudio.
An example: When I select one table and return it into an r object things seem to be working:
```{sql , output.var="x", connection='db' }
SELECT count(*) n
FROM origindb
```
When I try anything with temp tables it seems like the commands are running but returns an empty r data.frame
```{sql , output.var="x", connection='db' }
SELECT count(*) n
INTO #whatever
FROM origindb
SELECT *
FROM #whatever
```
My impression is that the Rstudio notebook sql chunks are just set to make one single query. So my temporary solution is to create the tables in a stored procedure in the database. Then I can get the results I want with something simple. I would prefer to have a bit more flexibility in the sql code chunks.
my db connection looks like this:
```{r,echo=F}
db <- DBI::dbConnect(odbc::odbc(),
driver = "SQL Server",
server = 'sql',
database = 'databasename')
```
Like this question, it will work if you put
set nocount on
at the top of your chunk. R seems to get confused when it's handed back the rowcount for the temp table.
I accomplished my goal using CTEs. As long as you define your CTEs in the order that they will be used it works. It is just like using temp tables with one big exception. The CTEs are gone after the query finishes where temp tables exist until you spid is kill (typically via a disconnect).
WITH CTE_WHATEVER AS (
SELECT COUNT(*) n
FROM origindb
)
SELECT *
FROM CTE_WHATEVER
You can also do this for multiple temp table examples
WITH CTE1 AS (
SELECT
STATE
,COUNTY
,COUNT(*) n
FROM origindb
GROUP BY
STATE
,COUNTY
),
CTE2 AS (
SELECT
STATE
,AVG(n)
,COUNTY_AVG
FROM CTE1
GROUP BY
STATE
)
SELECT *
FROM CTE2
WHERE COUNTY_AVG > 1000000
Sorry for the formatting. I couldn't figure out how to get the carriage returns to work in the code block.
I hope this helps.
You could manage a transaction within the SQL chunk defining a BEGIN and COMMIT clauses. For example:
BEGIN ;
CREATE TABLE foo (id varchar) ;
COMMENT ON TABLE foo IS 'Foo';
COMMIT ;

How to query a Postgres `RECORD` datatype

I have a query that will return a row as a RECORD data type from a subquery - see below for example:
select *
from (
select row(st.*) table_rows
from some_table st
) x
where table_rows[0] = 339787
I am trying to further qualify it in the WHERE clause and I need to do so by extracting one of the nodes in the returned RECORD data type.
When I do the above, I get an error saying:
ERROR: cannot subscript type record because it is not an array
Does anybody know of a way of implementing this?
Use (row).column_name. You can just refer to the table itself to create the record:
select *
from (
select r
from some_table r
) x
where (r).column_name = 339787
There is a small chance that later a column is created with the same name as the alias you chose and the above query will fail as select r will return the later created column in instead of the record. The first solution is to use the row constructor as you did in your question:
select row(r.*) as r
The second solution is to use the schema qualified name of the table:
select my_squema.some_table as r
Alternately You can try this
select *
from (
select *
from tbl
) x
where x.col_name = 339787

Unpacking the return value of a function

I have a function like this, which always returns exactly one record:
CREATE FUNCTION foo(pid int) RETURNS TABLE (a int, b int)
AS $$
-- …
$$ LANGUAGE sql;
I want to select rows from a table like this:
SELECT p.id
, foo(p.id).*
FROM puns AS p;
However, this gives a syntax error at .*. I couldn’t figure out how to do it with a JOIN, since p.id is an argument to the function.
How can I unpack the record returned by the function into the select query? The desired result would have three columns id, a and b.
I’m using PostgreSQL 9.2.
Option 1 - upgrade to postgres 9.3 and use LATERAL.
Option 2 - use something like:
SELECT sub_q.id, (sub_q.foo_row).a, (sub_q.foo_row).b
FROM (
SELECT p.id
, foo(p.id) as foo_row
FROM puns AS p ) sub_q;
Option 3 - try additional brackets like:
SELECT p.id
, (foo(p.id)).*
FROM puns AS p;
But I haven't tested option 3.