Transforming and repeating multiple rows - sql-server

I have a table that has two IDs within it named FamilyID and PersonID. I need to be able to repeat these rows with all combinations, as the below screenshot shows noting that each of the numbers get an extra row.
Here is some SQL to create the table with some sample data. There is no set number of occurrences that could occur.
Anyone aware of how we could be achieved?
CREATE TABLE #TempStackOverflow
(
FamilyID int,
PersonID int
)
insert into #TempStackOverflow
(
FamilyID,
PersonID
)
select
1012,
1
union
select
1013,
1
union
select
1014,
1
union
select
1015,
2
union
select
14774,
3
union
select
1019,
5

I understand that you need some sort of a complete list of matches within groups, but honestly, it would be much better if you would explain the business context, using plain English, in the first place.
The following query seems to produce your sample result:
with cte as (
select a.FamilyID, a.PersonID, a.PersonID as [GroupId] from #TempStackOverflow a
union all
select b.PersonID, b.FamilyID, b.PersonID from #TempStackOverflow b
)
select distinct c.FamilyID, s.PersonID
from cte c
inner join cte s on s.GroupId = c.GroupId
where c.FamilyID != s.PersonID;

Here is the simplest version I can come up with that groups the items by PersonId, as you do above. Obviously if you don't want that, then you can remove the outer query.
SELECT FamilyId,
PersonID
FROM (
SELECT FamilyId, PersonId, PersonID as SortBy
FROM #TempStackOverflow t1
UNION
SELECT PersonId, FamilyId, PersonId as SortBy
FROM #TempStackOverflow t1
UNION
SELECT t1.FamilyID, t2.FamilyID, t1.PersonID as SortBy
FROM #TempStackOverflow t1
FULL OUTER JOIN #TempStackOverflow t2
ON t1.PersonID = t2.PersonID
WHERE t1.FamilyID != t2.FamilyID
) as Src
ORDER BY SortBy

Related

sql server using recrusive cte to get the level in the same group

I have a sql server table showing the IDs and their previous IDs,
create table test2 ( ID varchar(10) ,
Pre_ID varchar(10)
)
insert into test2 values ('e','d')
, ('d','c')
, ('c','b')
, ('b','a')
, ('a',null)
, ('r','q')
, ('q','p')
, ('p',null)
the table is like this:
The result should be like this:
I have successfully got the levels using a recursive cte, but could not get the correct group for them. can anyone help? Thanks.
This is my code:
with cte as (
select id, Pre_ID, level
from #temp2
where Pre_ID is null
union all
select t2.id, t2.Pre_ID, t2.level
from cte
inner join #temp2 t2
on t2.Pre_ID=cte.id
)
select * from cte
order by id
What you need to do is start with the first level and add a ROW_NUMBER to that, then join all further levels recursively:
with cte as (
select id, Pre_ID, level, row_number() over (order by ID) as grp
from #temp2
where Pre_ID is null
union all
select t2.id, t2.Pre_ID, t2.level, cte.grp
from cte
inner join #temp2 t2
on t2.Pre_ID=cte.id
)
select * from cte
order by id;

Can't get my data sorted as needed in query results using SQL Server 2016

I have query that displays the results as follows:
However, I need the query results to be displayed as follows:
Here is my query code:
SELECT *
FROM #tempRecordsWithoutSUBJ
WHERE [Policy Number] = 'EAA1396891' --'EAA1380770'
GROUP BY [RN], [RTN], [AM Best Number], [Policy Number], [Line of Business (LOB)], [Transaction Effective Date], [Data Fields], [PolicySysID], [Record Type]
ORDER BY RN, [Record Type];
What I'm needing is to have the PROP and PRP1 records for each POLR record. There are 3 PROP and 3 corresponding PRP1 records and I need them sorted under each POLR record as displayed in the 2nd image. I added ROW_NUMBER to each section of the code to help but obviously I'm struggling. Any help/direction would be greatly appreciated.
From what you've provided, it looks like your requirement is to return all of the RTN=1 rows, each one with a full set of 2&3 rows under it, in order of RN,RTN.
If that's right, seems like one way to get this is with a UNION ALL that duplicates the 2&3 for each 1, then supplies an artificial column for ordering.
SELECT * , RTN AS Ord
FROM..WHERE..AND RTN=1
UNION ALL
SELECT t1.* , t2.RTN AS Ord
FROM myTable t1
CROSS JOIN myTable t2
WHERE..AND t1.RTN<>1 AND t2.RTN=1
ORDER BY Ord,RN,RTN
EDIT:
Ok, I see what I missed. We need to actually use RN AS Ord, and we also need to add one more artificial column to force the POLR records to the top of their grouping. So more like this:
SELECT *, RN AS Ord, 1 AS Ord2
FROM myTable
WHERE..AND RTN=1
UNION ALL
SELECT t1.* , t2.RN AS Ord, 2 AS Ord2
FROM myTable t1
CROSS JOIN myTable t2
WHERE..AND t1.RTN<>1 AND t2.RTN=1
ORDER BY Ord,Ord2,RN,RTN
I tested this and it works:
CREATE TABLE #tmp (
L1 char(1)
, I1 int
, I2 int
);
INSERT INTO #tmp
VALUES
('a',1,1)
, ('a',1,2)
, ('c',2,1)
, ('d',3,1)
, ('c',2,2)
, ('d',3,2)
;
SELECT *, I2 AS Ord, 1 AS Ord2
FROM #tmp
WHERE I1=1
UNION ALL
SELECT t1.*, t2.I2 AS Ord, 2 AS Ord2
FROM #tmp t1
CROSS JOIN #tmp t2
WHERE t1.I1<>1 AND t2.I1=1
ORDER BY Ord, Ord2, I2, I1
;
DROP TABLE #tmp;

SQL Server Group By - Aggregate NULL or empty values into all other values

I am trying to group by a column. The problem is that the NULL values of the column are grouped as a separate group.
I want the NULL values to be added to each of the other group values instead.
Example of a table:
The results I want to get from group by with sum aggregation over the 'val' column:
Can anyone help me?
Thanks!
You can precalculate the value to spread through the rows and then just do arithmetic:
select t.id,
sum(t.val) + (null_sum / cnt_id)
from t cross join
(select count(distinct id) as cnt_id,
sum(case when id is null then val else 0 end) as null_sum
from t
) tt
group by t.id;
Note some databases do integer division, so you might need null_sum * 1.0 / cnt_id.
A GROUP BY operation can't really generate values for each group on the fly, so logically you need records which are missing to really be present.
One approach is to use a calendar table to generate a table containing one NULL record for each id group:
WITH ids AS (
SELECT DISTINCT id FROM yourTable
WHERE id IS NOT NULL
),
cte AS (
SELECT t1.id, t2.val
FROM ids t1
CROSS JOIN yourTable t2
WHERE t2.id IS NULL
)
SELECT t.id, SUM(t.val) AS val
FROM
(
SELECT id, val FROM yourTable WHERE id IS NOT NULL
UNION ALL
SELECT id, val FROM cte
) t
GROUP BY
id;
Demo

T-SQL Left join twice

Query below works as planned, it shows exactly the way i joined it, and that is fine, but problem with it, is that if you have more "specialization" tables for users, something like "Mail type" or anything that user can have more then one data ... you would have to go two left joins for each and "give priority" via ISNULL (in this case)
I am wondering, how could I avoid using two joins and "give" priority to TypeId 2 over TypeId 1 in a single join, is that even possible?
if object_id('tempdb..#Tab1') is not null drop table #Tab1
create table #Tab1 (UserId int, TypeId int)
if object_id('tempdb..#Tab2') is not null drop table #Tab2
create table #Tab2 (TypeId int, TypeDescription nvarchar(50))
insert into #Tab1 (UserId, TypeId)
values
(1, 1),
(1, 2)
insert into #Tab2 (TypeId, TypeDescription)
values
(1, 'User'),
(2, 'Admin')
select *, ISNULL(t2.TypeDescription, t3.TypeDescription) [Role]
from #Tab1 t1
LEFT JOIN #Tab2 t2 on t1.TypeId = t2.TypeId and
t2.TypeId = 2
LEFT JOIN #Tab2 t3 on t1.TypeId = t3.TypeId and
t3.TypeId = 1
The first problem is determining priority. In this case, you could use the largest TypeId, but that does not seem like a great idea. You could add another column to serve as a priority ordinal instead.
From there, it is a top 1 per group query:
using top with ties and row_number():
select top 1 with ties
t1.UserId, t1.TypeId, t2.TypeDescription
from #Tab1 t1
left join #Tab2 t2
on t1.TypeId = t2.TypeId
order by row_number() over (
partition by t1.UserId
order by t2.Ordinal
--order by t1.TypeId desc
)
using common table expression and row_number():
;with cte as (
select t1.UserId, t1.TypeId, t2.TypeDescription
, rn = row_number() over (
partition by t1.UserId
order by t2.Ordinal
--order by t1.TypeId desc
)
from #Tab1 t1
left join #Tab2 t2
on t1.TypeId = t2.TypeId
)
select UserId, TypeId, TypeDescription
from cte
where rn = 1
rextester demo for both: http://rextester.com/KQAV36173
both return:
+--------+--------+-----------------+
| UserId | TypeId | TypeDescription |
+--------+--------+-----------------+
| 1 | 2 | Admin |
+--------+--------+-----------------+
Actually I don't think you don't need a join at all. But you have to take the max TypeID without respect to the TypeDescription, since these differences can defeat a Group By. So a workaround is to take the Max without TypeDescription initially, then subquery the result to get the TypeDescription.
SELECT dT.*
,(SELECT TypeDescription FROM #Tab2 T2 WHERE T2.TypeId = dT.TypeId) [Role] --2. Subqueries TypeDescription using the Max TypeID
FROM (
select t1.UserId
,MAX(T1.TypeId) [TypeId]
--, T1.TypeDescription AS [Role] --1. differences will defeat group by. Subquery for value later in receiving query.
from #Tab1 t1
GROUP BY t1.UserId
) AS dT
Produces Output:
UserId TypeId Role
1 2 Admin

Why doesn't this union give me two columns?

I want two columns in the output of the join. I only get one, the storeID. The StoreComponentID is not there.
if you want two column you need to declare two columns
SELECT column1, NULL as column2 -- even when Table1 doesnt have column2
FROM Table1
UNION
SELECT NULL as column1, column2 -- even when Table2 doesnt have column1
FROM Table2
Now if you want some kind of merge side by side.
WITH idA as (
SELECT StoreComponentID,
ROW_NUMBER() OVER (ORDER BY StoreComponentID) as rn
FROM StoreComponent
), idB as (
SELECT StoreID
ROW_NUMBER() OVER (ORDER BY StoreID) as rn
FROM Store
)
SELECT idA.StoreComponentID,
idB.StoreID
FROM idA
FULL JOIN idB
ON idA.rn = idB.rn
I figured out a simple solution:
select S.storeid as sID, SC.storecomponentid as SCID from tstore as S, tstorecomponent as SC

Resources