How to store result of sql query in variable? - sql

I have the following query:
with cte as
(SELECT top 10 [1],[2]
FROM [tbl_B] where [2] > '2000-01-01' and Status_7 = 0 and Status_8 = 1
ORDER BY [2])
,
CTE1 AS
( select [1], row_number() over (order by [2]) as rn
from CTE
)
select [1] from CTE1 where rn = '10'
how can I put this into a variable to compare it to another query result?
If i use set #123 = (above query) it gives errors.

with cte as
(
SELECT top 10 [1],[2]
FROM [tbl_B]
where [2] > '2000-01-01' and Status_7 = 0 and Status_8 = 1
ORDER BY [2]
)
,CTE1 AS
(
select [1], row_number() over (order by [2]) as rn
from CTE
)
select #123 = [1] from CTE1 where rn = '10'

with cte as
(SELECT top 10 [1],[2]
FROM [tbl_B] where [2] > '2000-01-01' and Status_7 = 0 and Status_8 = 1
ORDER BY [2])
,
CTE1 AS
( select [1], row_number() over (order by [2]) as rn
from CTE
)
select #123 = [1] from CTE1 where rn = '10'

You can use a table variable to store the CTE's result set. For example:
declare #table_var table (id int, col1 varchar(50));
; with CTE as
(
... your definition here ...
)
insert #table_var
(id, col1)
select id
, col1
from CTE
Comparing this with another set can be done with a full outer join:
select coalesce(t1.id, t2.id) as id
, coalesce(t1.col1, t2.col1) as col1
, case
when t1.id is null then 'Missing in t1'
when t2.id is null then 'Missing in t2'
when isnull(t1.col1,'') <> isnull(t2.col1,'') then 'Col1 is different'
else 'Identical'
end as Difference
from #table_var1 t1
full outer join
#table_var2 t2
on t1.id = t2.id

Related

unable to swap rows in sql

I have the below table where names will be inserted first. Then I will get IDs where I need to map with names
ID NAME
null Test1
null Test2
1 null
2 null
I need the result like
ID NAME
1 Test1
2 Test2
I tried below query but it doesn't work for me
select t1.ID , t2.Name from table1 T1 join table1 t2 on T1.id = t2.id
According to screen short you are working with SQL Server , you could try cte expression which may help you
;with cte as
(
select max(id) id, row_number() over (order by (select 1)) rn from
(
select *, rank() over(order by id) rnk from table
) a
group by a.rnk
having max(id) is not null
), cte1 as
(
select max(name) name, row_number() over (order by (select 1)) rn from
(
select *, rank() over(order by name) rnk from table
) a
group by a.rnk
having max(name) is not null
)
select c.id, c1.name from cte c
join cte1 c1 on c1.rn = c.rn
Result :
id name
1 test1
2 test2

SQL Self Recursive Join with Grouping

In SQL Server, I have the following table:
Name New_Name
---------------
A B
B C
C D
G H
H I
Z B
I want to create a new table that links all the names that are related to a single new groupID
GroupID Name
-------------
1 A
1 B
1 C
1 D
1 Z
2 G
2 H
2 I
I'm a bit stuck on this can can't figure out how to do it apart from a bunch of joins. But I would like to do it properly.
Edited the question to allow grouping from two different start points, A and Z into one group.
Since you've changed the question, I'm updating the answer. Please note that answer is same in sense of logical structure. All it does differently is that instead of going from G to I in calculating levels, answer now calculates from I to G.
Working demo link
;with cte as
(
select
t1.Name as Name, row_number() over (order by t1.Name) r,
t1.New_Name as New_Name,
1 as level
from yt t1 left join yt t2
on t1.New_Name=t2.name
where t2.name is null
union all
select
yt.Name as Name, r,
yt.New_Name as New_Name,
c.level+1 as level
from cte c join yt
on yt.New_Name=c.Name
),
cte2 as
(
select r as group_id, Name from cte
union
select c1.r as group_id, c1.New_name as Name from cte c1
where level = (select min(level) from cte c2 where c2.r=c1.r)
)
select * from cte2;
Below is old answer.
You can try below CTE based query:
create table yt (Name varchar(10), New_Name varchar(10));
insert into yt values
('A','B'),
('B','C'),
('C','D'),
('G','H'),
('H','I');
;with cte as
(
select
t1.Name as Name, row_number() over (order by t1.Name) r,
t1.New_Name as New_Name,
1 as level
from yt t1 left join yt t2
on t1.Name=t2.New_name
where t2.new_name is null
union all
select
yt.Name as Name, r,
yt.New_Name as New_Name,
c.level+1 as level
from cte c join yt
on yt.Name=c.New_Name
),
cte2 as
(
select r as group_id, Name from cte
union
select c1.r as group_id, c1.New_name as Name from cte c1
where level = (select max(level) from cte c2 where c2.r=c1.r)
)
select * from cte2;
see working demo
Little bit complex but working.
DECLARE #T TABLE (Name VARCHAR(2), New_Name VARCHAR(2))
INSERT INTO #T
VALUES
('A','B'),
('B','C'),
('C','D'),
('G','H'),
('H','I'),
('Z','B')
;WITH CTE AS
(
SELECT * , RN = ROW_NUMBER() OVER(ORDER BY Name) FROM #T
)
,CTE2 AS (SELECT T1.RN, T1.Name Name1, T1.New_Name New_Name1,
X.Name Name2, X.New_Name New_Name2,
FLAG = CASE WHEN X.Name IS NULL THEN 1 ELSE 0 END
FROM CTE T1
OUTER APPLY (SELECT * FROM CTE T2 WHERE T2.RN > T1.RN
AND (T2.Name IN (T1.Name , T1.New_Name)
OR T2.New_Name IN (T1.Name , T1.New_Name)
)) AS X
)
,CTE3 AS (SELECT *,
GroupID = ROW_NUMBER() OVER (ORDER BY RN) -
ROW_NUMBER() OVER (PARTITION BY Flag ORDER BY RN) +1
FROM CTE2
)
SELECT
DISTINCT GroupID, Name
FROM
(SELECT * FROM CTE3 WHERE Name2 IS NOT NULL) SRC
UNPIVOT ( Name FOR COL IN ([Name1], [New_Name1], [Name2], [New_Name2])) UNPVT
Result
GroupID Name
-------------------- ----
1 A
1 B
1 C
1 D
1 Z
2 G
2 H
2 I

How to use CTE recursion to get a running total of a column

I have been researching CTE recursion, but I still seem to be confused.
I have table: utb(date, b_id, v_id, b_vol)
I need to get the running total of the column: b_vol.
The catch is that I need to divide if the row_number is even, and multiply if it is odd, so essentially:
P1= b_vol1, P2 = b_vol1/b_vol2, P3= b_vol1/b_vol2*b_vol3,
P4= b_vol1/b_vol2*b_vol3/b_vol4
So, it is basically P(n)= (P(n-1)(*OR/(b_vol(n))
I can't seem to figure out how to put that into a query.
Thanks for taking the time to read this. I hope you can help.
My sample table only has 1 column B_VOL. Try this
DECLARE #SampleData AS TABLE ( B_VOL int)
INSERT INTO #SampleData VALUES (50), (50), ( 50), (50) ,(155), (255)
;WITH temp AS
(
SELECT sd.*, row_number() OVER(ORDER BY (SELECT null)) - 1 AS RowIndex FROM #SampleData sd
)
,cte AS
(
SELECT TOP 1 t.RowIndex, CAST( t.B_VOL AS decimal(18,7)) AS sv FROM temp t ORDER BY t.RowIndex ASC
UNION ALL
SELECT t.RowIndex, CAST(cte.sv * (CASE WHEN t.RowIndex % 2 = 1 THEN CAST(1 AS decimal(18,7))/t.B_VOL ELSE t.B_VOL END) AS decimal(18,7)) AS sv
FROM cte
INNER JOIN temp t ON cte.RowIndex + 1 = t.RowIndex
)
SELECT t.*, c.sv
FROM temp t
INNER JOIN cte c ON t.RowIndex = c.RowIndex
OPTION(MAXRECURSION 0)
First, a CTE is not the best way to solve this problem. But . . .
with u as (
select u.*, row_number() over (order by date) - 1 as seqnum
from utb u
),
cte as (
select seqnum, b_vol as result
from u
union all
select cte.seqnum, cte.result * (case when seqnum % 2 = 1 then 1.0 / b_vol else b_vol end) as result
from cte join
u
on u.seqnum = cte.seqnum + 1
)
select *
from cte;
you should try this,
DECLARE #SampleData AS TABLE ( B_VOL int)
INSERT INTO #SampleData VALUES (50), (50), ( 50), (50) ,(155), (255)
;with CTE as
(
select S.B_VOL,ROW_NUMBER()over(order by ((select null)))rn
from #SampleData S
)
,CTE1 AS
(
select b_vol,cast(b_vol as float) sv,1 rn1
from cte where rn=1
union ALL
select c.b_vol,
case when (c1.rn1+1)%2=0
THEN c1.sv/cast(c.b_vol as float)
ELSE
c1.sv*cast(c.b_vol as float)
end
,c1.rn1+1
from CTE C
inner join CTE1 c1
on c.rn=c1.rn1+1
where c1.rn1<7
)
select * from cte1

SQL Joining table with Min and Sec Min row

I want to join table 1 with table2 twice becuase I need to get the first minimum record and the second minimum. However, I can only think of using a cte to get the second minimum record. Is there a better way to do it?
Here is the table table:
I want to join Member with output table FirstRunID whose Output value is 1 and second RunID whose Output value is 0
current code I am using:
select memid, a.runid as aRunid,b.runid as bRunid
into #temp
from FirstTable m inner join
(select min(RunID), MemID [SecondTable] where ouput=1 group by memid)a on m.memid=a.memid
inner join (select RunID, MemID [SecondTable] where ouput=0 )b on m.memid=a.memid and b.runid>a.runid
with cte as
(
select row_number() over(partition by memid, arunid order by brunid ),* from #temp
)
select * from cte where n=1
You can use outer apply operator for this:
select * from t1
outer apply(select top 1 t2.runid from t2
where t1.memid = t2.memid and t2.output = 1 order by t2.runid) as oa1
outer apply(select top 1 t2.runid from t2
where t1.memid = t2.memid and t2.output = 0 order by t2.runid) as oa2
You can do this with conditional aggregation. Based on your results, you don't need the first table:
select t2.memid,
max(case when output = 1 and seqnum = 1 then runid end) as OutputValue1,
max(case when output = 0 and seqnum = 2 then runid end) as OutputValue2
from (select t2.*,
row_number() over (partition by memid, output order by runid) a seqnum
from t2
) t2
group by t2.memid;
declare #FirstTable table
(memid int, name varchar(20))
insert into #firsttable
values
(1,'John'),
(2,'Victor')
declare #secondtable table
(runid int,memid int,output int)
insert into #secondtable
values
(1,1,0),(1,2,1),(2,1,1),(2,2,1),(3,1,1),(3,2,0),(4,1,0),(4,2,0)
;with cte as
(
SELECT *, row_number() over (partition by memid order by runid) seq --sequence
FROM #SECONDTABLE T
where t.output = 1
union all
SELECT *, row_number() over (partition by memid order by runid) seq --sequence
FROM #SECONDTABLE T
where t.output = 0 and
t.runid > (select min(x.runid) from #secondtable x where x.memid = t.memid and x.output = 1 group by x.memid) --lose any O output record where there is no prior 1 output record
)
select cte1.memid,cte1.runid,cte2.runid from cte cte1
join cte cte2 on cte2.memid = cte1.memid and cte2.seq = cte1.seq
where cte1.seq = 1 --remove this test if you want matched pairs
and cte1.output = 1 and cte2.output = 0

Get average time between record creation

So I have data like this:
UserID CreateDate
1 10/20/2013 4:05
1 10/20/2013 4:10
1 10/21/2013 5:10
2 10/20/2012 4:03
I need to group by each user get the average time between CreateDates. My desired results would be like this:
UserID AvgTime(minutes)
1 753.5
2 0
How can I find the difference between CreateDates for all records returned for a User grouping?
EDIT:
Using SQL Server 2012
Try this:
SELECT A.UserID,
AVG(CAST(DATEDIFF(MINUTE,B.CreateDate,A.CreateDate) AS FLOAT)) AvgTime
FROM #YourTable A
OUTER APPLY (SELECT TOP 1 *
FROM #YourTable
WHERE UserID = A.UserID
AND CreateDate < A.CreateDate
ORDER BY CreateDate DESC) B
GROUP BY A.UserID
This approach should aslo work.
Fiddle demo here:
;WITH CTE AS (
Select userId, createDate,
row_number() over (partition by userid order by createdate) rn
from Table1
)
select t1.userid,
isnull(avg(datediff(second, t1.createdate, t2.createdate)*1.0/60),0) AvgTime
from CTE t1 left join CTE t2 on t1.UserID = t2.UserID and t1.rn +1 = t2.rn
group by t1.UserID;
Updated: Thanks to #Lemark for pointing out number of diff = recordCount - 1
since you're using 2012 you can use lead() to do this
with cte as
(select
userid,
(datediff(second, createdate,
lead(CreateDate) over (Partition by userid order by createdate)
)/60) datdiff
From table1
)
select
userid,
avg(datdiff)
from cte
group by userid
Demo
Something like this:
;WITH CTE AS
(
SELECT
ROW_NUMBER() OVER (PARTITION BY UserID ORDER BY CreateDate) RN,
UserID,
CreateDate
FROM Tbl
)
SELECT
T1.UserID,
AVG(DATEDIFF(mi, ISNULL(T2.CreateDate, T1.CreateDate), T1.CreateDate)) AvgTime
FROM CTE T1
LEFT JOIN CTE T2
ON T1.UserID = T2.UserID
AND T1.RN = T2.RN - 1
GROUP BY T1.UserID
With SQL 2012 you can use the ROW_NUMBER function and self-join to find the "previous" row in each group:
WITH Base AS
(
SELECT
ROW_NUMBER() OVER (PARTITION BY UserID ORDER BY CreateDate) RowNum,
UserId,
CreateDate
FROM Users
)
SELECT
B1.UserID,
ISNULL(
AVG(
DATEDIFF(mi,B2.CreateDate,B1.CreateDate) * 1.0
)
,0) [Average]
FROM Base B1
LEFT JOIN Base B2
ON B1.UserID = B2.UserID
AND B1.RowNum = B2.RowNum + 1
GROUP BY B1.UserId
Although I get a different answer for UserID 1 - I get an average of (5 + 1500) / 2 = 752.
This only works in 2012. You can use the LEAD analytic function:
CREATE TABLE dates (
id integer,
created datetime not null
);
INSERT INTO dates (id, created)
SELECT 1 AS id, '10/20/2013 4:05' AS created
UNION ALL SELECT 1, '10/20/2013 4:10'
UNION ALL SELECT 1, '10/21/2013 5:10'
UNION ALL SELECT 2, '10/20/2012 4:03';
SELECT id, isnull(avg(diff), 0)
FROM (
SELECT id,
datediff(MINUTE,
created,
LEAD(created, 1, NULL) OVER(partition BY id ORDER BY created)
) AS diff
FROM dates
) as diffs
GROUP BY id;
http://sqlfiddle.com/#!6/4ce89/22