T-SQL Recursive with two initial statements - sql-server

I don't have idea how to write this recursive in SQL. How handle with CTE when I have two initial assumptions?
Below easy example:
a1 = 2
a2 = 3
an = a(n-1)*a(n-2)
I tried write something like below but unfortunately I don't know how handle with this:
with recur(n,results) as
(
select 1,2
union all
select 2,3
union all
select
/*how to write this pattern?*/
where n<
)
select * from recur
Do you have any idea?

It seems you want to generate the Fibonacci numbers using a recursive CTE.
Try something like this:
WITH CTE AS (
SELECT 1 AS N, 2 AS A, 3 AS B
UNION ALL
SELECT N+1 AS N, B AS A, A+B AS B
FROM CTE
WHERE N<10
)
SELECT A FROM CTE

Related

Check if element in list string BigQuery

I have a comma separated list in BigQuery
select '1,2,3' as number_list
I want to return true if 1 is in the list without splitting into an array then unnesting
I want to be able to say
select if(1 in split('1,2,3'),1,0)
I also want to avoid saying
select if('1,2,3' like '%,1,%' or '1,2,3' like '1,%' or '1,2,3' like '%,1',1,0)
Below example for BigQuery Standard SQL
#standardSQL
CREATE TEMP FUNCTION InList(list STRING, num INT64) AS ((
SELECT COUNTIF(num = CAST(number AS INT64)) FROM UNNEST(SPLIT(list)) number
));
WITH `project.dataset.table` AS (
SELECT '1,2,3' AS number_list UNION ALL
SELECT '2,3,4'
)
SELECT number_list, InList(number_list, 1) in_list
FROM `project.dataset.table`
with result
Row number_list in_list
1 1,2,3 1
2 2,3,4 0
I also want to avoid saying
SELECT IF('1,2,3' LIKE '%,1,%' OR '1,2,3' LIKE '1,%' OR '1,2,3' LIKE '%,1',1,0)
to avoid such redundancy you can use below version
SELECT IF(CONCAT(',', number_list, ',') LIKE CONCAT('%,1,%'), 1, 0)
... And, finally - and most likely the winner :o)
I want to be able to say select if(1 in split('1,2,3'),1,0)
The closest is
SELECT IF('1' IN UNNEST(SPLIT(number_list)), 1, 0)
You can use subquery with MAX function matching your searched value
SELECT id,
(SELECT MAX(IF(n = 1, n, null)) = 1 FROM UNNEST(number_list) AS n)
FROM (
SELECT
1 AS id,
[1,2,3] AS number_list
)
or with
SELECT id,
(SELECT MAX(IF(n = '1', n, null)) = '1' FROM UNNEST(number_list) AS n)
FROM (
SELECT
1 AS id,
SPLIT('1,2,3',',') AS number_list
)

SQL Server calculations based on aggregates inside recursive CTEs

Could you please help me with this dillema?
I tried to simplify the example as much as I could, but basically, what I want is to somehow use an aggregate of the previous results of a recursive query inside the next level of the recursive query (hope that makes sense).
I tried using window functions (max() over()), however those seem to focus on only the current row for some reason (that seems better explained here: recursive cte with ranking functions ).
I also tried referencing the 'r' CTE more than once, however that seems illegal.
Do you have any other ideas of how I can do this?
I need to do this in SQL and not T-SQL. The reason is that I actually have a working version in T-SQL using loops, but the performance of that is pretty poor for what I'm trying to do. I'm hoping a pure SQL solution will work much faster.
I'm using SQL Server 2012.
Thanks!
--this works, however it's not recursive and I don't know in advance how many "levels" there will be:
;with t as (
select 1 a, 1 b union all
select 2 a, 1 b union all
select 3 a, 1 b
), r as (
select a, b, 1 lvl
from t
)
select *
from r
union all --we took the "union all" outside the CTE, which means it's not recursive anymore
select a + max(a) over(partition by b) a, --this now works as expected and returns "a + 3" on all cases
b, lvl-1
from r
where lvl > 0
--this doesn't work:
;with t as (
select 1 a, 1 b union all
select 2 a, 1 b union all
select 3 a, 1 b
), r as (
select a, b, 1 lvl
from t
union all
select a + max(a) over(partition by b) a, --this returns the "max" over only the current row instead of doing the partition from what I expect to be the "previous step"
b, lvl-1
from r
where lvl > 0
)
select *
from r
--this also fails:
;with t as (
select 1 a, 1 b union all
select 2 a, 1 b union all
select 3 a, 1 b
), r as (
select a, b, 1 lvl
from t
union all
select a + (select max(a) from r r2 where r2.b = r.b) a, --this returns the "max" over only the current row instead of doing the partition from what I expect to be the "previous step"
b, lvl-1
from r
where lvl > 0
)
select *
from r

Selecting a set of rows more than once

Is there a simple, concise way to select the same set of rows repeated based on a count held in a variable, without using a loop?
For instance, suppose SELECT a, b, c FROM foo WHERE whatsit = something returns
a b c
--- --- ----
1 2 3
...and I have #count with 3 in it. Is there a reasonable way without a loop to get:
a b c
--- --- ----
1 2 3
1 2 3
1 2 3
? Order doesn't matter, and I don't need to know which group any given row belongs to. I actually only need this for one row (as above), and a solution that only works for one row would do the trick, but I assume if we can do it for one, we can do it for any number.
Try with a Recursive CTE
WITH cte
AS (SELECT 1 AS id,a,b,c
FROM tablename
UNION ALL
SELECT id + 1,a,b,c
FROM cte
WHERE id < 3) --#count
SELECT a,b,c
FROM cte
Another way to do using cross join
SELECT a, b, c
FROM Table1
CROSS JOIN (SELECT number
FROM master.dbo.spt_values
WHERE type = 'P'
AND number BETWEEN 1 AND 3) T
I don't know of a way you could do this without a loop or dynamic SQL. I think a union is all that I can come up with
select q1.a,q1.b,q1.c
from (
SELECT a, b, c FROM foo
union all
SELECT a, b, c FROM foo
union all
SELECT a, b, c FROM foo ) q1
order by q1.a

Select all rows related by a column

i have a Url table
UrlId Followedby
1 NULL
2 1
3 2
i want to write a sp which take urlid as parameter and return all rows.
GetAllUrls 3
and it will return above rows.
Can above doable without cursor ?
Have a look at Recursive Queries Using Common Table Expressions.
Using a recursive CTE it would look like this
declare #UrlId int = 3
;with C as
(
select U.UrlId,
U.Followedby
from Url as U
where U.UrlId = #UrlId
union all
select U.UrlId,
U.Followedby
from Url as U
inner join C
on U.UrlId = C.Followedby
)
select UrlId,
Followedby
from C
https://data.stackexchange.com/stackoverflow/q/119027/

How to nest CTE properly

This question was asked few other times, but I still did not manage to sort out the right answer or proper way to do this:
...
;WITH CTE AS
(
SELECT * FROM ...
)
SELECT *, [dbo].[udf_BetaInv](A, B, C, D) AS 'Loss'
FROM CTE
WHERE (Loss >= #MinRetention)
This does not work and I cannot create the stored procedure, clearly I cannot use Loss in the WHERE because does not exist in that scope.
I would like to use another CTE to wrap this one so I can put the WHERE on the outer one but not does not seem to work, tried this:
;WITH CTE AS
(
SELECT * FROM ...
)
SELECT *, [dbo].[udf_BetaInv(A, B, C, D) AS 'Loss'
FROM CTE,
RESULTS AS
(SELECT * FROM CTE)
SELECT *
FROM RESULTS
WHERE (Loss >= #MinRetention)
But it does not compile in SQL Server, I get an error that a '(' is misplaces many rows above but has nothing to do, if I remove the second CTE it works fine.
I only want to avoid code duplication, not want to call my [udf_BetaInv] twice in the select and also in the where.
You have an intermediate SELECT that you should not have. This should work:
;WITH CTE AS
(
SELECT * FROM ...
),
RESULTS AS
(
SELECT *, [dbo].[udf_BetaInv(A, B, C, D) AS 'Loss'
FROM CTE
)
SELECT *
FROM RESULTS
WHERE (Loss >= #MinRetention)
Obviously the problem with the first query is that 'Loss' is just a column alias and can't be used in a WHERE clause. You're right that using it in a CTE would avoid duplicating the expression. Here's how you'd do that;
WITH CTE AS
(
SELECT * FROM ...
),
CteWithLoss AS (
SELECT *, [dbo].[udf_BetaInv](A, B, C, D) AS 'Loss'
FROM CTE
)
SELECT *
FROM CteWithLoss
WHERE (Loss >= #MinRetention);
On a side note: See if you can break the habit of starting your CTE definitions with ;WITH and instead get into the habit of ending all your SQL statements with a semi-colon. It's more readable and better practice.
Below is the example of nested CTE.
with cte_data as
(
Select * from [HumanResources].[Department]
),cte_data1 as
(
Select * from cte_data
)
select * from cte_data1

Resources