If Exists inside a CTE in SQl Server - sql

I just want to know that How to write a CTE containing If Exists in SQl Server ?
I had tried to write a CTE below where i am Using If Exists Statement to select weather the record exist or not .In case if the record does not exist then i am assigning default value but i am getting error
'Incorrect syntax near the keyword 'if'
.' Please help me to fix this error and guide me to write this CTE.
Please find below the CTE which i had written:-
Alter procedure St_Proc_GetTeamProductionReport
#mindate DateTime,
#maxdate DateTIme,
#userID varchar(50)
as
Begin
set NoCount on;
with
ProductionCTE(CalendarDate,RoleID,UserID,UserECode,UserName,ImmediateSupervisor,NatureOfWorkName,RegionProjectName,CountyName,WorkTypeName,TaskName,VolumneProcessed,TimeSpent,Comment)
as
(
if exists
(
select P.CalendarDate,U.RoleID,U.UserID,U.UserECode,U.UserName,U.ImmediateSupervisor,N.NatureofWorkName,
R.RegionProjectName,C.Countyname,W.WorktypeName,T.TaskName,P.VolumeProcessed,P.Timespent,P.Comment
from production P inner join NatureOfWork N
on N.NatureofWorkID=P.natureofworkid
inner join dbo.RegionAndProjectInfo R
on R.RegionProjectID=P.RegionProjectID
inner join county C
on C.countyid=P.countyid
inner join worktype W
on W.Worktypeid=P.worktypeID
inner join task T
on T.taskid=P.TaskID
inner join UserInfo U
on U.Userid=P.userid
where P.userid=#userID and ( convert(varchar, P.CalendarDate, 101) ) between (
convert(varchar, #mindate, 101) ) and ( convert(varchar, #maxdate, 101) )
)
else
(
Select '2012-09-14 13:41:52' as CalendarDate,
2 as RoleID,'938' as UserID,
(select Userecode from Userinfo where userid=#userID) as UserECode,
(select UserName from Userinfo where userid=#userID)as UserName,
(select ImmediateSupervisor from Userinfo where userid=#userID)as ImmediateSupervisor,
'BP' as NatureOfWorkName,
'CO Processing' as RegionProjectName,
'Adams' as CountyName,
'Quality' as WorkTypeName,
'Corrections ' as TaskName,
5 as VolumneProcessed,
'01:00' as TimeSpent,
'test' as Comment
)
union all
select P.CalendarDate,U.RoleID,U.UserID,U.UserECode,U.UserName,U.ImmediateSupervisor,N.NatureofWorkName,
R.RegionProjectName,C.Countyname,W.WorktypeName,T.TaskName,P.VolumeProcessed,P.Timespent,P.Comment
from production P inner join NatureOfWork N
on N.NatureofWorkID=P.natureofworkid
inner join dbo.RegionAndProjectInfo R
on R.RegionProjectID=P.RegionProjectID
inner join county C
on C.countyid=P.countyid
inner join worktype W
on W.Worktypeid=P.worktypeID
inner join task T
on T.taskid=P.TaskID
inner join UserInfo U
on U.Userid=P.userid
inner join ProductionCTE
on U.ImmediateSupervisor=ProductionCTE.UserECode
where P.IsTaskCompleted=1 and ( convert(varchar, P.CalendarDate, 101) ) between (
convert(varchar, #mindate, 101) ) and ( convert(varchar, #maxdate, 101) )
)
select distinct CONVERT(VARCHAR,CalendarDate,20) as CalendarDate,UserECode,UserName,NatureOfWorkName,RegionProjectName,CountyName,WorkTypeName,TaskName,VolumneProcessed,TimeSpent,Comment from ProductionCTE where RoleID=1
end
GO
When i am removing this If Exist statement then the CTE is working fine but after adding the IF Exists statement it is having error.

You can't use IF EXISTS in this way. A common table expression must only contain a single select statement, it's not possible to say if condition SELECT THIS else SELECT THAT.
It looks like you are trying to add an additional created row to a resultset returned by a query. You could achieve this by implementing the CTE as a table-valued function that would return the single new row.
http://msdn.microsoft.com/en-gb/library/ms191165(v=sql.105).aspx

If you want to construct a UNION where you only get a result from the second SELECT if the first SELECT returns no rows, you can achieve this using RANK(). So, you can place your real query in the first SELECT and the desired default values in the second, and achieve the results you want.
I don't have your tables and data, so I'm not going to attempt to re-write your query. But I'll illustrate with this:
;With WithDefaults as (
select name,0 as Rank from sys.objects
union all
select 'abc',1 --Default if no results
), Ranked as (
select *,RANK() OVER (ORDER BY Rank) as Rnk from WithDefaults
)
select * from Ranked where Rnk = 1
Returns (on a mostly empty DB I tried it on) 98 results, of which none had the name abc. If we force the first SELECT to return no results:
select name,0 as Rank from sys.objects where 1 = 2
We now get a single row result with the name abc.
Hopefully, you can see how this could apply to your original query.

You can't use IF EXISTS in CTE. But you can modify logic of function
Example:
alter procedure St_Proc_GetTeamProductionReport
#mindate DateTime,
#maxdate DateTIme,
#userID varchar(50)
as
Begin
set NoCount on;
;with
ProductionCTE(CalendarDate,RoleID,UserID,UserECode,UserName,ImmediateSupervisor,NatureOfWorkName,RegionProjectName,CountyName,WorkTypeName,TaskName,VolumneProcessed,TimeSpent,Comment)
as
(
select P.CalendarDate,U.RoleID,U.UserID,U.UserECode,U.UserName,U.ImmediateSupervisor,N.NatureofWorkName,
R.RegionProjectName,C.Countyname,W.WorktypeName,T.TaskName,P.VolumeProcessed,P.Timespent,P.Comment, 1 AS cnt
from production P inner join NatureOfWork N
on N.NatureofWorkID=P.natureofworkid
inner join dbo.RegionAndProjectInfo R
on R.RegionProjectID=P.RegionProjectID
inner join county C
on C.countyid=P.countyid
inner join worktype W
on W.Worktypeid=P.worktypeID
inner join task T
on T.taskid=P.TaskID
inner join UserInfo U
on U.Userid=P.userid
where P.userid=#userID and ( convert(varchar, P.CalendarDate, 101) ) between (
convert(varchar, #mindate, 101) ) and ( convert(varchar, #maxdate, 101) )
UNION ALL
Select '2012-09-14 13:41:52' as CalendarDate,
2 as RoleID,'938' as UserID,
(select Userecode from Userinfo where userid=#userID) as UserECode,
(select UserName from Userinfo where userid=#userID)as UserName,
(select ImmediateSupervisor from Userinfo where userid=#userID)as ImmediateSupervisor,
'BP' as NatureOfWorkName,
'CO Processing' as RegionProjectName,
'Adams' as CountyName,
'Quality' as WorkTypeName,
'Corrections ' as TaskName,
5 as VolumneProcessed,
'01:00' as TimeSpent,
'test' as Comment, 0
), ProductionCTE2 AS
(
SELECT TOP(SELECT CASE WHEN COUNT(*) = 0 THEN 1 ELSE COUNT(*) END FROM ProductionCTE WHERE cnt = 1)
CalendarDate,RoleID,UserID,UserECode,UserName,ImmediateSupervisor,NatureofWorkName,
RegionProjectName,Countyname,WorktypeName,TaskName,VolumeProcessed,Timespent,Comment
FROM ProductionCTE2
union all
select P.CalendarDate,U.RoleID,U.UserID,U.UserECode,U.UserName,U.ImmediateSupervisor,N.NatureofWorkName,
R.RegionProjectName,C.Countyname,W.WorktypeName,T.TaskName,P.VolumeProcessed,P.Timespent,P.Comment
from production P inner join NatureOfWork N
on N.NatureofWorkID=P.natureofworkid
inner join dbo.RegionAndProjectInfo R
on R.RegionProjectID=P.RegionProjectID
inner join county C
on C.countyid=P.countyid
inner join worktype W
on W.Worktypeid=P.worktypeID
inner join task T
on T.taskid=P.TaskID
inner join UserInfo U
on U.Userid=P.userid
inner join ProductionCTE
on U.ImmediateSupervisor=ProductionCTE.UserECode
where P.IsTaskCompleted=1 and ( convert(varchar, P.CalendarDate, 101) ) between (
convert(varchar, #mindate, 101) ) and ( convert(varchar, #maxdate, 101) )
)
select distinct CONVERT(VARCHAR,CalendarDate,20) as CalendarDate,UserECode,UserName,NatureOfWorkName,RegionProjectName,CountyName,WorkTypeName,TaskName,VolumneProcessed,TimeSpent,Comment
from ProductionCTE2
where RoleID=1
end

Related

Avoid SQL Pivot returning duplicate rows

I have the following SQL script which returns duplciate values in PIVOT. How do I combine those duplicate records to one row.
Please check the below image for the results set.
SELECT *
FROM (SELECT X.stockcode,
X.description,
X.pack,
X.location,
X.lname,
X.qty,
Y.stockcode AS StockCode2,
y.periodname,
Y.months,
Y.saleqty
FROM (SELECT dbo.stock_items.stockcode,
dbo.stock_items.description,
dbo.stock_items.pack,
dbo.stock_loc_info.location,
dbo.stock_locations.lname,
dbo.stock_loc_info.qty
FROM dbo.stock_locations
INNER JOIN dbo.stock_loc_info
ON dbo.stock_locations.locno = dbo.stock_loc_info.location
LEFT OUTER JOIN dbo.stock_items
ON dbo.stock_loc_info.stockcode = dbo.stock_items.stockcode
WHERE ( dbo.stock_items.status = 's' )) AS X
LEFT OUTER JOIN (SELECT dbo.dr_invlines.stockcode,
( 12 + Datepart(month, Getdate()) - Datepart(month, dbo.dr_trans.transdate) ) % 12 + 1 AS Months,
Sum(dbo.dr_invlines.quantity) AS SaleQty,
dbo.period_status.periodname
FROM dbo.dr_trans
INNER JOIN dbo.period_status
ON dbo.dr_trans.period_seqno = dbo.period_status.seqno
LEFT OUTER JOIN dbo.stock_items AS STOCK_ITEMS_1
RIGHT OUTER JOIN dbo.dr_invlines
ON STOCK_ITEMS_1.stockcode = dbo.dr_invlines.stockcode
ON dbo.dr_trans.seqno = dbo.dr_invlines.hdr_seqno
WHERE ( STOCK_ITEMS_1.status = 'S' )
AND ( dbo.dr_trans.transtype IN ( 1, 2 ) )
AND ( dbo.dr_trans.transdate >= Dateadd(m, -6, Getdate()) )
GROUP BY dbo.dr_invlines.stockcode,
Datepart(month, dbo.dr_trans.transdate),
dbo.period_status.periodname) AS Y
ON X.stockcode = Y.stockcode) z
PIVOT (Sum(saleqty) FOR [months] IN ([1],[2],[3],[4],[5],[6])) AS pivoted
EDIT: I missed the root-cause of your issue being the inclusion of the periodname column causing the percieved duplication. I am leaving this in place as general solution showing CTE usage, because it could still be useful if you then want to do extra filtering/transformation of your pivot results
One way is to take the results of the pivot query and run it through a SELECT DISTINCT query.
An example of wrapping your pivot query as a CTE and using it to feed a SELECT DISTINCT below (please note: untested, but parses as valid in my SSMS)
WITH PivotResults_CTE (
stockcode,
description,
pack,
location,
lname,
qty,
StockCode2,
periodname,
months,
saleqty
)
AS (
SELECT *
FROM (
SELECT X.stockcode
,X.description
,X.pack
,X.location
,X.lname
,X.qty
,Y.stockcode AS StockCode2
,y.periodname
,Y.months
,Y.saleqty
FROM (
SELECT dbo.stock_items.stockcode
,dbo.stock_items.description
,dbo.stock_items.pack
,dbo.stock_loc_info.location
,dbo.stock_locations.lname
,dbo.stock_loc_info.qty
FROM dbo.stock_locations
INNER JOIN dbo.stock_loc_info ON dbo.stock_locations.locno = dbo.stock_loc_info.location
LEFT OUTER JOIN dbo.stock_items ON dbo.stock_loc_info.stockcode = dbo.stock_items.stockcode
WHERE (dbo.stock_items.STATUS = 's')
) AS X
LEFT OUTER JOIN (
SELECT dbo.dr_invlines.stockcode
,(12 + Datepart(month, Getdate()) - Datepart(month, dbo.dr_trans.transdate)) % 12 + 1 AS Months
,Sum(dbo.dr_invlines.quantity) AS SaleQty
,dbo.period_status.periodname
FROM dbo.dr_trans
INNER JOIN dbo.period_status ON dbo.dr_trans.period_seqno = dbo.period_status.seqno
LEFT OUTER JOIN dbo.stock_items AS STOCK_ITEMS_1
RIGHT OUTER JOIN dbo.dr_invlines ON STOCK_ITEMS_1.stockcode = dbo.dr_invlines.stockcode ON dbo.dr_trans.seqno = dbo.dr_invlines.hdr_seqno WHERE (STOCK_ITEMS_1.STATUS = 'S')
AND (
dbo.dr_trans.transtype IN (
1
,2
)
)
AND (dbo.dr_trans.transdate >= Dateadd(m, - 6, Getdate()))
GROUP BY dbo.dr_invlines.stockcode
,Datepart(month, dbo.dr_trans.transdate)
,dbo.period_status.periodname
) AS Y ON X.stockcode = Y.stockcode
) z
PIVOT(Sum(saleqty) FOR [months] IN (
[1]
,[2]
,[3]
,[4]
,[5]
,[6]
)) AS pivoted
)
SELECT DISTINCT *
FROM
PivotResults_CTE
;
Also note, your sql included in the above may look slightly different to your original but that is only because i ran it through a reformatter to ensure i understood the structure of it.
In other words, the basic CTE wrapper for your pivot query is:
WITH PivotResults_CTE (
Field1,
Field2,
...
)
AS (
YOUR_PIVOT_QUERY_HERE
)
SELECT DISTINCT *
FROM
PivotResults_CTE
;

How to add a temp table in SQL server

I am trying to add a temp table to my query so that I can query that temp table, I have searched the internet but I couldn't get a solution.
this is my query
;WITH cte AS (
SELECT ID, g.Name
FROM game.Game g WITH(NOLOCK
WHERE ID IN (SELECT Data FROM system.Split(1, ','))
UNION ALL
SELECT g.ID, g.Name
FROM game.Game g WITH(NOLOCK)
JOIN cte ON g.ParentID = cte.ID
)
SELECT c.ID,
c.Name
FROM cte c
INNER JOIN list.Type gt WITH(NOLOCK) ON c.TypeId = gt.TypeID
WHERE c.ID NOT IN (SELECT Data FROM system.Split(1, ','))
AND c.ID IN (SELECT ID FROM game.code WITH(NOLOCK)
WHERE ID = c.ID
AND StatusCode IN ('OP', 'CL', 'SU')
AND isDisplay = 'True'
AND GETDATE() BETWEEN DisplayStart AND DisplayEnd
AND GETDATE() < ISNULL(ResultDateTime, ResultExpected)
)
which gives me the following when I run it
ID | Name
1111 | BaseBall
2222 |BasketBall
45896 |Relay
now I tried to create a temp table as follows
Create Table #temp(
ID int,
Name varchar
)
;WITH cte AS (
SELECT ID, g.Name
FROM game.Game g WITH(NOLOCK)
WHERE ID IN (SELECT Data FROM system.Split(1, ','))
UNION ALL
SELECT g.ID, g.Name
FROM game.Game g WITH(NOLOCK)
JOIN cte ON g.ParentID = cte.ID
)
insert into #temp // i wanted to set these values in the temp table
SELECT c.ID,
c.Name
FROM cte c
INNER JOIN list.Type gt WITH(NOLOCK) ON c.TypeId = gt.TypeID
WHERE c.ID NOT IN (SELECT Data FROM system.Split(1, ','))
AND c.ID IN (SELECT ID FROM game.code WITH(NOLOCK)
WHERE ID = c.ID
AND StatusCode IN ('OP', 'CL', 'SU')
AND isDisplay = 'True'
AND GETDATE() BETWEEN DisplayStart AND DisplayEnd
AND GETDATE() < ISNULL(ResultDateTime, ResultExpected)
)
every time I try to store this information in the temp table it gives me an error 'Column name or number of supplied values does not match table definition.' But I only have two values in. What am I doing wrong that I cant see?
First, why not just use select into?
IF OBJECT_ID('TempDB..#temp') IS NOT NULL
BEGIN
DROP TABLE #temp
END
select c.ID, c.Name
into #temp
from . . .
Then you don't need to define #temp as a table.
Next, your definition is bad, because Name has only one character. This would be fixed with select into.
However, I don't know why you are getting the particular error you are getting. The numbers of columns appears to match.

Join tables showing all records for each week

I was hoping someone would be able to help me. I have two tables, one with student names and the other with the the amount of homework each student has done, each week (not a real example). Only one student has done any work. I would like to see a table showing all the students and how much work they have done (even if it is null, for each week.
CREATE TABLE #NAME (Name VARCHAR(20))
INSERT INTO #NAME VALUES
('John'),('Tom'),('Jack')
CREATE TABLE #TIME (Name VARCHAR(20), Week INT, Year INT, Total INT)
INSERT INTO #TIME VALUES
('John',1,2017,34),('John',2,2017,24),('John',3,2017,65),('John',4,2017,22),('John',5,2017,45)
I thought a left outer join would work - but it only references the join between names and not weeks
SELECT
#Name.Name,
#Time.Week,
#Time.Year,
#Time.Total
FROM #NAME LEFT OUTER JOIN #Time ON #NAME.Name = #Time.Name
I tried a outer apply - but essentially get the same thing -
SELECT
#Name.Name,
A.Week,
A.Year,
A.Total
FROM #NAME OUTER APPLY (SELECT * FROM #TIme WHERE #Name.Name = #Time.Name) A
The output from the above two queries is shown below - alongside what I am trying to get - repeating for each week, showing all students regardless of whether they have any values associated or not.
I'd be really appreciative if someone could help me with this.
You need to get all combinations of Name, Week, and Year and then do a LEFT JOIN on #TIME to get the desired result:
WITH CteNameWeekYear(Name, [Week], [Year]) AS(
SELECT
n.*, t.*
FROM(
SELECT DISTINCT [Week], [Year] FROM #TIME
) t
CROSS JOIN #Name n
)
SELECT
c.Name,
c.[Week],
c.[Year],
t.Total
FROM CteNameWeekYear c
LEFT JOIN #TIME t
ON c.Name = t.Name
AND c.[Year] = t.[Year]
AND c.[Week] = t.[Week]
ORDER BY c.[Year], c.[Week], c.Name;
ONLINE DEMO
Try this
WITH cte AS (
SELECT DISTINCT t.Week, t.Year
FROM #TIME t
), cte1 AS (
SELECT n.Name, cte.Week, cte.Year
FROM #NAME n
CROSS JOIN cte
)
SELECT
n.Name, n.Week, n.Year, t.Total
FROM
cte1 n
LEFT JOIN #TIME t ON n.NAME = t.NAME AND n.Week = t.Week AND n.Year = t.Year

Improve performance of the query

My query is taking very long time.
select distinct JobName,
ValidationType,
AppName,
Result,
ResultType,
ErrorWarningDetails,
CvtStartDateTime
from contentvalidationjobdetails with (nolock)
where appname=#AppName
and result=#Result
and (cast(cvtstartdatetime as date) > #Date )
and concat(Jobname,validationtype) not in (
select concat(jobname,validationtype)
from Contentvalidationjobdetails with (nolock)
where appname = #AppName
and CVTStartDateTime = (
select top 1 teststartdatetime
from contentvalidation
where appname=#AppName
and Teststartdatetime<#Date
order by teststartdatetime desc
)
)
I know that the concat(jobname,validationtype) is taking time. how to handle this.
Place the query in FROm section to be executed just once (not for each line in WHERE). Add outer join and leave only records which has no joins.
select distinct JobName,
ValidationType,
AppName,
Result,
ResultType,
ErrorWarningDetails,
CvtStartDateTime
from contentvalidationjobdetails with (nolock)
LEFT OUTER JOIN (
select concat(jobname,validationtype) cnt
from Contentvalidationjobdetails with (nolock)
where appname = #AppName
and CVTStartDateTime = (
select top 1 teststartdatetime
from contentvalidation
where appname=#AppName
and Teststartdatetime<#Date
order by teststartdatetime desc) sub ON concat(Jobname,validationtype)=sub.cnt
where appname=#AppName
and result=#Result
and (cast(cvtstartdatetime as date) > #Date ))
HAVING sub.cnt is null

Declaring variables in CTEs SQL Server 2008

How can I implement something like the following:
declare #myInt int
set #myInt=(select count(*) from x)
;with x as
(
select row_number() over(partition by c.patientid order by c.admissiondate) as rn
,c.patientid,c.admissiondate
,max(c.claimsfromdate) as maxHemiDate
,min(c.claimsfromdate) minHemiDate
,(
select max(c2.claimsfromdate)
from claims as c2
where c2.patientid=c.patientid
group by c2.patientid
) as maxClaimsDate
,p.drgCode
,datediff(dd,min(c.claimsfromdate),max(c.claimsfromdate)) /7 as weeksWithHemi
from claims as c inner join icdclaims as ci on ci.id=c.id
inner join tblicd as t on t.icd_id=ci.icd_id
inner join patient as p on p.patientid=c.patientid
and p.admissiondate = c.admissiondate
and p.dischargedate = c.dischargedate
where t.icdText like '%X%' and p.statecode='21'
group by c.patientid, c.admissiondate, p.drgCode
)
select p.patientid, count(*)
from patient as p
left join x on x.patientid=p.patientid
where x.patientid is null
group by p.patientid
The error thrown when this is executed is
invalid object name x
I kinda figured that this would happen since the variable declaration is outside of the CTE. If I move the declaration inside of the parentheses of WITH I get another error.
How can I assign a variable like this inside a CTE? Or can you not use a variable that draws data from the CTE at all?
If you are using SQL Server 2005 or later, you can put the total on each row:
select t.*, cnt, count(*) over () as NumRows
from (select p.patientid, count(*) as cnt
from patient as p left join
x
on x.patientid=p.patientid
where x.patientid is null
group by p.patientid
) t
In case you are using the total to calculate percentages, or something like that, it might be convenient to have the value on each row.
To get in #myInt number of rows, you can do:
declare #myInt int
;with x as
(
__your query__
)
select p.patientid, count(*)
from patient as p
left join x on x.patientid=p.patientid
where x.patientid is null
group by p.patientid
set #myInt=##ROWCOUNT
EDITED (Due Jon Egerton comment) If you need to count x rows, then a temporay table is the way:
declare #myInt int
;with x as
(
__your query__
)
select *
into #tmp_x
from x;
set #myInt=(select count(*) from #tmp_x)
select p.patientid, count(*)
from patient as p
left join #tmp_x x on x.patientid=p.patientid
where x.patientid is null
group by p.patientid
Thanks Jon Egerton
You can't use a single CTE for two distinct statements - they go out of scope.
So either you need to remove the need for the variable, or you can just declare a table variable and then keep selecting on that as many times as you like.
You can declare table var as follows:
declare #x table (rowno int, patientid varchar...
Then you can fill that using the select that you've currently got in your CTE.
The problem is with this line:
set #myInt=(select count(*) from x)
You are trying to do the select on x before it has been declared!
UPDATE
In this case it would be best to use a temporary table or table variable rather than a CTE. For example:
declare #myInt int
select row_number() over(partition by c.patientid order by c.admissiondate) as rn
,c.patientid,c.admissiondate
,max(c.claimsfromdate) as maxHemiDate
,min(c.claimsfromdate) minHemiDate
,(
select max(c2.claimsfromdate)
from claims as c2
where c2.patientid=c.patientid
group by c2.patientid
) as maxClaimsDate
,p.drgCode
,datediff(dd,min(c.claimsfromdate),max(c.claimsfromdate)) /7 as weeksWithHemi
INTO #XTable
from claims as c inner join icdclaims as ci on ci.id=c.id
inner join tblicd as t on t.icd_id=ci.icd_id
inner join patient as p on p.patientid=c.patientid
and p.admissiondate = c.admissiondate
and p.dischargedate = c.dischargedate
where t.icdText like '%X%' and p.statecode='21'
group by c.patientid, c.admissiondate, p.drgCode
set #myInt=(select count(*) from #XTable)
select p.patientid, count(*)
from patient as p
left join #XTable x on x.patientid=p.patientid
where x.patientid is null
group by p.patientid
This is the quick and dirty method, but you could obviously declare your table earlier in the script.
A CTE may be plural. It doesn't solve your stated problem, but it is often clearer to break a complex CTE into several steps, each building on the prior definitions. In this example there is a recursive CTE and a second CTE that computes statistics based on the first. The final SELECT combines the results:
with CTE
as (
select 1 as Number
union all
select Number + 1
from CTE
where Number < 10
),
Summary
as (
select Count( 42 ) as HowMany, Min( Number ) as Least, Max( Number ) as Most
from CTE
)
select *
from CTE cross join
Summary