How to get the values in comma separated using joins? - sql-server

I am working on SQL, I have two tables
EId Ename
1 john
2 alex
3 piers
4 sara
And the second table is
PID PNAME EID
1 mcndd 1
2 carter 1
3 leare 2
4 jain 2
The result should be
EID count PID
1 2 1
1 2 2
2 2 3
2 2 4
I want a query for this.i had tried like this
SELECT t1.EID, COUNT(t1.EID) count,PID
from Employertable t1
INNER JOIN persontable P ON P.EID=t1.EID
Group By t1.EID Having Count(T1.EID) > 1

You can do this using window functions. With those functions you can combine aggregated data with non-aggregated data:
DECLARE #t1 TABLE ( EID INT )
DECLARE #t2 TABLE ( PID INT, EID INT )
INSERT INTO #t1
VALUES ( 1 ),
( 2 ),
( 3 ),
( 4 )
INSERT INTO #t2
VALUES ( 1, 1 ),
( 2, 1 ),
( 3, 2 ),
( 4, 2 )
SELECT *
FROM ( SELECT t1.EID ,
COUNT(*) OVER ( PARTITION BY t2.EID ) AS C ,
t2.PID
FROM #t1 t1
JOIN #t2 t2 ON t2.EID = t1.EID
) t
WHERE t.C > 1
Output:
EID C PID
1 2 1
1 2 2
2 2 3
2 2 4

Related

How to convert multiple column values into rows in hive?

Input:
ID COLUMN1 COLUMN2 COLUMN3
1 M,S,E,T 1,2,3,4 5,6,7
2 A,B,C 6,5,8,7,9,1 2,4,3,0,1
Output:
ID COLUMN1 COLUMN2 COLUMN3
1 M 10 50
1 S 20 60
1 E 30 70
1 T 40 NULL
2 A 6 2
2 B 5 4
2 C 8 3
2 NULL 7 0
2 NULL 9 1
2 NULL 1 NULL
Code:
select ID,
array_index( COLUMN1_arr, n ) as COLUMN1,
array_index( COLUMN2_arr, n ) as COLUMN2
from sample
lateral view numeric_range(size(COLUMN1_arr)) n1 as n;
Error:
FAILED: Semantic Exception [Error 10011]: Invalid function array_index
Here I'm having a multiple values in single column i need to convert it to rows as mentioned Output.
Explode Is an UDTF provided in hive you can use the same to split data from columns into rows.
SELECT ID1, col1,col2,col3
FROM tableName
lateral view explode(split(COLUMN1,',')) cols1 AS col1
lateral view explode(split(COLUMN2,',')) cols2 AS col2
lateral view explode(split(COLUMN3,',')) cols3 AS col3
Plain vanilla hive solution, without brickhouse UDFs.
Demo:
with
input as ( ---------------Input dataset
select stack(2,
1, array('M','S','E','T'), array(1,2,3,4), array(5,6,7),
2, array('A','B','C'), array(6,5,8,7,9,1), array( 2,4,3,0,1)
) as (ID,COLUMN1,COLUMN2,COLUMN3)
),
--explode each array and FULL join them
c1 as (
select i.id, v.column1, p
from input i
lateral view posexplode(i.COLUMN1) v as p,column1
),
c2 as (
select i.id, v.column2, p
from input i
lateral view posexplode(i.COLUMN2) v as p,column2
),
c3 as (
select i.id, v.column3, p
from input i
lateral view posexplode(i.COLUMN3) v as p,column3
)
--FULL JOIN
select coalesce(c1.id,c2.id,c3.id) id, c1.column1, c2.column2, c3.column3
from c1
full join c2 on c1.id=c2.id and c1.p=c2.p
full join c3 on nvl(c1.id,c2.id)=c3.id and nvl(c1.p,c2.p)=c3.p --note NVL usage
;
Result:
OK
id column1 column2 column3
1 M 1 5
1 S 2 6
1 E 3 7
1 T 4 NULL
2 A 6 2
2 B 5 4
2 C 8 3
2 NULL 7 0
2 NULL 9 1
2 NULL 1 NULL

How to sum a column in SQL Server recursive cte for optimization?

I have following table with hierarchical data:
FolderId ParentFolderId NumberOfAffectedItems
---------------------------------------------
1 NULL 2
2 1 3
3 2 5
4 2 3
5 1 0
I want to find number of affected items under each folders and all of its children. I can write a recursive cte, which can produce following result, after that by doing group by I can find out what I want.
Normal recursive CTE:
WITH FolderTree AS
(
SELECT
fsa.FolderId AS ParentFolderId,
fsa.FolderId AS ChildFolderId,
fsa.NumberOfReportsAffected
FROM
FoldersWithNumberOfReportsAffected fsa
UNION ALL
SELECT
ft.ParentFolderId,
fsa.FolderId AS ChildFolderId,
fsa.NumberOfReportsAffected
FROM
FoldersWithNumberOfReportsAffected fsa
INNER JOIN
FolderTree ft ON fsa.ParentFolderId = ft.ChildFolderId
)
Result:
ParentFolderId ChildFolderId NumberOfAffectedItems
--------------------------------------------------
1 1 2
1 2 3
1 3 5
1 4 3
1 5 0
2 2 3
2 3 5
2 4 3
3 3 5
4 4 3
5 5 0
But I want to optimize it, I want to start from the leaf child, while
moving through the CTE itself, I want to compute NumberOfAffectedItems.
Expected CTE
WITH FolderTree AS
(
SELECT
fsa.FolderId AS LeafChildId,
fsa.FolderId AS ParentFolderId,
fsa.NumberOfReportsAffected
FROM
FoldersWithNumberOfReportsAffected fsa
LEFT JOIN
FoldersWithNumberOfReportsAffected f ON fsa.folderid = f.ParentfolderId
WHERE
f.ParentfolderId is null -- this is finding leaf child
UNION ALL
SELECT
ft.LeafChildId,
fsa.FolderId AS ParentFolderId,
fsa.NumberOfReportsAffected + ft.NumberOfReportsAffected AS [ComputedResult]
FROM
FoldersWithNumberOfReportsAffected fsa
INNER JOIN
FolderTree ft ON fsa.FolderId = ft.ParentFolderId
)
Result:
LeafChildId ParentFolderId ComputedNumberOfAffectedItems
---------------------------------------------------------
3 3 5
3 2 8
3 1 10
4 4 3
4 2 5
4 1 7
5 5 0
5 1 2
If I group by ParentFolderId, I will get a wrong result, the reason is while doing computing in CTE, the same parent folder is visited from multiple
children, hence results in a wrong result. I want to find out is there anyway we can compute the result while going through the CTE itself.
Please check the following solution. I used your cte as basis and added the calculation (as column x) to it:
DECLARE #t TABLE(
FolderID INT
,ParentFolderID INT
,NumberOfAffectedItems INT
);
INSERT INTO #t VALUES (1 ,NULL ,2)
,(2 ,1 ,3)
,(3 ,2 ,5)
,(4 ,2 ,3)
,(5 ,1 ,0);
WITH FolderTree AS
(
SELECT 1lvl,
fsa.FolderId AS LeafChildId,
fsa.ParentFolderId AS ParentFolderId,
fsa.NumberOfAffectedItems
FROM
#t fsa
LEFT JOIN
#t f ON fsa.folderid = f.ParentfolderId
WHERE
f.ParentfolderId is null -- this is finding leaf child
UNION ALL
SELECT lvl + 1,
ft.LeafChildId,
fsa.ParentFolderId,
fsa.NumberOfAffectedItems
FROM
FolderTree ft
INNER JOIN #t fsa
ON fsa.FolderId = ft.ParentFolderId
)
SELECT LeafChildId,
ISNULL(ParentFolderId, LeafChildId) ParentFolderId,
NumberOfAffectedItems,
SUM(NumberOfAffectedItems) OVER (PARTITION BY LeafChildId ORDER BY ISNULL(ParentFolderId, LeafChildId) DESC) AS x
FROM FolderTree
ORDER BY 1, 2 DESC
OPTION (MAXRECURSION 0)
Result:
LeafChildId ParentFolderId NumberOfAffectedItems x
3 3 2 2
3 2 5 7
3 1 3 10
4 4 2 2
4 2 3 5
4 1 3 8
5 5 2 2
5 1 0 2

Performance issue with CTE SQL Server query

We have a table with a parent child relationship, that represents a deep tree structure.
We are using a view with a CTE to query the data but the performance is poor (see code and execution plan below).
Is there any way we can improve the performance?
WITH cte (ParentJobTypeId, Id) AS
(
SELECT
Id, Id
FROM
dbo.JobTypes
UNION ALL
SELECT
e.Id, cte.Id
FROM
cte
INNER JOIN
dbo.JobTypes AS e ON e.ParentJobTypeId = cte.ParentJobTypeId
)
SELECT
ISNULL(Id, 0) AS ParentJobTypeId,
ISNULL(ParentJobTypeId, 0) AS Id
FROM
cte
A quick example of using the range keys. As I mentioned before, hierarchies were 127K points and some sections where 15 levels deep
The cte Builds, let's assume the hier results will be will be stored in a table (indexed as well)
Declare #Table table(ID int,ParentID int,[Status] varchar(50))
Insert #Table values
(1,101,'Pending'),
(2,101,'Complete'),
(3,101,'Complete'),
(4,102,'Complete'),
(101,null,null),
(102,null,null)
;With cteOH (ID,ParentID,Lvl,Seq)
as (
Select ID,ParentID,Lvl=1,cast(Format(ID,'000000') + '/' as varchar(500)) from #Table where ParentID is null
Union All
Select h.ID,h.ParentID,cteOH.Lvl+1,Seq=cast(cteOH.Seq + Format(h.ID,'000000') + '/' as varchar(500)) From #Table h INNER JOIN cteOH ON h.ParentID = cteOH.ID
),
cteR1 as (Select ID,Seq,R1=Row_Number() over (Order by Seq) From cteOH),
cteR2 as (Select A.ID,R2 = max(B.R1) From cteOH A Join cteR1 B on (B.Seq Like A.Seq+'%') Group By A.ID)
Select B.R1
,C.R2
,A.Lvl
,A.ID
,A.ParentID
Into #TempHier
From cteOH A
Join cteR1 B on (A.ID=B.ID)
Join cteR2 C on (A.ID=C.ID)
Select * from #TempHier
Select H.R1
,H.R2
,H.Lvl
,H.ID
,H.ParentID
,Total = count(*)
,Complete = sum(case when D.Status = 'Complete' then 1 else 0 end)
,Pending = sum(case when D.Status = 'Pending' then 1 else 0 end)
,PctCmpl = format(sum(case when D.Status = 'Complete' then 1.0 else 0.0 end)/count(*),'##0.00%')
From #TempHier H
Join (Select _R1=B.R1,A.* From #Table A Join #TempHier B on A.ID=B.ID) D on D._R1 between H.R1 and H.R2
Group By H.R1
,H.R2
,H.Lvl
,H.ID
,H.ParentID
Order By 1
Returns the hier in a #Temp table for now. Notice the R1 and R2, I call these the range keys. Data (without recursion) can be selected and aggregated via these keys
R1 R2 Lvl ID ParentID
1 4 1 101 NULL
2 2 2 1 101
3 3 2 2 101
4 4 2 3 101
5 6 1 102 NULL
6 6 2 4 102
VERY SIMPLE EXAMPLE: Illustrates the rolling the data up the hier.
R1 R2 Lvl ID ParentID Total Complete Pending PctCmpl
1 4 1 101 NULL 4 2 1 50.00%
2 2 2 1 101 1 0 1 0.00%
3 3 2 2 101 1 1 0 100.00%
4 4 2 3 101 1 1 0 100.00%
5 6 1 102 NULL 2 1 0 50.00%
6 6 2 4 102 1 1 0 100.00%
The real beauty of the the range keys, is if you know an ID, you know where it exists (all descendants and ancestors).

SQL Query Conversation

I have three tables:
__Person__ __Hat__ __Shoe__
ID int ID int ID int
Name nvarchar Name nvarchar Name nvarchar
HatID int
ShoeID int
Here's some sample data of the tables:
________________Person_________________
-ID- -Name- -HatID- -ShoeID-
1 Anna 1 2
2 Nina 2 3
3 Lola 3 NULL
______Hat_______
-ID- -Name-
1 Blue
2 Red
3 Green
______Shoe_______
-ID- -Name-
1 Boot
2 Heels
3 Sport
I have a query like this:
SELECT Person.ID, Person.Name, Hat.Name, Shoe.Name
FROM Person
INNER JOIN Hat ON Person.HatID = Hat.ID
JOIN JOIN Shoe ON Person.Shoe = Shoe.ID
This query returns the following results:
-PersonID- -PersonName- -HatName- -ShoeName-
1 Anna Blue Heels
2 Nina Red Sport
3 Lola Green NULL
I want to give PersonName, HatName and ShoeName order numbers 1, 2, 3. I need results like this:
-PersonID- -OrderNumber- -Value-
1 1 Anna
1 2 Blue
1 3 Heels
2 1 Nina
2 2 Red
2 3 Sport
3 1 Lola
3 2 Green
3 3 NULL
How should I write the query to return this results?
You can use UNPIVOT here:
DECLARE #Persons TABLE
(
ID INT ,
Name NVARCHAR(20) ,
HatID INT ,
ShoeID INT
)
DECLARE #Hats TABLE ( ID INT, Name NVARCHAR(20) )
DECLARE #Shoes TABLE ( ID INT, Name NVARCHAR(20) )
INSERT INTO #Persons
VALUES ( 1, 'Anna', 1, 2 ),
( 2, 'Nina', 2, 3 ),
( 3, 'Lola', 3, NULL )
INSERT INTO #Hats
VALUES ( 1, 'Blue' ),
( 2, 'Red' ),
( 3, 'Green' )
INSERT INTO #Shoes
VALUES ( 1, 'Boot' ),
( 2, 'Heels' ),
( 3, 'Sport' );
WITH cte
AS ( SELECT p.ID ,
p.Name AS PersonName ,
h.Name AS HatName ,
ISNULL(s.Name, '') AS ShoeName
FROM #Persons p
INNER JOIN #Hats h ON p.HatID = h.ID
LEFT JOIN #Shoes s ON p.ShoeID = s.ID
)
SELECT ID AS PersonID ,
ROW_NUMBER() OVER ( PARTITION BY ID ORDER BY ( SELECT
1
) ) AS OrderNumber ,
IIF(Value = '', NULL, Value) AS Value
FROM cte UNPIVOT( Value FOR v IN ( [PersonName], [HatName], [ShoeName] ) ) u;
Output:
PersonID OrderNumber Value
1 1 Anna
1 2 Blue
1 3 Heels
2 1 Nina
2 2 Red
2 3 Sport
3 1 Lola
3 2 Green
3 3 NULL
try this:
SELECT Person.ID, 1 OrderNumber, Person.Name
FROM Person
UNION ALL
SELECT Person.ID, 2 OrderNumber, Hat.Name
FROM Person
LEFT JOIN JOIN Hat ON Person.HatID = Hat.ID
UNION ALL
SELECT Person.ID, 3 OrderNumber, Shoe.Name
FROM Person
LEFT JOIN JOIN Shoe ON Person.ShoeID = Shoe.ID
ORDER BY 1,2

count detail record and display in new column in sql server

i am using sql server 2008, in which i have some trouble i can not find one column
TblMaster
ID Name City
1 Hiren Juanagadh
2 Ashish Gandhinagar
2 Mayur Ahmedabad
3 Hitesh Junagadh
4 Nipun Ahmedabad
4 Vivek Rajkot
4 Samir Surat
5 Sagar Vadodara
Now i want Anoter column CountId so i want output like below
TblMaster
ID Name City CountId
1 Hiren Juanagadh 0
2 Ashish Gandhinagar 2
2 Mayur Ahmedabad 2
3 Hitesh Junagadh 0
4 Nipun Ahmedabad 3
4 Vivek Rajkot 3
4 Samir Surat 3
5 Sagar Vadodara 0
Means if Id column only one then CountId = 0
If Id column more than one then CountId = Count of Idcolumn
Prepare table
declare #T table (
id int,
Name nvarchar(6),
City nvarchar(20))
insert #T values
( 1 , 'Hiren', 'Juanagadh'),
( 2 , 'Ashish', 'Gandhinagar'),
( 2 , 'Mayur', 'Ahmedabad'),
( 3 , 'Hitesh', 'Junagadh'),
( 4 , 'Nipun', 'Ahmedabad'),
( 4 , 'Vivek', 'Rajkot'),
( 4 , 'Samir', 'Surat'),
( 5 , 'Sagar', 'Vadodara')
Select statement
without 1->0 correction
SELECT *, CountID = count(*) over (Partition by ID)
from #T
with 1->0 correction
select id, Name,City,CountID = case when CountID = 1 then 0 else CountID end
from (
SELECT *, CountID = count(*) over (Partition by ID)
from #T )
RES
Try this query:::
select *,(case when (select count(id) from TblMaster )=1
then 0 else (select count(id) from TblMaster) end) as count
from tblmaster

Resources