SQL Server Recursive Query to get Top parent - sql

I need your help on making on recursive query using a CTE in SQL Server.
I have order no as input parameter.. I need to display its top parent despatch details. even if I search for its children.. ie if I search for order no 3 I should get its top parent order no. that is 20.
Here is my table structure..
CREATE TABLE #TblSerialNo
(
[SRno] [char](20) NOT NULL ,
[CustSrNo] [varchar](75) NULL
)
CREATE TABLE #TblSerialReleation
(
[SRno] [char](20) NOT NULL ,
[ChildSRno] [char](20) NOT NULL
)
CREATE TABLE #TblDespatch
(
[SRno] [char](20) NOT NULL ,
OrderNo INT NOT NULL
)
INSERT INTO #TblSerialNo VALUES ( 'TS1', 'DD123CV1' )
INSERT INTO #TblSerialNo VALUES ( 'TS2', 'DD123CV2' )
INSERT INTO #TblSerialNo VALUES ( 'TS3', 'DD123CV3' )
INSERT INTO #TblSerialNo VALUES ( 'BS1', 'DD12sfs3CV1' )
INSERT INTO #TblSerialNo VALUES ( 'BS2', 'DD1et23CV2' )
INSERT INTO #TblSerialNo VALUES ( 'CS1', 'DD12e3CV1' )
INSERT INTO #TblSerialNo VALUES ( 'CS2', 'DD12fe3CV2' )
INSERT INTO #TblSerialNo VALUES ( 'BS1aa', 'DD12d3CV1' )
INSERT INTO #TblSerialNo VALUES ( 'BS1ab', 'DDd123CV2' )
INSERT INTO #TblSerialNo VALUES ( 'BS1ac', 'DD1r23CV3' )
INSERT INTO #TblSerialNo VALUES ( 'BS2aa', 'DDs123CV4' )
INSERT INTO #TblSerialNo VALUES ( 'BS2ab', 'DD12d3CV1' )
INSERT INTO #TblSerialNo VALUES ( 'BS2ac', 'DD1s23CV2' )
INSERT INTO #TblSerialNo VALUES ( 'CS1aa', 'DD1s23CV3' )
INSERT INTO #TblSerialNo VALUES ( 'CS1ab', 'DD12s3CV4' )
INSERT INTO #TblSerialNo VALUES ( 'CS1ac', 'DD123dCV1' )
INSERT INTO #TblSerialNo VALUES ( 'CS2aa', 'DDa123CV2' )
INSERT INTO #TblSerialNo VALUES ( 'CS2ab', 'DDa123CV3' )
INSERT INTO #TblSerialNo VALUES ( 'CS2ac', 'DDa123CV4' )
--================ Relation table ==============
INSERT INTO #TblSerialReleation VALUES ( 'TS1', 'BS1' )
INSERT INTO #TblSerialReleation VALUES ( 'TS1', 'BS2' )
INSERT INTO #TblSerialReleation VALUES ( 'TS2', 'CS1' )
INSERT INTO #TblSerialReleation VALUES ( 'TS2', 'CS2' )
INSERT INTO #TblSerialReleation VALUES ( 'BS1', 'BS1aa' )
INSERT INTO #TblSerialReleation VALUES ( 'BS1', 'BS1ab' )
INSERT INTO #TblSerialReleation VALUES ( 'BS1', 'BS1ac' )
INSERT INTO #TblSerialReleation VALUES ( 'BS2', 'BS2aa' )
INSERT INTO #TblSerialReleation VALUES ( 'BS2', 'BS2ab' )
INSERT INTO #TblSerialReleation VALUES ( 'BS2', 'BS2ac' )
INSERT INTO #TblSerialReleation VALUES ( 'CS1', 'CS1aa' )
INSERT INTO #TblSerialReleation VALUES ( 'CS1', 'CS1ab' )
INSERT INTO #TblSerialReleation VALUES ( 'CS1', 'CS1ac' )
INSERT INTO #TblSerialReleation VALUES ( 'CS2', 'CS2aa' )
INSERT INTO #TblSerialReleation VALUES ( 'CS2', 'CS2ab' )
INSERT INTO #TblSerialReleation VALUES ( 'CS2', 'CS2ac' )
--=========== Despatch
INSERT INTO #TblDespatch VALUES ( 'CS2ac', 1 )
INSERT INTO #TblDespatch VALUES ( 'CS2ab', 1 )
INSERT INTO #TblDespatch VALUES ( 'CS2ac', 1 )
INSERT INTO #TblDespatch VALUES ( 'CS1aa', 1 )
INSERT INTO #TblDespatch VALUES ( 'CS1ac', 1 )
INSERT INTO #TblDespatch VALUES ( 'CS2ac', 1 )
INSERT INTO #TblDespatch VALUES ( 'CS2ac', 1 )
INSERT INTO #TblDespatch VALUES ( 'TS1', 1 )
INSERT INTO #TblDespatch VALUES ( 'TS3', 2 )
INSERT INTO #TblDespatch VALUES ( 'TS2', 3 )
INSERT INTO #TblDespatch VALUES ( 'BS2ab', 20 )
DROP TABLE #TblDespatch
DROP TABLE #TblSerialNo
DROP TABLE #TblSerialReleation
Thanks in advance.

Looking at your data, the relation seems to go the other way around (BS2ab (Order 20) is the child of TS1(Order 3) through BS2.
If this is the case, starting from the child (BS2ab) you can find its top parent with the following statement:
;with ParentOrders as(
select
convert(char(20), 'BS2ab')as SRno,
0 as Level
union all
select r.SRno, o.Level + 1
from ParentOrders o
join TblSerialReleation r
on o.SRNo = r.ChildSRno
)
select top 1 SRNO
from ParentOrders
order by Level desc
Here's a working sample of the query: http://www.sqlfiddle.com/#!3/e253e/6

Related

Derive StartDateTime and EndDateTime from SingleDateTime column with some condition-SQL EXPERTS

For better understanding please find the attached image (For detailed information please click here)
Condition:
value_string/Value_Float column field value present i.e Greater than 0, consider as Start_DateTime, next row have same value don’t consider that value just ignore that field. else next row it consists different value consider that one as start_datetime.
If value_string/Value_Float column field value 0,consider as End_Time,In every Group if First Value 0 don’t consider.after the start_Datetime arrived 0 considered as End_dateTime
If the group does not finish with 0(End_dateTime) show the field as 'Null'(Example Group C)
Source Table:
Desired Result
Create Table
CREATE TABLE [dbo].[Activity]
(
[DateTime] [datetime] NULL,
[Group] [nvarchar](255) NULL,
[Value_String] [float] NULL,
[Value_Float] [float] NULL
)
Insert values
Insert INTO [Activity] VALUES ( '2021-06-23 11:32.000','A','0',0)
Insert INTO [Activity] VALUES ( '2021-06-23 12:13.000','A','1',1)
Insert INTO [Activity] VALUES ( '2021-06-23 17:25.000','A','0',0)
Insert INTO [Activity] VALUES ( '2021-06-24 07:32.000','A','12',12)
Insert INTO [Activity] VALUES ( '2021-06-24 11:30.000','A','0',0)
Insert INTO [Activity] VALUES ( '2021-06-23 05:02.000','B','15',15)
Insert INTO [Activity] VALUES ( '2021-06-23 06:20.000','B','0',0)
Insert INTO [Activity] VALUES ( '2021-06-23 08:16.000','B','5',5)
Insert INTO [Activity] VALUES ( '2021-06-24 19:12.000','B','5',5)
Insert INTO [Activity] VALUES ( '2021-06-24 23:29.000','B','0',0)
Insert INTO [Activity] VALUES ( '2021-06-23 11:42.000','C','0',0)
Insert INTO [Activity] VALUES ( '2021-06-23 13:20.000','C','4',4)
Insert INTO [Activity] VALUES ( '2021-06-23 16:15.000','C','0',0)
Insert INTO [Activity] VALUES ( '2021-06-24 17:52.000','C','4',4)
Insert INTO [Activity] VALUES ( '2021-06-24 23:12.000','C','4',4)
Insert INTO [Activity] VALUES ( '2021-06-23 11:32.000','D','17',17)
Insert INTO [Activity] VALUES ( '2021-06-23 13:47.000','D','15',15)
Insert INTO [Activity] VALUES ( '2021-06-23 16:48.000','D','0',0)
Insert INTO [Activity] VALUES ( '2021-06-24 17:32.000','D','24',24)
Insert INTO [Activity] VALUES ( '2021-06-24 19:32.000','D','0',0)
…
select min([Datetime]) as startdt, max(next0datetime) as enddt, [Group], Value_String, Value_Float
from
(
select *, sum(addme) over(partition by [Group] order by [DateTime]) as grpid
from
(
select *,
min(case when Value_String = '0' then [Datetime] end) over(partition by [Group] order by [DateTime] rows between 1 following and unbounded following)
as next0datetime,
case when Value_String <> lag(Value_String) over(partition by [Group] order by [DateTime]) then 1 else 0 end as addme
from dbo.Activity
) as a
) as g
where Value_String <> '0'
group by [Group], grpid, Value_String, Value_Float
order by [Group], startdt, enddt;

How do you count the number of rows in a table that have the same value in value in a column?

Suppose I have the following simple table:
create table mytable (
desid bigint not null,
ancid bigint not null
);
insert into mytable (ancid,desid) values (1,10);
insert into mytable (ancid,desid) values (1,20);
insert into mytable (ancid,desid) values (1,21);
insert into mytable (ancid,desid) values (1,22);
insert into mytable (ancid,desid) values (2,30);
insert into mytable (ancid,desid) values (3,40);
insert into mytable (ancid,desid) values (3,41);
insert into mytable (ancid,desid) values (3,42);
insert into mytable (ancid,desid) values (3,43);
What is the SQL command that will print out the following information:
4 rows with ancid=1
1 rows with ancid=2
4 rows with ancid=3
You can get the information by grouping by the ancid:
SELECT ancid, COUNT(*)
FROM mytable
GROUP BY ancid

SQL Finding multiple combinations in 2 tables (with all records)

I have two tables, one with some user configurations (#USERCONFIG) and the other (#COMBINATIONS), multiples combinations of configurations I need to find in the first table.
CREATE TABLE #COMBINATIONS (INDEX1 INT, MENU CHAR(10))
CREATE TABLE #USERCONFIG (USERID VARCHAR(10), MENU VARCHAR(10))
INSERT INTO #COMBINATIONS VALUES (1, 'ABC300')
INSERT INTO #COMBINATIONS VALUES (1, 'ABC400')
INSERT INTO #COMBINATIONS VALUES (2, 'ABC100')
INSERT INTO #COMBINATIONS VALUES (2, 'ABC500')
INSERT INTO #COMBINATIONS VALUES (2, 'ABC600')
INSERT INTO #USERCONFIG VALUES ('SMITHJ', 'ABC100')
INSERT INTO #USERCONFIG VALUES ('SMITHJ', 'ABC500')
INSERT INTO #USERCONFIG VALUES ('SMITHJ', 'ABC600')
INSERT INTO #USERCONFIG VALUES ('SMITHC', 'ABC100')
INSERT INTO #USERCONFIG VALUES ('SMITHC', 'ABC500')
INSERT INTO #USERCONFIG VALUES ('SMITHA', 'ABC100')
INSERT INTO #USERCONFIG VALUES ('SMITHA', 'ABC200')
INSERT INTO #USERCONFIG VALUES ('SMITHA', 'ABC300')
INSERT INTO #USERCONFIG VALUES ('SMITHA', 'ABC400')
INSERT INTO #USERCONFIG VALUES ('SMITHA', 'ABC600')
With this example data, I want the resultset to look like this:
'SMITHJ', '2'
'SMITHA', '1'
'SMITHC', '2'
Where it will return all users that have a match of configurations from the combinations table.
Any help would be appreciated.
The following will list users and the complete combinations they have. If it helps, you can think of it as the recipe-ingredient and user-ingredient textbook problem:
SELECT alluser.USERID, index_menu.INDEX1
FROM (SELECT DISTINCT USERID FROM #USERCONFIG) AS alluser
CROSS JOIN #COMBINATIONS AS index_menu
LEFT JOIN #USERCONFIG AS user_menu ON alluser.USERID = user_menu.USERID AND index_menu.MENU = user_menu.MENU
GROUP BY alluser.USERID, index_menu.INDEX1
HAVING COUNT(index_menu.MENU) = COUNT(user_menu.MENU)
This snippet will get that result:
IF OBJECT_ID('tempdb..#COMBINATIONS') IS NOT NULL DROP TABLE #COMBINATIONS;
IF OBJECT_ID('tempdb..#USERCONFIG') IS NOT NULL DROP TABLE #USERCONFIG;
CREATE TABLE #COMBINATIONS (INDEX1 INT, MENU VARCHAR(10));
CREATE TABLE #USERCONFIG (USERID VARCHAR(10), MENU VARCHAR(10));
INSERT INTO #COMBINATIONS (INDEX1, MENU) VALUES
(1, 'ABC301'),
(1, 'ABC401'),
(2, 'ABC102'),
(2, 'ABC502'),
(2, 'ABC602');
INSERT INTO #USERCONFIG (USERID, MENU) VALUES
('SMITHJ', 'ABC102'),
('SMITHJ', 'ABC502'),
('SMITHJ', 'ABC602'),
('SMITHC', 'ABC102'),
('SMITHC', 'ABC502'),
('SMITHA', 'ABC102'),
('SMITHA', 'ABC200'),
('SMITHA', 'ABC301'),
('SMITHA', 'ABC401'),
('SMITHA', 'ABC602');
SELECT USERID, INDEX1
FROM
(
SELECT uconf.USERID, comb.INDEX1,
COUNT(*) AS Total,
DENSE_RANK() OVER (PARTITION BY uconf.USERID ORDER BY COUNT(*) DESC, comb.INDEX1 ASC) AS Rnk
FROM #USERCONFIG uconf
INNER JOIN #COMBINATIONS comb
ON comb.MENU = uconf.MENU
GROUP BY uconf.USERID, INDEX1
) q
WHERE Rnk = 1
ORDER BY Total DESC, USERID;
Returns:
USERID INDEX1
SMITHJ 2
SMITHA 1
SMITHC 2

Transpose rows to columns without aggragation

I want to transpose rows to columns against RuleID and Dname.Following is sample data. Please help me out to acheive it
CREATE TABLE [dbo].[Table1](
[RuleID] [nvarchar](10) NULL,
[DateTime1] [datetime] NULL,
[DName] [nvarchar](30) NULL
) ON [PRIMARY]
INSERT [dbo].Table1 ([RuleID], [DateTime1], [DName]) VALUES (N'DBRS', CAST(N'2017-03-28T12:22:04.000' AS DateTime), N'DB1')
INSERT [dbo].Table1 ([RuleID], [DateTime1], [DName]) VALUES (N'DBRK', CAST(N'2017-03-28T12:22:04.260' AS DateTime), N'DB1')
INSERT [dbo].Table1 ([RuleID], [DateTime1], [DName]) VALUES (N'DBRE', CAST(N'2017-03-28T12:22:09.000' AS DateTime), N'DB1')
INSERT [dbo].Table1 ([RuleID], [DateTime1], [DName]) VALUES (N'DBRK', CAST(N'2017-04-04T08:33:15.870' AS DateTime), N'DB2')
INSERT [dbo].Table1 ([RuleID], [DateTime1], [DName]) VALUES (N'DBRE', CAST(N'2017-04-04T08:33:31.000' AS DateTime), N'DB2')
INSERT [dbo].Table1 ([RuleID], [DateTime1], [DName]) VALUES (N'DBRK', CAST(N'2017-04-04T09:14:30.503' AS DateTime), N'DB2')
INSERT [dbo].Table1 ([RuleID], [DateTime1], [DName]) VALUES (N'DBRS', CAST(N'2017-04-04T09:14:31.000' AS DateTime), N'DB2')
INSERT [dbo].Table1 ([RuleID], [DateTime1], [DName]) VALUES (N'DBRE', CAST(N'2017-04-04T09:44:33.000' AS DateTime), N'DB2')
Desired Output:
SELECT 'DB1' As DName,'2017-03-28 12:22:04.260'AS BRKIndicated ,'2017-03-28 12:22:04.000' As BRKStart,'2017-03-28 12:22:09.000' AS BRKEnd
UNION
SELECT 'DB2'As DName,'2017-04-04 08:33:15.870'AS BRKIndicated,NULL As BRKStart,'2017-04-04 08:33:31.000'AS BRKEnd
UNION
SELECT 'DB2'As DName,'2017-04-04 09:14:30.503'AS BRKIndicated,'2017-04-04 09:14:31.000' As BRKStart,'2017-04-04 09:44:33.000'AS BRKEnd
Use PIVOT table :
SELECT *
FROM
(
SELECT *
FROM Table1
) A
PIVOT
(
MAX(DateTime1) FOR RuleID IN ([DBRS],[DBRK],[DBRE])
)pvt
Use a self join
select D1.DName, D1.DateTime1 as DBRS, D2.DateTime1 as DBRK, D3.DateTime1 as DBRE
from Table1 D1
inner join Table1 D2
on D1.DName = D2.DName
and D2.RuleID = 'DBRK'
inner join Table1 D3
on D1.DName = D3.DName
and D3.RuleID = 'DBRE'
where D1.RuleID = 'DBRS'
If it's possible that one of the values might be missing, use LEFT JOIN instead

SQL Server Grouped results containing number and null values

I want to build a query which will return only the phase_ids that contain level_id values of BOTH numeric AND null
In the following example I would expect to return phase_id 1,3
DECLARE #tbl TABLE
(phase_id numeric(10,0) null,
type_id numeric(10,0) null,
level_id numeric(10,0) null)
INSERT #tbl VALUES (1,1,1)
INSERT #tbl VALUES (1,2,1)
INSERT #tbl VALUES (1,5,2)
INSERT #tbl VALUES (1,1,5)
INSERT #tbl VALUES (1,1,NULL)
INSERT #tbl VALUES (2,1,2)
INSERT #tbl VALUES (2,3,6)
INSERT #tbl VALUES (2,1,1)
INSERT #tbl VALUES (3,1,6)
INSERT #tbl VALUES (3,1,NULL)
SELECT * FROM #tbl
Thank you
count(*) counts all rows, count(level_id) counts non-null rows:
select phase_id
from tbl
group by phase_id
having count(*) <> count(level_id)
and count(level_id) > 0