How can I create multi level hierarchy in SQL Server - sql-server

I am creating multi level hierarchy in SQL Server. How can I create that?
This my table data-
ID DeptID ParentID FolderName
1 1 0 2
2 1 1 2.1
3 1 1 2.2
4 1 1 2.3
5 1 2 2.1.1
6 1 2 2.1.2
7 1 2 2.1.3
8 1 2 2.1.4
9 1 5 2.1.1.1
10 1 5 2.1.1.2
11 1 5 2.1.1.3
12 2 0 1
13 3 0 3
I want following result.
ID DeptID ParentID FolderName
1 1 0 2
2 1 1 2.1
5 1 2 2.1.1
9 1 5 2.1.1.1
10 1 5 2.1.1.2
11 1 5 2.1.1.3
6 1 2 2.1.2
7 1 2 2.1.3
8 1 2 2.1.4
3 1 1 2.2
4 1 1 2.3
12 2 0 1
13 3 0 3

If you already have the FolderName column, some simple replacement and conversions turns it into a hierarchyid which already understands how to sort hierarchically:
declare #t table (ID int,DeptID int, ParentID int, FolderName varchar(900))
insert into #t(ID, DeptID, ParentID, FolderName) values
(1 ,1,0,'2'),
(2 ,1,1,'2.1'),
(3 ,1,1,'2.2'),
(4 ,1,1,'2.3'),
(5 ,1,2,'2.1.1'),
(6 ,1,2,'2.1.2'),
(7 ,1,2,'2.1.3'),
(8 ,1,2,'2.1.4'),
(9 ,1,5,'2.1.1.1'),
(10,1,5,'2.1.1.2'),
(11,1,5,'2.1.1.3'),
(12,2,0,'1'),
(13,3,0,'3')
;With Abc as (
select
*,
CAST('/' + REPLACE(FolderName,'.','/') + '/' as hierarchyid) as FolderNameRightType
from
#t
)
select
*
from
Abc
order by FolderNameRightType
Result:
ID DeptID ParentID FolderName FolderNameRightType
----------- ----------- ----------- -------------------- -----------------------
12 2 0 1 0x58
1 1 0 2 0x68
2 1 1 2.1 0x6AC0
5 1 2 2.1.1 0x6AD6
9 1 5 2.1.1.1 0x6AD6B0
10 1 5 2.1.1.2 0x6AD6D0
11 1 5 2.1.1.3 0x6AD6F0
6 1 2 2.1.2 0x6ADA
7 1 2 2.1.3 0x6ADE
8 1 2 2.1.4 0x6AE1
3 1 1 2.2 0x6B40
4 1 1 2.3 0x6BC0
13 3 0 3 0x78

Related

Get output of multiple Counts in one query

Could you help me how to write a query for the following issue:
There are two tables:
Table persons:
P_id Name BirthDate
1 N1 2016-08-02
2 N2 2015-05-02
3 N3 2013-06-01
4 N4 2014-01-09
Table visited:(p_id is foreign key to table persons)
Id. Visitor_id. P_id. Visit_date
1 10 1 2017-03-05
2 11 2 2017-01-01
3 10 2 2017-02-03
4 12 3 2016-05-07
5 11 4 2016-04-09
6 10 1 2017-04-09
We are going to get the count of visited by each Visitor and also count of visited distinct person on filter on for those person who their age are under 1, between 1 and 2, between 2 and 3 at date of visit_date by each visitor_id.
The results should be like :
Under_one Bet_one_two Bet_two_three
Visitor_id VisitedCount/PersonCount VisitedCount/PersonCount VisitedCount/PersonCount
10 2 1 1 1 0 0
11 0 0 1 1 1 1
12 0 0 0 0 1 1
Between 1 and 2 means the result of subtracting visited_date and birthdate (for example : the result of 2013/03/05 - 2011/06/07) is between 1 and 2 years.
I don't know if I can give you the output laid out exactly as you have specified, but this
SELECT
visited.Visitor_id,
visited.P_id,
Int(([Visit_date]-[BirthDate])/365) AS Age,
Count(persons.P_id) AS NumVisits
FROM persons INNER JOIN visited ON persons.P_id = visited.P_id
GROUP BY
visited.Visitor_id,
visited.P_id,
Int((-[BirthDate]+[Visit_date])/365);
returns
Visitor_id P_id Age NumVisits
10 1 0 2
10 2 1 1
11 2 1 1
11 4 2 1
12 3 2 1

T-SQLHelp - Generating Ids

I have a set of data where I need to generate SetIds. Basically, if I where to walkthrough the first dataset with an order on column ID, I want to increament a counter everytime I hit a RecordType of 5. See the second sample on desired output.
Id RecordType Amount
----------------------------
1 5 1.00
2 6 1.00
3 7 3.00
5 5 1.00
6 6 .50
7 6 .50
8 8 1.00
9 5 .05
Id RecordType Amount SetId
-------------------------------------
1 5 1.00 1
2 6 1.00 1
3 7 3.00 1
5 5 1.00 2
6 6 .50 2
7 6 .50 2
8 8 1.00 2
9 5 .05 3
10 6 .05 3
Your initial sample data was missing ID 10
DECLARE #Table Table (Id Int, RecordType Int, Amount Decimal(9,2))
Insert Into #Table (Id,RecordType,Amount) Values
(1,5,1),
(2,6,1),
(3,7,3),
(5,5,1),
(6,6,.5),
(7,6,.5),
(8,8,1),
(9,5,.05),
(10,6,.05)
Select *
,SetId = Sum(IIF(RecordType=5,1,0)) over (Order by ID)
From #Table
Order By Id
Returns
Id RecordType Amount Flag SetId
1 5 1.00 1 1
2 6 1.00 0 1
3 7 3.00 0 1
5 5 1.00 1 2
6 6 0.50 0 2
7 6 0.50 0 2
8 8 1.00 0 2
9 5 0.05 1 3
10 6 0.05 0 3
DECLARE #DataX TABLE (
Id INT IDENTITY
, RecordType INT
, Amount DECIMAL(5,2)
, SetId INT
)
INSERT INTO #DataX (RecordType, Amount) VALUES
(5,1)
, (6,1)
, (7,3)
, (5,1)
, (6,.5)
, (6,.5)
, (8,1)
, (5,.5)
; WITH SetId
AS (
SELECT Id, SUM (CASE WHEN RecordType = 5 THEN 1 ELSE 0 END) OVER (ORDER BY Id) AS SetId
FROM #DataX
)
UPDATE dx1
SET dx1.SetId = (SELECT SetId.SetId)
FROM #DataX dx1
JOIN SetId
ON dx1.Id = SetId.Id
SELECT * FROM #DataX

SQL Server SELECT Rank() and Grouping of data

Please help me with this specific query.
Here's my sample query
with cte as
(
select entryID,LogDateTime,logtype[logtype],batch,
rank() over (partition by logType
order by logdatetime) rnk
from Emp_TimeLog
where cast(LogDateTime as date) = '2016-05-17'
) select entryID,LogDateTime,logType,batch, rnk
from cte order by LogDateTime
It resulted like this
2016-05-17 11:57:44.000 1 1 1
2016-05-17 11:57:53.000 5 1 1
2016-05-17 11:57:58.000 6 1 1
2016-05-17 11:58:10.000 2 1 1
2016-05-17 11:58:18.000 1 2 2
2016-05-17 11:58:25.000 3 1 1
2016-05-17 11:58:32.000 4 1 1
2016-05-17 11:58:42.000 5 2 2
2016-05-17 11:58:49.000 6 2 2
2016-05-17 11:58:55.000 2 2 2
But what I want is like this.
2016-05-17 11:57:44.000 1 1 1
2016-05-17 11:57:53.000 5 1 1
2016-05-17 11:57:58.000 6 1 1
2016-05-17 11:58:10.000 2 1 1
2016-05-17 11:58:18.000 1 2 2
2016-05-17 11:58:25.000 3 2 2
2016-05-17 11:58:32.000 4 2 2
2016-05-17 11:58:42.000 5 2 2
2016-05-17 11:58:49.000 6 2 2
2016-05-17 11:58:55.000 2 2 2
The last 2 columns are the Batch and Rank,
while the 3rd column is the logType.
it should be group by batch of logType wherein LogType group is 1,2,3,4,5,6.
so, for every 1 group it is another batch and I need to place it on last 2 columns.
Please help with this, on how I can achieve this.
Thanks in advance.
You just need to fix the order in the rank... as:
rank() over (partition by logType
order by batch) rnk

Merge two tables while dragging one column from one table to the other

With Sql Server 2014:
I have two tables - Events and Locations, that share a time column and I need to merge them into one table order by time. In the Events table there is an Event column that I need to place in all the Locations row following that event (time wise), here is an example:
Events:
time event
------------
09:00 2
09:10 3
10:15 1
10:17 2
10:30 3
Locations:
time X Y
-------------
09:01 1 3
09:02 2 3
09:05 4 1
09:09 6 4
09:10 7 8
09:11 8 8
09:12 9 7
10:17 1 2
10:19 5 4
10:20 4 3
10:25 5 4
10:28 3 5
Merged Table:
time X Y event
--------------------
09:00 0 0 2
09:01 1 3 2 <
09:02 2 3 2 <
09:05 4 1 2 <
09:09 6 4 2 <
09:10 0 0 3
09:10 7 8 3 <
09:11 8 8 3 <
09:12 9 7 3 <
10:15 0 0 1
10:17 0 0 2
10:17 1 2 2 <
10:19 5 4 2 <
10:20 4 3 2 <
10:25 5 4 2 <
10:28 3 5 2 <
10:30 0 0 3
The elements that mark with '<' are the inserted Events.
Any ideas and help on how to perform this task is welcome.
You can use UNION ALL and APPLY:
SQL Fiddle
SELECT
[Time], X = 0, Y = 0, [Event]
FROM [Events]
UNION ALL
SELECT l.*, x.Event
FROM Locations l
CROSS APPLY(
SELECT TOP 1 *
FROM [Events]
WHERE [Time] <= l.[Time]
ORDER BY [Time] DESC
)x
ORDER BY [Time]

SQL query to get Groups and sub groups hierarchy

Account table
ac_id ac_name st_id
----------- ------------- -----------
1 LIABILITES 1
2 ASSET 1
3 REVENUE 1
4 EXPENSES 1
5 EQUITY 1
Groups table
grp_id grp_name ac_no grp_of st_id type_ cmp_id
----------- ------------------- ---------- -------- --------- --------- --------
1 Capital Account 1 0 1 0 0
2 Current Liability 1 0 1 0 0
3 Loan Liability 1 0 1 0 0
4 Suspense A/C 1 0 1 0 0
5 Current Assets 2 0 1 0 0
6 Fixed Assests 2 0 1 0 0
7 Investment 2 0 1 0 0
8 Misc. Expenses 2 0 1 0 0
9 Direct Income 3 0 1 0 0
10 Indirect Income 3 0 1 0 0
11 Sale Account 3 0 1 0 0
12 Direct Expense 4 0 1 0 0
13 Indirect Expense 4 0 1 0 0
14 Purchase Account 4 0 1 0 0
15 Sundry Creditors 2 1 1 0 0
16 Sundry Debitors 5 1 1 0 0
17 Bank Account 5 1 1 0 0
18 Cash In Hand 5 1 1 0 0
19 Duties & Taxes 2 1 1 0 0
20 Salary 12 1 1 0 0
21 Personal 5 1 1 0 0
22 Loan 2 0 1 0 0
23 Customer 16 1 1 0 0
34 Vendor 15 1 1 0 0
38 Sale Softwares 11 1 1 1 1
46 Stock In Hand 5 1 1 1 1
47 test 1 1 1 1 1
48 test in 47 1 1 1 1
Query to get all groups hierarchy.
declare #ac_no as int =2
;With CTE(grp_id,grp_name,ac_no,Level)
AS
( SELECT
grp_id,grp_name,ac_no,CAST(1 AS int)
FROM
Groups
WHERE
grp_id in (select grp_id from Groups where (ac_no=#ac_no) and grp_of=0)
UNION ALL
SELECT
o.grp_id,o.grp_name,o.ac_no,c.Level+1
FROM
Groups o
INNER JOIN
CTE c
ON c.grp_id=o.ac_no --where o.ac_no=2 and o.grp_of=1
)
select * from CTE
Result is ok for ac_no=2/3/4
grp_id grp_name ac_no Level
----------- ------------------- ----------- ------
5 Current Assets 2 1
6 Fixed Assests 2 1
7 Investment 2 1
8 Misc. Expenses 2 1
22 Loan 2 1
16 Sundry Debitors 5 2
17 Bank Account 5 2
18 Cash In Hand 5 2
21 Personal 5 2
46 Stock In Hand 5 2
23 Customer 16 3
But when I try to get result for ac_no=1;
I get error :
Msg 530, Level 16, State 1, Line 4
The statement terminated. The maximum recursion 100 has been exhausted before statement completion.
I think the issue is that you end up in an infinite recursion as you have a row that is it's own parent/child (eg. grp_id = ac_no).
I think it should work if you add a limiting clause to the recursive member like this:
DECLARE #ac_no AS int = 1;
WITH CTE (grp_id , grp_name , ac_no , Level ) AS (
SELECT grp_id, grp_name, ac_no, CAST( 1 AS int )
FROM Groups
WHERE grp_id IN (SELECT grp_id FROM Groups WHERE ac_no = #ac_no AND grp_of = 0)
UNION ALL
SELECT o.grp_id, o.grp_name, o.ac_no, c.Level + 1
FROM Groups o
INNER JOIN CTE c ON c.grp_id = o.ac_no --where o.ac_no=2 and o.grp_of=1
WHERE c.ac_no <> c.grp_id
)
SELECT * FROM CTE;

Resources