Sorting comments with nested replies - sql

I am trying to come up with a query that will return comments following their replies and its replies.
Something like
comment 1
reply 1.1
reply 1.1.1
reply 1.2
comment 2
comment 3
comment 3.1
etc
I have this so far
SELECT [CommentID]
,[ParentID]
,[Message]
, ROW_NUMBER() over(partition by ParentID order by CommentID ) as rn
,[CreatedBy]
,[CreatedDate]
FROM [DBNAME].[dbo].[Commenttable]
GROUP BY [CommentID],[ParentID],[CreatedDate],[Message],[CreatedBy]
but what I get is
comment 1
comment 2
comment 3
reply 1.1
reply 1.2
reply 3.1
reply 1.1.1
Basic Structure is just a table with Comment ID, Parent ID, and the message.
The comments and replies are just to help explain what I am trying to achieve

Give this a try:
declare #CommentTable as Table ( CommentId Int Identity, ParentId Int Null, Message VarChar(16) )
insert into #CommentTable ( ParentId, Message ) values
( null, '1' ),
( null, '2' ), ( 1, '1.1' ),
( null, '3' ), ( 4, '3.1' ), ( 3, '1.1.1' ), ( 1, '1.2' )
select * from #CommentTable
; with Cindy as (
-- Start with the base comments.
select CommentId, ParentId, Message, Row_Number() over ( order by CommentId ) as Number,
Cast( Row_Number() over ( order by CommentId ) as VarChar(1000) ) as Path,
Cast( Right( '0000' + Cast( Row_Number() over ( order by CommentId ) as VarChar(4) ), 5 ) as VarChar(1000) ) as OrderPath
from #CommentTable
where ParentId is NULL
union all
-- Add replies on layer at a time.
select CT.CommentId, CT.ParentId, CT.Message, Row_Number() over ( order by CT.CommentId ),
Cast( C.Path + '.' + Cast( Row_Number() over ( order by CT.CommentId ) as VarChar(4) ) as VarChar(1000) ),
Cast( C.OrderPath + Right( '0000' + Cast( Row_Number() over ( order by CT.CommentId ) as VarChar(4) ), 5 ) as VarChar(1000) )
from #CommentTable as CT inner join
Cindy as C on C.CommentId = CT.ParentId
)
select *
from Cindy
order by OrderPath

Related

Return random value for each row from different table

I'm trying to get random name for each row, but it just shows same random value for every row. What am I missing?
SELECT TOP (1000) v.id,v.[Name], RandomName
FROM [V3_Priva].[dbo].[Vehicle] v
cross join
(Select top 1 ISNULL([Description_cs-CZ], [Description]) RandomName
from crm.Enumeration e
join crm.EnumerationType et on e.EnumerationType_FK = et.Id
where EnumerationType_FK = 12
order by NEWID()) RandomName
Result table
Try using something like the following to drive your lookup.
DECLARE #Rows AS TABLE ( I INT NOT NULL )
DECLARE #Vals AS TABLE ( ID INT IDENTITY, Val NVARCHAR(255) NOT NULL )
INSERT INTO #Rows
VALUES ( 0 )
, ( 1 )
, ( 2 )
, ( 3 )
, ( 4 )
, ( 5 )
, ( 6 )
, ( 7 )
, ( 8 )
, ( 9 )
INSERT INTO #Vals
VALUES ( 'Apple' )
, ( 'Banana' )
, ( 'Peach' )
, ( 'Plum' )
, ( 'Pear' )
WITH cte AS ( SELECT *, ABS(CHECKSUM(NEWID())) % 5 ID FROM #Rows )
SELECT cte.I
, cte.ID
, V.ID
, V.Val
FROM cte
JOIN #Vals V ON V.ID = cte.ID + 1
ORDER BY I
This way new ID is generated for each row, rather than once for the lookup.

TSQL - Mapping Parent/Child Hierarchy

Sample Data:
DECLARE #Hierarchy TABLE
(
[ParentId] INT
, [ChildId] INT
) ;
INSERT INTO #Hierarchy
VALUES
( 1, 2 )
, ( 1, 3 )
, ( 2, 4 )
, ( 3, 5 )
, ( 4, 3 )
, ( 4, 6 )
, ( 5, 6 )
, ( 7, 3 ) ;
Current Query:
; WITH CTE AS
(
SELECT [ParentId]
, [ChildId]
, 1 AS [Level]
, CONCAT ( CAST ( [ParentId] AS VARCHAR(MAX) ), '.', CAST ( [ChildId] AS VARCHAR(MAX) ) ) AS [Path]
FROM #Hierarchy
UNION ALL
SELECT [C].[ParentId]
, [T].[ChildId]
, [C].[Level] + 1
, CAST ( [C].[Path] + '.' + CAST([T].[ChildId] AS VARCHAR(MAX) ) AS VARCHAR(MAX) )
FROM CTE AS [C]
JOIN #Hierarchy AS [T]
ON [C].[ChildId] = [T].[ParentId]
)
SELECT *
FROM CTE
ORDER BY [ParentId]
, [Level]
, [ChildId] ;
Goal:
distinctly group levels of shared "path" together
find the shallowest and the deepest levels of the shared "path"
Expected Output:
NOTICE: the records with Orange highlight at the end are manually inserted to show what I'm expecting, but haven't figure out yet.
Group: Basically a "dense rank" of each "groups" of nodes that follow the same path. I think if you look at the values of Group in the above image and relate it to Level and Path field's data, it'll make more sense.
IsShallowest: 1st level (I can see that now that someone brought it up). Just need to figure out how to derive those missing (repeating) records
IsDeepest: max level within the group.
Think IsShallowest and IsDeepest is easy to figure out once "Group" logic is figured out and adding missing (repeated) records.
Please check this solution. It provide the requested solution except adding the extra row which more information is needed
;WITH CTE AS (
SELECT
[ParentId]
, [ChildId]
, 1 AS [Level]
, CONCAT ( CAST ( [ParentId] AS VARCHAR(MAX) ), '.', CAST ( [ChildId] AS VARCHAR(MAX) ) ) AS [Path]
, MyGroup1 = ROW_NUMBER() OVER(ORDER BY [ParentId])
, MyGroup2 = ROW_NUMBER() OVER(ORDER BY [ParentId])
FROM Hierarchy
UNION ALL
SELECT
[C].[ParentId]
, [T].[ChildId]
, [C].[Level] + 1
, CAST ( [C].[Path] + '.' + CAST([T].[ChildId] AS VARCHAR(MAX) ) AS VARCHAR(MAX) )
, MyGroup1 = C.MyGroup1
, MyGroup2 = [C].[MyGroup1] + ROW_NUMBER() OVER(ORDER BY [T].[ParentId]) - 1
FROM CTE AS [C]
JOIN Hierarchy AS [T] ON [C].[ChildId] = [T].[ParentId]
)
, MyCTE2 as (
SELECT
[ParentId]
, [ChildId]
, [Level]
, [Path]
-- un-comment bellow 2 rows to see the logic
--, MyGroup1
--, MyGroup2
, MyGroup = DENSE_RANK() OVER (ORDER BY MyGroup1, MyGroup2)
FROM CTE
),
MyCTE3 as (
SELECT
[ParentId]
, [ChildId]
, [Level]
, [Path]
, MyGroup
, shallowest = ROW_NUMBER() OVER(PARTITION BY MyGroup ORDER BY [Path])
, deepest = ROW_NUMBER() OVER(PARTITION BY MyGroup ORDER BY [Path] DESC)
FROM MyCTE2
)
SELECT
[ParentId]
, [ChildId]
, [Level]
, [Path]
, MyGroup
, ISshallowest = CASE WHEN shallowest = 1 then 1 else 0 END
, Isdeepest = CASE WHEN deepest = 1 then 1 else 0 END
FROM MyCTE3
ORDER BY
--[Path]
[ParentId]
, [Level]
, [ChildId];

SQL - Prepend a value if missing

Code/data:
DECLARE #T TABLE
(
[Col1] VARCHAR(20)
, [RowNum] INT
) ;
INSERT INTO #T
VALUES
( N'second', 1 )
, ( N'fifth', 4 )
, ( N'fourth', 3 )
--, ( N'zzz', 1 )
, ( N'third', 2 )
---- OR when "zzz" is part of this list
--VALUES
-- ( N'second', 2 )
-- , ( N'fifth', 5 )
-- , ( N'fourth', 4 )
-- , ( N'zzz', 1 )
-- , ( N'third', 3 )
SELECT STUFF ((
SELECT ',' + [SQ].[Col1]
FROM
(
SELECT N'zzz' AS [Col1]
, 1 AS [RowNum]
UNION
SELECT [Col1]
, [RowNum]
FROM #T
) AS [SQ]
FOR XML PATH ( '' ), TYPE
).[value] ( '.', 'varchar(MAX)' ), 1, 1, ''
) ;
Current output:
fifth,fourth,second,third,zzz
Goal:
Prepend "zzz," in the output string if missing in the 2nd part of the union AND the values should be in ASC ordered based on the values specified in [rownum] field defined in the 2nd part of the union. If "zzz" exists in the 2nd part of the input already (it will always be RowNum 1 in that case), it should return it only once as the first value.
Expected output:
zzz,second,third,fourth,fifth
UPDATED the requirement due to an error on my part when creating this post. Updated code/data represents more accurate scenario. Please note the RowNum seq in the 2nd part of the UNION, it also starts with 1, but this time, it might or might not be associated to "zzz" Basically, I want to prepend "zzz" in the comma-delimited & ordered output if it doesn't exist.
Hope the below one will help you.
SELECT ',' + [SQ].[Col1]
FROM
(
SELECT N'first' AS [Col1],1 AS [RowNum]
UNION
SELECT [ABC].[Col1],[ABC].[RowNum]
FROM
(
VALUES
( N'second', 2 )
, ( N'fifth', 5 )
, ( N'fourth', 4 )
--, ( N'first', 1 )
, ( N'third', 3 )
) AS [ABC] ( [Col1], [RowNum] )
) AS [SQ]
ORDER BY [RowNum]
FOR XML PATH ( '' ), TYPE
).[value] ( '.', 'varchar(MAX)' ), 1, 1, ''
) ;
Returns an output
first,second,third,fourth,fifth
Attached the Answer for the updated Scenario-
DECLARE #T TABLE
(
[Col1] VARCHAR(20)
, [RowNum] INT
) ;
INSERT INTO #T
VALUES
( N'second', 1 )
, ( N'fifth', 4 )
, ( N'fourth', 3 )
--, ( N'zzz', 1 )
, ( N'third', 2 )
---- OR when "zzz" is part of this list
--VALUES
-- ( N'second', 2 )
-- , ( N'fifth', 5 )
-- , ( N'fourth', 4 )
-- , ( N'zzz', 1 )
-- , ( N'third', 3 )
SELECT STUFF ((
SELECT ',' + [SQ].[Col1]
FROM
(
SELECT N'zzz' AS [Col1]
, 0 AS [RowNum]
UNION
SELECT [Col1]
, [RowNum]
FROM #T
) AS [SQ]
ORDER BY [RowNum]
FOR XML PATH ( '' ), TYPE
).[value] ( '.', 'varchar(MAX)' ), 1, 1, ''
) ;
Returns
zzz,second,third,fourth,fifth
Common Table Expressions (CTEs) provide a handy way of breaking queries down into simpler steps. Note that you can view the results of each step by switching out the last select statement.
with
Assortment as (
-- Start with the "input" rows.
select Col1, RowNum
from ( values ( N'second', 2 ), ( N'fifth', 5 ), ( N'fourth', 4 ),
-- ( N'first', 1 ),
( N'third', 3 ) ) ABC ( Col1, RowNum ) ),
ExtendedAssortment as (
-- Conditionally add "first".
select Col1, RowNum
from Assortment
union all -- Do not remove duplicate rows.
select N'first', 1
where not exists ( select 42 from Assortment where Col1 = N'first' ) )
-- Output the result.
-- Intermediate results may be seen by uncommenting one of the alternate select statements.
-- select * from Assortment;
-- select * from ExtendedAssortment;
select Stuff(
( select N',' + Col1 from ExtendedAssortment order by RowNum for XML path(N''), type).value( N'.[1]', 'NVarChar(max)' ),
1, 1, N'' ) as List;
The same logic can be performed using tables for input:
-- Rows to be included in the comma delimited string.
declare #Input as Table ( Col1 NVarChar(20), RowNum Int );
insert into #Input ( Col1, RowNum ) values
( N'second', 2 ), ( N'fifth', 5 ),
--( N'ZZZ', 17 ), -- Test row.
( N'fourth', 4 ), ( N'third', 3 );
select * from #Input;
-- Mandatory value that must appear in the result. One row only.
declare #Mandatory as Table ( Col1 NVarChar(20), RowNum Int );
-- By using the maximum negative value for an Int this value will be prepended
-- (unless other rows happen to have the same RowNum value).
insert into #Mandatory ( Col1, RowNum ) values ( N'ZZZ', -2147483648 );
select * from #Mandatory;
-- Process the data.
with
AllRows as (
select Col1, RowNum
from #Input
union all
select Col1, RowNum
from #Mandatory
where not exists ( select 42 from #Mandatory as M inner join #Input as I on M.Col1 = I.Col1 ) )
-- Output the result.
-- Intermediate results may be seen by uncommenting the alternate select statement.
--select * from AllRows;
select Stuff(
( select N',' + Col1 from AllRows order by RowNum for XML path(N''), type).value( N'.[1]', 'NVarChar(max)' ),
1, 1, N'' ) as List;

converting rows into columns in sql server

I wonder if anyone can help: I want to convert rows into columns. This is the original table:
I have tried using pivot but this case it is too complex for me.
declare #Table AS TABLE
(
TYPE VARCHAR(100) ,
SERIE VARCHAR(100) ,
CUR1 INT,
CUR2 INT
)
INSERT #Table
( TYPE, SERIE, CUR1, CUR2)
VALUES
( 'CORP', 'S1' ,2122,322 ),
( 'CORP', 'S2' ,321,546 ),
( 'SER', 'S1',543,788 ),
( 'SER', 'S2' ,655, 988 )
I expect the output to be like the attached table:
Please try this, a variant of this will help:-
;with cte as (
select SERIE, [CORP] as [CORP_CUR1], [SER] as [SER_CUR1] from (
select type , serie, cur1 from #Table)
as d
pivot
( max(cur1) for [type] in ( [CORP], [SER]) ) as p
),
ct as (
select SERIE, [CORP] as [CORP_CUR2], [SER] as [SER_CUR2] from (
select type , serie, cur2 from #Table)
as d
pivot
( max(cur2) for [type] in ( [CORP], [SER]) ) as p
)
select cte.SERIE, cte.[CORP_CUR1], cte.[SER_CUR1], ct.[CORP_CUR2], ct.[SER_CUR2] from cte inner join ct on cte.SERIE=ct.SERIE

Find page number by row ID in paged list

Is there any way to determine a page numer (in paged list), that contains row with given ID?
Something like this would work in T-SQL if you make sure the ORDER BY is accurate for what you're sorting by:
DECLARE #RowId INT = 55
, #PageSize INT = 10;
DECLARE #Data TABLE
(
Id INT IDENTITY(1,1)
, Value INT
)
INSERT #Data
SELECT
CAST(V.number AS INT)
FROM master..spt_values V
WHERE V.[type] = 'P'
AND CAST(V.number AS INT) BETWEEN 1 AND 100
;WITH RankedData AS
(
SELECT
ROW_NUMBER() OVER(ORDER BY D.Value) AS Row
, D.Id
FROM
#Data D
)
SELECT
(SELECT Row FROM RankedData WHERE Id = #RowId) / #PageSize
declare #Foo as table ( FooId int identity, Bar varchar(16) )
insert into #Foo ( Bar ) values ( 'this' ), ( 'is' ), ( 'some' ), ( 'sample' ), ( 'data' ), ( 'eh?' )
declare #PageSize int = 3
-- Display the page numbers. Note that there must be an explicit order.
select FooId, Bar, ( RN + #PageSize - 1 ) / #PageSize as Page
from (
select FooId, Bar, Row_Number() over ( order by Bar ) as RN
from #Foo
) as Janet
-- Retrieve a single page number based on a FooId .
select FooId, Bar, ( RN + #PageSize - 1 ) / #PageSize as Page
from (
select FooId, Bar, Row_Number() over ( order by Bar ) as RN
from #Foo
) as Janet
where FooId = 3