How to get GroupName and GroupMembers in a Row - tsql

I have a table with GroupMembers and GorupName in 2 Columns as
Col 1 GroupMember Col2 GroupName
A1 A
A2 A
B1 B
B2 B
C1 C
C2 C
How to get output result as
A - GroupName
A1 - GroupMember
A2 - GroupMember
B
B1
B2
C
C1
C2
Here I am trying to get the GroupName and its GroupMembers in a single Column

;with Groups AS
(
select distinct GroupName from YourTableName
)
,OrderedGroups AS
(
select GroupName, ROW_NUMBER() Over(order by GroupName) R from Groups
)
,RankedData As
(
select T.GroupMember, T.GroupName, OG.R from YourTableName T
inner join OrderedGroups OG on T.GroupName = OG.GroupName
)
select GroupMember, R from RankedData
union
select GroupName, R from RankedData
order by R

Related

DB2: SQL to return all rows in a group having a particular value of a column in two latest records of this group

I have a DB2 table having one of the columns (A) which has either value PQR or XYZ.
I need output where the latest two records based on col C date have value A = PQR.
Sample Table
A B C
--- ----- ----------
PQR Mark 08/08/2019
PQR Mark 08/01/2019
XYZ Mark 07/01/2019
PQR Joe 10/11/2019
XYZ Joe 10/01/2019
PQR Craig 06/06/2019
PQR Craig 06/20/2019
In this sample table, my output would be Mark and Craig records
Since 11.1
You may use the nth_value OLAP function.
Refer to OLAP specification.
SELECT A, B, C
FROM
(
SELECT
A, B, C
, NTH_VALUE (A, 1) OVER (PARTITION BY B ORDER BY C DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) C1
, NTH_VALUE (A, 2) OVER (PARTITION BY B ORDER BY C DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) C2
FROM TAB
)
WHERE C1 = 'PQR' AND C2 = 'PQR'
dbfiddle link.
Older versions
SELECT T.*
FROM TAB T
JOIN
(
SELECT B
FROM
(
SELECT
A, B
, ROWNUMBER() OVER (PARTITION BY B ORDER BY C DESC) RN
FROM TAB
)
WHERE RN IN (1, 2)
GROUP BY B
HAVING MIN(A) = MAX(A) AND COUNT(1) = 2 AND MIN(A) = 'PQR'
) G ON G.B = T.B;
A simple solution could be
SELECT A,B,C
FROM tab
WHERE A = 'PQR'
ORDER BY C DESC FETCH FIRST 2 ROWS only

Group retrieved records from a RECURSIVE query, that have the same parents, grandparents

I have a table with Item(s) than are in a ManyToMany Relationship with Category.
Item
id | name
1 name1
2 name2
3 name3
ItemCategory
id | category_id | item_id
1 4 1
2 5 1
3 7 1
4 8 1
Category (parent_id foreign key to itself)
id | parent_id | name
1 Null A1
2 1 B1
3 1 B2
4 2 C1
5 3 C2
6 1 D1
7 6 DE
8 1 DT
I'm trying to get the Item Categories, from child to parent, for an Item so I use:
WITH RECURSIVE descendants(name, id, slug, parent_id, bread_order) AS (
SELECT name, id, slug, parent_id, 0
FROM categories
where id in (
SELECT c.id FROM items AS p
INNER JOIN items_categories AS pc ON p.id=pc.item_id
INNER JOIN categories AS c ON pc.category_id = c.id
WHERE p.id = 10
)
UNION ALL
SELECT c2.name, c2.id, c2.slug, c2.parent_id, bread_order+1
FROM categories AS c2
INNER JOIN descendants AS d ON c2.id=d.parent_id
) SELECT id, name, parent_id, bread_order FROM descendants
ORDER by bread_order DESC
The problem is that two child Categories can have the same parent, or a parent for one is grand parent for the other.
C1 -> B1 -> A1
C2 ->B1 -> A1
C3 ->B2  -> A1
DE -> D1 -> A1
DT -> A1
I tried to group them but, because have the same parents, grand_parents is not what I need, I need when I retrieve the information from database to know how to make the path(See above).
Is there any way, like using CASE with the IDs that returns from the subquery ?
You can aggregate the path during the query:
WITH RECURSIVE descendants(name, id, parent_id, bread_order, path) AS (
SELECT name, id, parent_id, 0, array[id] as path
FROM categories
where id in (SELECT c.id
FROM items AS p
JOIN items_categories AS pc ON p.id=pc.item_id
JOIN categories AS c ON pc.category_id = c.id
WHERE p.id = 1)
UNION ALL
SELECT c2.name, c2.id, c2.parent_id, bread_order+1, d.path||c2.id
FROM categories AS c2
JOIN descendants AS d ON c2.id=d.parent_id
)
SELECT id, name, parent_id, path, bread_order
FROM descendants
ORDER by path

Displaying related child records on a single row

in DBs I'm familiar with, a query listing parents and children would look like this:
Parfirst ParLast Childfirst
Mary Smith Sally
Mary Smith Jim
Mary Smith Kim
However, I've been asked to create a report that looks like this:
Parfirst ParLast Child1 Child2 Child3 Child4
Mary Smith Sally Jim Kim
I'm at a loss as to how to accomplish this. Any suggestions are welcome.
You can do this using STRING_AGG function (if you are using SQL Server 2017 or newer) or to do some ugly XML magic using FOR XML:
SELECT t.ParFirst, t.ParLast, LEFT(t.Children, Len(t.Children)-1) As Children
FROM
(
SELECT DISTINCT p.ParFirst, p.ParLast,
(
SELECT c.ChildFirst + ',' AS [text()]
FROM dbo.Children c
WHERE c.ParentId = p.ParentId
ORDER BY c.ChildFirst
FOR XML PATH ('')
) l
FROM dbo.Parents p
) t
SELECT p.ParFirst, p.ParLast, STRING_ACC(c.ChildFirst, ',') as Children
FROM dbo.Parents p
LEFT JOIN dbo.Children c on c.ParentId = p.ParentId
GROUP BY p.ParFirst, p.ParLast
If you want to include every child name in it's own column, you must define these columns in your query and you won't be able to return any additional child, if there is more than the number of columns you defined. Use ROW_NUMBER like this:
select p.ParFirst, p.ParLast, c1.ChildFirst, c2.ChildFirst, c3.ChildFirst
from dbo.Parents p
outer apply ( select ChildFirst from (select ChildFirst, row_number() over (order by ChildFirst) as rowNo from dbo.Children c where c.ParentId = p.ParentId) t1 where t1.rowNo = 1 ) c1
outer apply ( select ChildFirst from (select ChildFirst, row_number() over(order by ChildFirst) as rowNo from dbo.Children c where c.ParentId = p.ParentId) t2 where t2.rowNo = 2 ) c2
outer apply ( select ChildFirst from (select ChildFirst, row_number() over(order by ChildFirst) as rowNo from dbo.Children c where c.ParentId = p.ParentId) t3 where t3.rowNo = 3 ) c3

How to order by count desc in each group in a hive?

Here's the HQL:
select A, B, count(*) as cnt from test_table group by A, B order by cnt desc;
The sample output is as follows:
a1 | b1 | 5
a2 | b1 | 3
a1 | b2 | 2
a2 | b2 | 1
But what I want is to do the order by in each group of A, and the intended output is like:
a1 | b1 | 5
a1 | b2 | 2
a2 | b1 | 3
a2 | b2 | 1
Could anyone can give me some idea how to resolve this problem in just one HQL? Thanks a lot!
select A, B, count(*) as cnt
from test_table
group by A, B
order by A, cnt desc;
Try this query:
If you want only order of A then:
select A, B, count(*) as cnt from test_table group by A, B order by A asc;
If you want order of A and B then:
select A, B, count(*) as cnt from test_table group by A, B order by A asc,B asc;
Hope this helps.
select A, B, count(*) as cnt from test_table group by A, B order by A asc, B asc, cnt desc;

Aggregate similar row

Suppose I've a table like this:
NAME REF1 REF2 DRCT
A (null) Ra D1
A Rb (null) D1
A (null) Rc D2
B Rd (null) D3
B (null) Re D3
I want aggregate this table in something like:
NAME REF1 REF2 DRCT
A Rb Ra D1
A (null) Rc D2
B Rd Re D3
As you can see, i want aggregate each row with same name. I've search through COALESCE and various aggregate functions but I haven't found what i was looking for. Any idea?
Assuming that what I ask in my previous comment is true, (only null or a given value for REF1 and REF2 for each NAME, DRCT pair), this seems to work:
select NAME, M_REF1, M_REF2, DRCT
from (
select A.NAME, coalesce(A.REF1, B.REF1) m_REF1,
coalesce(A.REF2, B.REF2) m_REF2, A.REF1 A_REF1, B.REF1 B_REF1,
A.REF2 A_REF2, B.REF2 B_REF2, A.DRCT
from Table1 A JOIN Table1 B on A.NAME = B.NAME AND A.DRCT = B.DRCT)
WHERE A_REF1 = m_REF1 AND B_REF2 = m_REF2
UNION
select A.NAME, A.REF1, A.REF2, A.DRCT
FROM Table1 A JOIN
(select NAME, DRCT, COUNT(*)
from Table1
group by NAME, DRCT
HAVING COUNT(*) = 1) B ON A.NAME = B.NAME AND A.DRCT = B.DRCT;
The union is used because the rows with only one record are not included in the first SELECT.
But this is somewhat simpler, and works too:
select A.NAME, coalesce(A.REF1, B.REF1) M_REF1, coalesce(A.REF2,B.REF2) M_REF2,A.DRCT
from Table1 A LEFT OUTER JOIN Table1 B ON A.DRCT = B.DRCT AND A.NAME = B.NAME
WHERE NVL2(A.REF1,0,1) = 1 AND NVL2(B.REF1,0,1) =0
AND NVL2(A.REF2,0,1) = 0 AND NVL2(B.REF2,0,1) = 1
UNION
select A.NAME, A.REF1, A.REF2, A.DRCT
FROM Table1 A JOIN
(select NAME, DRCT, COUNT(*)
from Table1
group by NAME, DRCT
HAVING COUNT(*) = 1) B ON A.NAME = B.NAME AND A.DRCT = B.DRCT;