Subtract result of two CTE - sql-server

So I have a query like this
Create Procedure sp_GetTotalTargetsCount
#userId int
AS
Begin
Create Table #RequestTargets
(
Name varchar(20),
Value int
)
Declare #rId int
Set #rId=0
Select #rId=r.RequestId From Requests r
Join RequestPipeline rp
on r.RequestId=rp.RequestId
Join RequestStatus rs
on rp.RequestStatusId=rs.StatusId
Where rs.StatusDescription='In Progress.'
;With TotalCTE AS (Select Count(*) As TotalTargets FROM Targets Where InsertedByUserId=#userId),
FilteredCTE AS (Select Count(*) As FilteredTargets From RequestDetails Where RequestId=#rId)
Insert into #RequestTargets (Name,Value)
Select 'TotalTargets', Count(*) FROM Targets Where InsertedByUserId=#userId
Insert into #RequestTargets (Name,Value)
Select 'UnderSurveillence', Count(*) From
RequestDetails Where RequestId=#rId
Insert into #RequestTargets (Name,Value)
Values ('NotInSurveillence', (TotalCTE.TotalTargets-FilteredCTE.FilteredTargets)) --ERROR HERE it says Multipart identifier -- TotalTargets could not be bound
End
I think I can subract one count() query from the other count() without using CTE. Is there there a way to subtract the result of two CTE's as above. Please help.

You can't use CTE that way. Try
;WITH totalcte
AS (SELECT Count(*) AS TotalTargets
FROM targets
WHERE insertedbyuserid = #userId),
filteredcte
AS (SELECT Count(*) AS FilteredTargets
FROM requestdetails
WHERE requestid = #rId)
INSERT INTO #requesttargets
(NAME,
value)
SELECT 'NotInSurveillence',
totalcte.totaltargets - filteredcte.filteredtargets
FROM totalcte
CROSS JOIN filteredcte
FROM TotalCTE CROSS JOIN FilteredCTE
infact. . you can combine all into one big single query
;WITH totalcte
AS (SELECT Count(*) AS TotalTargets
FROM targets
WHERE insertedbyuserid = #userId),
filteredcte
AS (SELECT Count(*) AS FilteredTargets
FROM requestdetails
WHERE requestid = #rId)
INSERT INTO #requesttargets
(NAME,
value)
SELECT 'NotInSurveillence',
totalcte.totaltargets - filteredcte.filteredtargets
FROM totalcte
CROSS JOIN filteredcte
UNION ALL
SELECT 'TotalTargets',
totalcte.totaltargets
FROM totalcte
UNION ALL
SELECT 'UnderSurveillence',
filteredcte.filteredtargets
FROM filteredcte

select * from cte1 union distinct cte2

Related

sql server using recrusive cte to get the level in the same group

I have a sql server table showing the IDs and their previous IDs,
create table test2 ( ID varchar(10) ,
Pre_ID varchar(10)
)
insert into test2 values ('e','d')
, ('d','c')
, ('c','b')
, ('b','a')
, ('a',null)
, ('r','q')
, ('q','p')
, ('p',null)
the table is like this:
The result should be like this:
I have successfully got the levels using a recursive cte, but could not get the correct group for them. can anyone help? Thanks.
This is my code:
with cte as (
select id, Pre_ID, level
from #temp2
where Pre_ID is null
union all
select t2.id, t2.Pre_ID, t2.level
from cte
inner join #temp2 t2
on t2.Pre_ID=cte.id
)
select * from cte
order by id
What you need to do is start with the first level and add a ROW_NUMBER to that, then join all further levels recursively:
with cte as (
select id, Pre_ID, level, row_number() over (order by ID) as grp
from #temp2
where Pre_ID is null
union all
select t2.id, t2.Pre_ID, t2.level, cte.grp
from cte
inner join #temp2 t2
on t2.Pre_ID=cte.id
)
select * from cte
order by id;

How to set an order when using CTE?

I have a table with 2 columns (id, childId). The data is as follows:
1, 2
3, 4
2, null
4, null
I'm using a CTE so that I get the child records:
DECLARE #id TABLE (id int);
INSERT INTO #id SELECT 1;
INSERT INTO #id SELECT 3;
WITH cte AS
(
SELECT id, childId
FROM mytable
WHERE
id IN (SELECT id FROM #id)
UNION ALL
SELECT b.id, b.childId
FROM mytable b
INNER JOIN cte
ON b.id = cte.childId
)
SELECT * FROM cte
The result always come back as:
1, 2
3, 4
4, null
2, null
But I need the result to look like:
1, 2
2, null
3, 4,
4, null
That is, first the anchor records then the records for the recursive sql for each anchor record.
Is this possible?
Add a static value to in anchor query. Then in recursive part add a static value greater than the static value of anchor query. Now the use static value in Order by
Try this
WITH cte AS
(
SELECT 0 as rn, id, childId
FROM mytable
WHERE
id IN (SELECT id FROM #id)
UNION ALL
SELECT 1 as rn,b.id, b.childId
FROM mytable b
INNER JOIN cte
ON b.id = cte.childId
)
SELECT * FROM cte
Order by rn,id
Also consider adding option(Maxrecursion N). By default it just makes only 100 recursions
By Adding a Seq, the results will be displayed in the proper order/nesting
DECLARE #id TABLE (id int);
INSERT INTO #id SELECT 1;
INSERT INTO #id SELECT 3;
WITH cte AS
(
SELECT id, childId
,Seq = cast(100000+Row_Number() over (Order by id) as varchar(500))
FROM mytable
WHERE
id IN (SELECT id FROM #id)
UNION ALL
SELECT b.id, b.childId
,Seq = cast(concat(cte.Seq,'.',100000+Row_Number() over (Order by b.id)) as varchar(500))
FROM mytable b
INNER JOIN cte
ON b.id = cte.childId
)
SELECT * FROM cte
Order By Seq

Using max(col) with count in sub-query SQL Server

I am putting together a query in SQL Server but having issues with the sub-query
I wish to use the max(loadid) and count the number of records the query returns.
So for example my last loadid is 400 and the amount of records with 400 is 2300, so I would my recor_count column should display 2300. I have tried various ways below but am getting errors.
select count (loadid)
from t1
where loadid = (select max(loadid) from t1) record_count;
(select top 1 LOADID, count(*)
from t1
group by loadid
order by count(*) desc) as Record_Count
Showing loadid and number of matching rows with the use of grouping, ordering by count and limiting the output to 1 row with top.
select top 1 loadid, count(*) as cnt
from t1
group by loadid
order by cnt desc
This may be easier to achieve with a window function in the inner query:
SELECT COUNT(*)
FROM (SELECT RANK() OVER (ORDER BY loadid DESC) AS rk
FROM t1) t
WHERE rk = 1
Another simplest way to achieve the result :
Set Nocount On;
Declare #Test Table
(
Id Int
)
Insert Into #Test(Id) Values
(397),(398),(399),(400)
Declare #Abc Table
(
Id Int
,Value Varchar(100)
)
INsert Into #Abc(Id,Value) Values
(398,'')
,(400,'')
,(397,'')
,(400,'')
,(400,'')
Select a.Id
,Count(a.Value) As RecordCount
From #Abc As a
Join
(
Select Max(t.Id) As Id
From #Test As t
) As v On a.Id = v.Id
Group By a.Id

How to find the maximum value in join without using if in sql stored procedure

I have a two tables like below
A
Id Name
1 a
2 b
B
Id Name
1 t
6 s
My requirement is to find the maximum id from table and display the name and id for that maximum without using case and if.
i findout the maximum by using below query
SELECT MAX(id)
FROM (SELECT id,name FROM A
UNION
SELECT id,name FROM B) as c
I findout the maximum 6 using the above query.but i can't able to find the name.I tried the below query but it's not working
SELECT MAX(id)
FROM (SELECT id,name FROM A
UNION
SELECT id,name FROM B) as c
How to find the name?
Any help will be greatly appreciated!!!
First combine the tables, since you need to search both. Next, determine the id you need. JOIN the id back with the temporarily created table to retreive the name that belongs to that id:
WITH tmpTable AS (
SELECT id,name FROM A
UNION
SELECT id,name FROM B
)
, max AS (
SELECT MAX(id) id
FROM tmpTable
)
SELECT t.id, t.name
FROM max m
JOIN tmpTable t ON m.id = t.id
You could use ROW_NUMBER(). You have to UNION ALL TableA and TableB first.
WITH TableA(Id, Name) AS(
SELECT 1, 'a' UNION ALL
SELECT 2, 'b'
)
,TableB(Id, Name) AS(
SELECT 1, 't' UNION ALL
SELECT 6, 's'
)
,Combined(Id, Name) AS(
SELECT * FROM TableA UNION ALL
SELECT * FROM TableB
)
,CTE AS(
SELECT *, RN = ROW_NUMBER() OVER(ORDER BY ID DESC) FROM Combined
)
SELECT Id, Name
FROM CTE
WHERE RN = 1
Just order by over the union and take first row:
SELECT TOP 1 * FROM (SELECT * FROM A UNION SELECT * FROM B) x
ORDER BY ID DESC
This won't show ties though.
For you stated that you used SQL Server 2008. Therefore,I used FULL JOIN and NESTED SELECT to get what your looking for. See below:
SELECT
(SELECT
1,
ISNULL(A.Id,B.Id)Id
FROM A FULL JOIN B ON A.Id=B.Id) AS Id,
(SELECT
1,
ISNULL(A.Name,B.Name)Name
FROM A FULL JOIN B ON A.Id=B.Id) AS Name
It's possible to use ROW_NUMBER() or DENSE_RANK() functions to get new numiration by Id, and then select value with newly created orderId equal to 1
Use:
ROW_NUMBER() to get only one value (even if there are some repetitions of max id)
DENSE_RANK() to get all equal max id values
Here is an example:
DECLARE #tb1 AS TABLE
(
Id INT
,[Name] NVARCHAR(255)
)
DECLARE #tb2 AS TABLE
(
Id INT
,[Name] NVARCHAR(255)
)
INSERT INTO #tb1 VALUES (1, 'A');
INSERT INTO #tb1 VALUES (7, 'B');
INSERT INTO #tb2 VALUES (4, 'C');
INSERT INTO #tb1 VALUES (7, 'D');
SELECT * FROM
(SELECT Id, Name, ROW_NUMBER() OVER (ORDER BY Id DESC) AS [orderId]
FROM
(SELECT Id, Name FROM #tb1
UNION
SELECT Id, Name FROM #tb2) as tb3) AS TB
WHERE [orderId] = 1
SELECT * FROM
(SELECT Id, Name, DENSE_RANK() OVER (ORDER BY Id DESC) AS [orderId]
FROM
(SELECT Id, Name FROM #tb1
UNION
SELECT Id, Name FROM #tb2) as tb3) AS TB
WHERE [orderId] = 1
Results are:

MSSQL subquery result to show and calculate

I need show a subquery result and use this same result to calculate other value, is possible set this value in a variable in MS SQL 2008 or something like this?
exemple:
SELECT
#test = (SELECT COUNT(*) FROM [tableTest] WHERE [tableTest].[columnA] = [tableA].[columnA]) as 'Counter'
, (#test * 50) as 'Calc'
, [tableA].[columnA]
FROM tableA
you may use a cte and join on it.
with cte as (select count(*) cnt, columnA from [tableTest] group by columnA)
select
c.cnt as 'Counter',
c.cnt * 50 as 'Calc',
a.columnA
from tableA a
join cte c on c.columnA = a.columnA
It could also be done with a subquery, of course
select
a.columnA,
c.cnt as 'Counter',
c.cnt * 50 as 'Calc'
from tableA a
join (select columnA, count(*) as cnt
from tableTest
group by columnA) c
on c.columnA = a.columnA
Why can't you do this. Move the subquery outside of select statement and store the result in a variable
Then use that variable for calculations.
declare #test int = (SELECT COUNT(*) FROM [tableTest])
SELECT
#test as 'Counter'
, (#test * 50) as 'Calc'
, [tableA].[columnA]
FROM tableA
Update :
SELECT [Counter],
( [Counter] * 50 ) AS 'Calc',
columnA
FROM (SELECT (SELECT Count(*)
FROM [tableTest]
WHERE [tableTest].[columnA] = [tableA].[columnA]) AS 'Counter',
[tableA].[columnA]
FROM tableA) A
You can also use correlated sub-queries:
SELECT
Counter = (SELECT COUNT(*) FROM tableTest t WHERE t.columnA = a.columnA),
Calc = (SELECT COUNT(*) FROM tableTest t WHERE t.columnA = a.columnA) * 50,
a.columnA
FROM tableA a
It'll be optimized to be only evaluated once.
Try:
SELECT t2.[Count]
,t2.[Count] * 50 As [Calc]
,[tableA].[columnA]
FROM TableA
CROSS APPLY
(
SELECT COUNT(*) AS [Count]
FROM TableTest
WHERE [tableTest].[columnA] = [tableA].[columnA]
) t2

Resources