0

I've found basic answer for replacing the Oracle's "CONNECT BY LEVEL" in this question but my case is little bit more complicated:

Basically things that I want to replace looks like this:

...
UNION ALL

Select 
    adate, 'ROAD' as TSERV_ID, 0 AS EQ_NBR
from 
   (SELECT 
        to_date(sysdate - 732,'dd/mm/yy') + rownum -1 as adate, rownum
    FROM 
        (select rownum 
         from dual 
         connect by level <= 732) 
    WHERE rownum <= 732)

UNION ALL

Select 
    adate, 'PORTPACK' as TSERV_ID, 0 AS EQ_NBR
from 
    (SELECT 
         to_date(sysdate - 732,'dd/mm/yy') + rownum -1 as adate, rownum
     FROM 
          (select rownum from dual connect by level <= 732) 
     WHERE rownum <= 732)

UNION ALL
....

Now, the single dual connect is easy, even if this is apparently not very efficient method

WITH CTE AS (
SELECT dateadd(day,-720,CONVERT (date, GETDATE())) as Datelist
UNION ALL
SELECT dateadd(day,1,Datelist)
FROM CTE 
WHERE datelist < getdate() )
SELECT *,'ROAD' as Tserv_ID , 0 as EQ_NBR FROM CTE
option (maxrecursion 0)

repeating the union is hard because I get an error:

Incorrect syntax near the keyword 'with'. If this statement is a common table expression, an xmlnamespaces clause or a change tracking context clause, the previous statement must be terminated with a semicolon.

There are more parts of this union that I've provided here; I've tried to use the "WITH" only at start but no luck. Am I missing something obvious here?

EDIT: There is of course big question WHY I am even trying to do such thing: Personally, I wouldn't, but at the other end of the query there is a huge Crystal Report that runs once every month and which accepts data in this particular format. End of the FULL query's output is something like

3 columns of data
3 Columns of data
...
Currentdate-732,"ROAD",0
Currentdate -731,"ROAD",0
...
Currentdate, "ROAD,"0"
Currentdate -732, "PORTPAK", 0
Currentdate -731, "PORTPAK", 0

etc.

Community
  • 1
  • 1
Yasskier
  • 791
  • 1
  • 14
  • 36
  • 1
    The last statement in the OP is correct and works here (http://www.sqlfiddle.com/#!6/d41d8/13594). What is the query where you are getting the syntax error? – Gordon Linoff Jan 07 '14 at 04:13
  • It is correct, if its alone, I can't do the union with the same CTE i.e. WITH CTE (Select....) UNION ALL WITH CTE (SELECT) U – Yasskier Jan 07 '14 at 07:19
  • Recursive queries where introduced in SQL Server 2005. Which version are you using? –  Jan 07 '14 at 08:46
  • 1
    @Kris that's because your syntax is wrong. In my answer I showed you how to combine multiple CTEs (in addition to a more reasonable way to do this). It isn't exact right now because you couldn't decide between 720 and 732 days above, and your original query also includes tomorrow (so mine does as well), but it should get you pretty close. – Aaron Bertrand Jan 07 '14 at 12:10

1 Answers1

2

Are you trying to do:

WITH CTE1 AS (...),
     CTE2 AS (...)
SELECT stuff FROM CTE1 
UNION ALL
SELECT stuff FROM CTE2;

? This is a common challenge, I guess it is not very discoverable that in order to use more than one CTE, you just separate them with a comma.

That all said, it seems like you are just trying to generate a series of dates. A recursive CTE (never mind a series of many of them) is not the most efficient way to do this. Instead of telling us you want to replace CONNECT BY LEVEL and showing us the syntax you've tried, why don't you just show or describe the output you want? We've already got an appreciation that you've tried something on your own (thanks!) but we'd rather give you an efficient solution than bridging the gap to an inefficient one.

As an example, here is something that requires a lot less redundant code, and ( think gives you what you're after:

DECLARE @n INT = 722, @d DATE = CURRENT_TIMESTAMP;

;WITH v AS (SELECT v FROM (VALUES('ROAD'),('PORTPACK')) AS v(v)),
      n AS (SELECT TOP (@n) n = ROW_NUMBER() OVER (ORDER BY number)
  FROM master.dbo.spt_values ORDER BY n)
SELECT Datelist = DATEADD(DAY, 2-n.n, @d), Tserv_ID = v.v, EQ_NBR = 0
FROM n CROSS JOIN v
ORDER BY Tserv_ID, Datelist;
Aaron Bertrand
  • 272,866
  • 37
  • 466
  • 490
  • The output I want and what comes from original Query is DATE-732,"ROAD",0; DATE-731,"ROAD",0....DATE-732,"PORTPAK",0; DATE-731,"PORTPACK",0 etc. I am just trying to follow some bad written code because at the other end is quite complicated crystal report which is formatted to accept exactly such format. – Yasskier Jan 07 '14 at 07:24
  • Thanks, it works now. I don't care at this stage about efficiency. It might be worth to mention that the OPTION (maxrecurse 0) is an issue here - has to be put either at the bottom of the query, or (if the query is saved as view) completely omitted and then view queried with OPTION (SELECT * FROM My_Query_as_a_view OPTION (Maxrecurse 0). Joy of MS SQL 2008 R2 :/ – Yasskier Jan 07 '14 at 21:19
  • @Kris I'm failing to understand why you need to use a recursive CTE here at all. Isn't the latter example I provided a much more scalable and readable approach? – Aaron Bertrand Jan 07 '14 at 21:20
  • Your 2nd method is easier, but then AFAIK you can't create views with DECLARE – Yasskier Jan 08 '14 at 02:09
  • Also simply speaking CRYSTAL doesn't want to accept it even as a command :( So in other words I have to stick to CTE – Yasskier Jan 08 '14 at 02:17
  • @Kris Since when is your only option with Crystal Reports a view? Are you saying it's not possible to point this behemoth away a stored procedure? Stop limiting yourself to what you think Crystal is capable of... – Aaron Bertrand Jan 08 '14 at 02:39
  • You might be right (even if I actually never tried using stored procedures with Crystal) and I really appreciate your answer, but even if this is very suboptimal solution I'll stick with CTE :| At this stage its simply not worth the effort, this monstrosity will be running once a month on a schedule, no one cares how long it will take to run (actually at this moment its pretty fast - query runs in about 5s) – Yasskier Jan 08 '14 at 09:49