SQL Join table to itself - sql

I have a table where there are two columns like below.
value1 DerivedFrom
1 0
2 1
3 2
4 3
5 4
Basically, what it is saying is 1 was new, 2 was derived from 1, 3 was derived from 2 and so on.
I want the out put with 1 as the master key and 2,3,4 and 5 as children.
value1 DerivedFrom
1 0
1 1
1 2
1 3
1 4
Is it achiveble in SQL ? Thanks in advance

As mentioned in the comment, the simplest way is with an rCTE (recursive Common Table Expression):
--Sample Data
WITH YourTable AS(
SELECT *
FROM (VALUES(1,0),
(2,1),
(3,2),
(4,3),
(5,4))V(value1,DerivedFrom)),
--Solution
rCTE AS(
SELECT YT.value1 as rootValue,
YT.value1,
YT.DerivedFrom
FROM YourTable YT
WHERE YT.DerivedFrom = 0
UNION ALL
SELECT r.rootValue,
YT.value1,
YT.DerivedFrom
FROM YourTable YT
JOIN rCTE r ON YT.DerivedFrom = r.value1)
SELECT r.rootValue AS value1,
r.DerivedFrom
FROM rCTE r;

Related

get number of times values on the basis of input value

Input table
Col
1
2
2
3
3
4
5
Output
1
2
2
2
2
3
3
3
3
3
3
4
4
4
4
5
5
5
5
5
Is there any way this could be achieved in sql with and without writing any function ? Please take a note that, column can have duplicate values.
you didn't state your DBMS product, but in Postgres this can be done using `generate_series()
select t.col
from the_table t
cross join generate_series(1, t.col)
order by t.col
This is just a cross join to a numbers/tally table. You already have one in your source data, so you can simply use it as a distinct list:
select i.col
from input i
cross join (select distinct col as n from input) n
where n.n <= i.col
order by i.col
Here is a standard SQL recursive query for this:
with cte (num, cnt) as
(
select num, num from mytable
union all
select num, cnt - 1 from cte where cnt > 1
)
select num from cte order by num;

The way for insert and fill table base on column in another table in sql with Several million rows

I have a table similar A With 2 million recordes
ROW ID ITEM NoOfUnit
1 1 A 2
2 2 B 1
3 3 C 3
.
.
.
I want fill table B base on NoOfUnit from A Similar to the below
ROW ID ITEM QTY
1 1 A 1
2 1 A 1
3 2 B 1
4 3 C 1
5 3 C 1
6 3 C 1
.
.
.
Number of rows in table B very large and cursor very slow...
I would just use a recursive CTE:
with cte as (
select id, item, NoOfUnit, 1 as n
from a
union all
select id, item, NoOfUnit, n + 1
from a
where n < NoOfUnit
)
insert into b (id, item, qty)
select id, item, 1
from cte;
If qty is ever greater than 100, then you need option (maxrecursion 0).
All you need to do here is duplicate your rows based on the number held in NoOfUnit, which you could do with a numbers table. You then insert the result of this into your destination table.
An example of how to do this is as follows:
Query
declare #d table(ID int, ITEM char(1),NoOfUnit int);
insert into #d values
(1,'A',2)
,(2,'B',1)
,(3,'C',3)
;
with t as(select t from(values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) as t(t)) -- table with 10 rows
,n as(select row_number() over (order by (select null)) as n from t,t t2,t t3,t t4,t t5) -- cross join 10 rows 5 times for 10 * 10 * 10 * 10 * 10 = 100,000 rows with incrementing value
select d.ID
,d.ITEM
,1 as QTY
from #d as d
join n
on d.NoOfUnit >= n.n
order by d.ID
,d.ITEM;
Output
ID
ITEM
QTY
1
A
1
1
A
1
2
B
1
3
C
1
3
C
1
3
C
1

View Level Number on Recursive Table SQL

I have the following table:
--------------------------------------------
ID ParentID Item
--------------------------------------------
1 root
2 1 AA
3 1 BB
4 1 CC
5 1 DD
6 2 A1
7 6 A11
ff.
I want to have the following result:
ID ParentID Item Level
---------------------------------------------
1 root 0
2 1 AA 1
3 1 BB 1
4 1 CC 1
5 1 DD 1
6 2 A1 2
7 6 A11 3
ff.
What is the best idea to create the new column level? Is create a new column and add a formula or something like computed or maybe function?
How can I achieve that on t-sql?
You would use a recursive CTE:
with cte as (
select t.id, t.parentid, t.item, 0 as lvl
from t
where parentid is null
union all
select t.id, t.parentid, t.item, cte.lvl + 1 as lvl
from t join
cte
on t.parentid = cte.id
)
select *
from cte;
Storing this data in the table is . . . cumbersome, because you need to keep it updated. You might want to just calculate it on-the-fly when you need it.
Simply using DENSE_RANK:
DECLARE #YourTable TABLE(ID INT,ParentID VARCHAR(10),Item VARCHAR(10))
INSERT into #YourTable VALUES(1,' ','root')
INSERT into #YourTable VALUES(2,'1','AA')
INSERT into #YourTable VALUES(3,'1','BB')
INSERT into #YourTable VALUES(4,'1','CC')
INSERT into #YourTable VALUES(5,'1','DD')
INSERT into #YourTable VALUES(6,'2','A1')
INSERT into #YourTable VALUES(7,'6','A11')
SELECT ID,ParentID,Item
,(DENSE_RANK() OVER(ORDER BY ISNULL(NULLIF(ParentID,''),0)))-1 [Level]
FROM #YourTable
Output:
ID ParentID Item Level
1 root 0
2 1 AA 1
3 1 BB 1
4 1 CC 1
5 1 DD 1
6 2 A1 2
7 6 A11 3
Hope it helps you.

sql select parent child recursive in one field

I do not know how to select query recursive..
id idparent jobNO
--------------------------------
1 0 1
2 1 2
3 1 3
4 0 4
5 4 5
6 4 6
how do the results like this With SqlServer
id idparent jobNO ListJob
----------------------------------------
1 0 1 1
2 1 2 1/2
3 1 3 1/3
4 0 4 4
5 4 5 4/5
6 5 6 4/5/6
You need to use a Recursive Common Table Expression.
There are many useful articles online.
Useful Links
Simple Talk: SQL Server CTE Basics
blog.sqlauthority: Recursive CTE
Here is a solution to your question:
CREATE TABLE #TEST
(
id int not null,
idparent int not null,
jobno int not null
);
INSERT INTO #Test VALUES
(1,0,1),
(2,1,2),
(3,1,3),
(4,0,4),
(5,4,5),
(6,5,6);
WITH CTE AS (
-- This is end of the recursion: Select items with no parent
SELECT id, idparent, jobno, CONVERT(VARCHAR(MAX),jobno) AS ListJob
FROM #Test
WHERE idParent = 0
UNION ALL
-- This is the recursive part: It joins to CTE
SELECT t.id, t.idparent, t.jobno, c.ListJob + '/' + CONVERT(VARCHAR(MAX),t.jobno) AS ListJob
FROM #Test t
INNER JOIN CTE c ON t.idParent = c.id
)
SELECT * FROM CTE
ORDER BY id;

Create indexed view

My table structure is below :
MyTable (ID Int, AccID1 Int, AccID2 Int, AccID3 int)
ID AccID1 AccID2 AccID3
---- -------- -------- --------
1 12 2 NULL
2 4 12 1
3 NULL NULL 5
4 7 NULL 1
I want to create indexed view with below output :
ID Level Value
---- ----- -------
1 1 12
1 2 2
2 1 4
2 2 12
2 3 1
3 3 5
4 1 7
4 3 1
EDIT :
My table is very huge and I want to have above output.
I can Get my query such as below :
Select ID,
Case StrLevel
When 'AccID1' Then 1
When 'AccID2' Then 2
Else 3
End AS [Level],
AccID as Value
From (
Select A.ID, A.AccID1, A.AccID2, A.AccID3
From MyTable A
)as p
UNPIVOT (AccID FOR [StrLevel] IN (AccID1, AccID2, AccID3)) AS unpvt
or
Select *
from (
select MyTable.ID,
num.n as [Level],
Case Num.n
When 1 Then MyTable.AccID1
When 2 Then MyTable.AccID2
Else MyTable.AccID3
End AS AccID
from myTable
cross join (select 1
union select 2
union select 3)Num(n)
)Z
Where Z.AccID IS NOT NULL
or
Select A.ID,
2 AS [Level],
A.AccID1 AS AccID
From MyTable A
Where A.AccID1 IS NOT NULL
Union
Select A.ID,
2 AS [Level],
A.AccID2
From MyTable A
Where A.AccID2 IS NOT NULL
Union
Select A.ID,
3 AS [Level],
A.AccID3
From MyTable A
Where A.AccID3 IS NOT NULL
But Above query is slow and I want to have indexed view to have better performance.
and in indexed view I can't use UNION or UNPIVOT or CROSS JOIN in indexed view.
What if you created a Numbers table to essentially do the work of your illegal CROSS JOIN?
Create Table Numbers (number INT NOT NULL PRIMARY KEY)
Go
Insert Numbers
Select top 30000 row_number() over (order by (select 1)) as rn
from sys.all_objects s1 cross join sys.all_objects s2
go
Create view v_unpivot with schemabinding
as
Select MyTable.ID,
n.number as [Level],
Case n.number
When 1 Then MyTable.AccID1
When 2 Then MyTable.AccID2
Else MyTable.AccID3
End AS AccID
From dbo.Mytable
Join dbo.Numbers n on n.number BETWEEN 1 AND 3
go
Create unique clustered index pk_v_unpivot on v_unpivot (ID, [Level])
go
Select
ID,
[Level],
AccID
From v_unpivot with (noexpand)
Where AccID IS NOT NULL
Order by ID, [Level]
The WHERE AccID IS NOT NULL must be part of the query because derived tables are not allowed in indexed views.