Converting row values separated by comma with inner joins tables query - sql

I would like to convert row values separated by comma with inner joins tables query with other columns are also there.
My query is displaying like below records:
Name ID Services Type
xyz 1 s1 A
xyz 1 s2 A
xyz 1 s3 A
abc 2 s2 B
abc 2 s3 B
I'd like output like below:
Name, ID, Services, Type
xyz 1 s1,s2,s3 A
abc 2 s2,s3 B

Please use below code:
create table #name (name varchar(10), id int ,type varchar(10))
insert into #name values ('XYZ',1,'A')
insert into #name values ('abc',2,'B')
create table #services (id int ,[Services] varchar(10))
insert into #services (1,'s1')
insert into #services (1,'s1')
insert into #services (1,'s2')
insert into #services (1,'s3')
insert into #services (2,'s2')
insert into #services (2,'s3')
select Name, t.ID
, (select s1.[Services] +',' from #Services s1 where s1.id = s.id for xml path('')) AS services
,[TyPe]
from #name t
inner join #services s on s.id = t.id

create table #name ( name varchar(10), id int ,type varchar(10))
insert into #name values ('XYZ',1,'A') insert into #name values ('abc',2,'B')
create table #services ( id int ,[Services] varchar(10))
insert into #services values (1,'s1' )
insert into #services values (1,'s2' )
insert into #services values (1,'s3' )
insert into #services values (2,'s2' )
insert into #services values (2,'s3' )
select * from #name
select * from #services
select Name, t.ID ,
(select s1.[Services] +',' from #Services s1 where s1.id=t.id for xml
path('') ) AS sevices ,[TYPe] from #name t

Related

How to split String after CONCAT over the repetition of Row Number

I have 2 tables as shown:
I want to CONCAT the two tables by joining them and split them over the repetition of Row Number.
CREATE TABLE #portiontable (
PortionKey NVARCHAR(100),
RN INT,
)
CREATE TABLE #finaltable (
Value NVARCHAR(100),
RN INT,
)
INSERT INTO #finaltable (Value,RN)
VALUES ('KRM__21X0E',1),
('C',2),
('',3),
('',4),
('KRM__21X0E',1),
('C',2),
('',3),
('',4)
INSERT INTO #portiontable (PortionKey,RN)
VALUES ('100',1),
('0AD',2),
('D',3)
SELECT * FROM #finaltable f
SELECT * FROM #portiontable p
SELECT (SELECT ''+ ValuePortionKey
FROM (
SELECT f.RN,f.value,P.PortionKey, f.value + P.PortionKey AS ValuePortionKey
FROM #portiontable p
INNER JOIN #finaltable f ON p.rn = f.rn
) ft
FOR XML PATH('')) as PartSignature
DROP TABLE #portiontable
DROP TABLE #finaltable
The desired output is 2 rows:
PartSignature
KRM__21X0E100C0ADD
KRM__21X0J100K0ADD
The actual output is:
PartSignature
KRM__21X0E100C0ADDKRM__21X0J100K0ADD
Firstly, it seems that you have 2 sets of data in the #finaltable. You need another column to identify it as a set. I have added a ValueSet in the #finaltable.
And, I think your sample data does not correspond to the expected output. I have amended the sample data for #finaltable
And finally, using STRING_AGG to perform the string concatenation, you can then GROUP BY the new ValueSet
CREATE TABLE #portiontable
(
PortionKey NVARCHAR(100),
RN INT,
)
CREATE TABLE #finaltable
(
ValueSet INT,
Value NVARCHAR(100),
RN INT,
)
INSERT INTO #portiontable (PortionKey,RN)
VALUES ('100',1),
('0AD',2),
('D',3)
INSERT INTO #finaltable (ValueSet,Value,RN)
VALUES (1,'KRM__21X0E',1),
(1,'C',2),
(1,'',3),
(1,'',4),
(2,'KRM__21X0J',1),
(2,'K',2),
(2,'',3),
(2,'',4)
SELECT f.ValueSet,
STRING_AGG (f.Value + p.PortionKey, '') AS ValuePortionKey
FROM #portiontable p
INNER JOIN #finaltable f ON p.RN = f.RN
GROUP BY f.ValueSet
DROP TABLE #portiontable
DROP TABLE #finaltable
-- Result
1 KRM__21X0E100C0ADD
2 KRM__21X0J100K0ADD

SQL server : Replace the value using like operator

I need to replace the column value if exists to another column have a same text as like below example.
create table #t1
(
a varchar(100)
)
create table #t2
(
b varchar(100),
c varchar(100)
)
insert into #t1 values('she is a girl teacher and he is a boy doctor')
insert into #t2 values('girl','G')
insert into #t2 values('boy','B')
select *from #t1
select *from #t2
select a=replace (t1.a,t2.b,t2.c)
from #t1 t1 inner join #t2 t2 on t1.a like '%'+t2.b+'%'
while i'm selecting the query the result displays like
she is a G teacher and he is a boy doctor
she is a girl teacher and he is a B doctor
but i have need the output like
she is a G teacher and he is a B doctor
How need to change my query for the above output.
The only solution I can think if using recursive queries.
create table #t1
(
a varchar(100)
)
create table #t2
(
b varchar(100),
c varchar(100)
)
insert into #t1 values('she is a girl teacher and he is a boy doctor')
, ('she is a girl soldier and he is a boy doctor')
, ('she is a girl dentist and he is a boy farmer')
insert into #t2 values('girl','G')
insert into #t2 values('boy','B')
select *from #t1
select *from #t2
select a=replace(t1.a,t2.b,t2.c), *
from #t1 t1
inner join #t2 t2 on t1.a like '%'+t2.b+'%';
with cte as (
select a, 1 as ct from #t1
union all
select cast(replace(a,t2.b,t2.c) as varchar(100)) as a, ct+1 from cte
cross apply #t2 t2 where a like '%'+t2.b+'%'
)select distinct a from (select a, ct as ct from cte) as t1 where t1.ct = (select max(ct) from cte);
drop table #t1
drop table #t2
-- she is a G teacher and he is a B doctor
The most straightforward way is to just use a cursor to loop through all the replacements, applying them.
create table #t1
(
a varchar(100)
)
create table #t2
(
b varchar(100),
c varchar(100)
)
insert into #t1 values('she is a girl teacher and he is a boy doctor')
insert into #t2 values('girl','G')
insert into #t2 values('boy','B')
-- We create a couple of variables and a temporal table to hold the incremental replacements
declare #Pattern varchar(64)
declare #Value varchar(64)
select * into #TempReplacements from #1
-- Apply the replacements
declare Replacements cursor for select b, c from #t2
open Replacements
fetch next from Replacements into #Pattern, #Value
while ##fetch_status = 0
update #TempReplacements set a = replace(a, #Pattern, #Value)
fetch next from Replacements into #Pattern, #Value
end
close Replacements
deallocate Replacements
-- We return the results
select * from #TempRelacements
-- Drop temporary Table
drop table #TempReplacements
drop table #t1
drop table #t2

Concatenate values in sql server and group by another value | ms sql server

I have simple select
select distinct UserName, Company from Users inner join Companies on Users.UserName = Companies.UserFullName
The result of query looks like this:
User1 | Company1
User1 | Company2
User1 | Company3
User1 | Company4
User2 | Company3
User2 | Company6
User2 | Company1
User2 | Company5
I want to concatenate Company values and group it by User. Like this:
User1 | Company1 , Company2 , Company3 , Company4
User2 | Company3 , Company6 , Company1 , Company5
Is it possible thing to do in sql server?
If you are using SQL Server 2017, you can use the new function, STRING_AGG:
SELECT UserName,
STRING_AGG(Company,' , ') WITHIN GROUP (ORDER BY Company) AS Companies
FROM #T1
GROUP BY Username;
Note that you have no ordering in your table, thus the order of 'Company3, Company6, Company1, Company5' cannot be retained for 'User2' unless you have some other column to order by.
The below code snippet would work for you -
CREATE TABLE #t1 (UserName VARCHAR(100), Company VARCHAR(100));
INSERT #t1 values ('User1','Company1');
INSERT #t1 values ('User1','Company2');
INSERT #t1 values ('User1','Company3');
INSERT #t1 values ('User1','Company4');
INSERT #t1 values ('User2','Company3');
INSERT #t1 values ('User2','Company6');
INSERT #t1 values ('User2','Company1');
INSERT #t1 values ('User2','Company5');
GO
select
UserName,
stuff((
select ',' + t.[Company]
from #t1 t
where t.UserName = #t1.UserName
order by t.[Company]
for xml path('')
),1,1,'') as CompanyName
from #t1
group by UserName;
Another solution that doesn't require the clause FOR XML PATH
This solution is a loop based
SET NOCOUNT ON
IF OBJECT_ID ('tempdb..#t1') IS NOT NULL DROP TABLE #T1;
IF OBJECT_ID ('tempdb..#t2') IS NOT NULL DROP TABLE #T2;
CREATE TABLE #t1 (UserName VARCHAR(100), Company VARCHAR(100));
INSERT #t1 values ('User1','Company1');
INSERT #t1 values ('User1','Company2');
INSERT #t1 values ('User1','Company3');
INSERT #t1 values ('User1','Company4');
INSERT #t1 values ('User2','Company3');
INSERT #t1 values ('User2','Company6');
INSERT #t1 values ('User2','Company1');
INSERT #t1 values ('User2','Company5');
GO
DECLARE #Table TABLE (UserName VARCHAR(100), Combined VARCHAR(4000))
DECLARE #i INT = 1
SELECT DENSE_RANK () OVER (ORDER BY UserName) Seq, *
INTO #T2
FROM #t1
WHILE #i <= (SELECT MAX(Seq) FROM #T2)
BEGIN
DECLARE #ConcatedCompany VARCHAR(4000) = ''
SELECT #ConcatedCompany+= ',' + Company
FROM #T2
WHERE Seq = #i
INSERT INTO #Table (UserName , Combined)
SELECT UserName , STUFF(#ConcatedCompany,1,1,'')
FROM #T2
WHERE Seq = #i
GROUP BY UserName
SET #i +=1
END
SELECT *
FROM #Table
UPDATE!!
Larnu's comment regarding the performance is a good point, usually I'd avoid using WHILE loops and think in terms of set based operations
so, here is the solution without a loop and without "FOR XML PATH"
SET NOCOUNT ON
IF OBJECT_ID ('tempdb..#t1') IS NOT NULL DROP TABLE #T1
IF OBJECT_ID ('tempdb..##T2') IS NOT NULL DROP TABLE ##T2
IF OBJECT_ID ('tempdb..##Table') IS NOT NULL DROP TABLE ##Table
CREATE TABLE #t1 (UserName VARCHAR(100), Company VARCHAR(100));
INSERT #t1 values ('User1','Company1');
INSERT #t1 values ('User1','Company2');
INSERT #t1 values ('User1','Company3');
INSERT #t1 values ('User1','Company4');
INSERT #t1 values ('User2','Company3');
INSERT #t1 values ('User2','Company6');
INSERT #t1 values ('User2','Company1');
INSERT #t1 values ('User2','Company5');
GO
CREATE TABLE ##Table (UserName nvarchar(50), Combined nvarchar(4000))
SELECT DENSE_RANK () OVER (ORDER BY UserName) Seq, *
INTO ##T2
FROM #t1
DECLARE #cmd NVARCHAR(MAX) =''
;WITH T2 (Seq) AS
(
SELECT DISTINCT Seq
FROM ##T2
)
SELECT #cmd += 'DECLARE #ConcatedCompany'+CONVERT(VARCHAR(10),Seq)+' NVARCHAR(4000) = ''''
SELECT #ConcatedCompany'+CONVERT(VARCHAR(10),Seq)+' += '','' + Company FROM ##T2 WHERE Seq = '+CONVERT(VARCHAR(10),Seq)+ CHAR(10)+
' INSERT INTO ##Table (UserName, Combined)
SELECT UserName , STUFF(#ConcatedCompany'+CONVERT(VARCHAR(10),Seq)+',1,1,'''')
FROM ##T2 WHERE Seq = '+CONVERT(VARCHAR(10),Seq) + CHAR(10)+
' GROUP BY UserName '+CHAR(10)+
';'
+CHAR(10)
FROM T2
EXEC sp_executesql #Cmd
SELECT UserName , Combined
FROM ##Table
DROP TABLE ##Table
DROP TABLE ##T2

Custom query assistance needed

I have 3 tables: (simplified for this question)
REQUIREMENTS : ID (PK), RequirementDescription
CUSTOMERS : ID (PK), CustomerName
CUSTOMER_REQUIREMENTS (join table): ID (PK), RequirementID (FK to REQUIREMENTS table), CustomerID (FK to CUSTOMERS table), DateCompleted
Question: I need to make a gridview in asp.net that basically shows the requirements on the left, all the customers as column headings and the DateCompleted as the "intersection". How can I do this?
For example:
Try following sql and replace temp tables with your table:
CREATE TABLE #REQUIREMENTS
(
ID INT,
RequirementDescription VARCHAR(100)
)
CREATE TABLE #CUSTOMERS
(
ID INT,
CustomerName VARCHAR(100)
)
CREATE TABLE #CUSTOMER_REQUIREMENTS
(
ID INT,
RequirementID INT,
CustomerID INT,
DateCompleted DATE
)
INSERT INTO #REQUIREMENTS VALUES (1,'Requirement1')
INSERT INTO #REQUIREMENTS VALUES (2,'Requirement2')
INSERT INTO #REQUIREMENTS VALUES (3,'Requirement3')
INSERT INTO #REQUIREMENTS VALUES (4,'Requirement4')
INSERT INTO #CUSTOMERS VALUES (1,'JOHN')
INSERT INTO #CUSTOMERS VALUES (2,'MARY')
INSERT INTO #CUSTOMERS VALUES (3,'BOB')
INSERT INTO #CUSTOMER_REQUIREMENTS VALUES (1,1,1,'2-2-2014')
INSERT INTO #CUSTOMER_REQUIREMENTS VALUES (1,2,1,'2-2-2014')
INSERT INTO #CUSTOMER_REQUIREMENTS VALUES (1,1,2,'2-2-2014')
INSERT INTO #CUSTOMER_REQUIREMENTS VALUES (1,2,2,'2-2-2014')
INSERT INTO #CUSTOMER_REQUIREMENTS VALUES (1,3,2,'2-2-2014')
INSERT INTO #CUSTOMER_REQUIREMENTS VALUES (1,4,2,'2-2-2014')
DECLARE #DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE #ColumnName AS NVARCHAR(MAX)
SELECT #ColumnName= ISNULL(#ColumnName + ',','') + QUOTENAME(CustomerName) FROM (SELECT DISTINCT CustomerName FROM #CUSTOMERS) AS Courses
SET #DynamicPivotQuery =
N'SELECT ReqID, ReqDes, ' + #ColumnName + '
FROM
(
SELECT
TEMP.ReqID,
TEMP.ReqDes,
TEMP.CusName,
CusReq.DateCompleted
FROM
(
SELECT
req.ID as ReqID,
req.RequirementDescription as ReqDes,
cus.ID as CusID,
cus.CustomerName as CusName
FROM
#REQUIREMENTS req,#CUSTOMERS cus
) AS TEMP
LEFT JOIN
#CUSTOMER_REQUIREMENTS as CusReq
ON
TEMP.ReqID = CusReq.RequirementID AND
Temp.CusID = CusReq.CustomerID
) AS TEMP1
PIVOT(MAX(TEMP1.DateCompleted)
FOR CusName IN (' + #ColumnName + ')) AS PVTTable'
EXEC sp_executesql #DynamicPivotQuery
DROP TABLE #CUSTOMER_REQUIREMENTS
DROP TABLE #CUSTOMERS
DROP TABLE #REQUIREMENTS

SQL select -one to many joins want to have the manys

I have two tables, TBL_PARENT (parentID, ParentName) and TBL_CHILDREN (ParentID,Child_Name)
A Parent can have 0 to many children
What I want is a query to give me a list of parent and their children in single row per parent.
For example
Parent1 John,Mary
Parent2 jane,steve,jana
And the number of rows to be the total number of parents
try this query :
I have created 3 table 2 of them are already created on your database #parant, #ch
and the third one is a temp table to put the result in.
create table #parant (id int , name varchar(10))
create table #ch (id int , name varchar(10), pid int)
insert into #parant select 1,'PA'
insert into #parant select 2,'PB'
insert into #parant select 3,'PC'
insert into #ch select 1,'Ca',1
insert into #ch select 1,'Cb',1
insert into #ch select 1,'Cc',1
insert into #ch select 1,'Cd',3
insert into #ch select 1,'Cf',3
insert into #ch select 1,'Ch',1
create table #testTable (id int, name varchar(10),chid int, chname varchar(10), cpid int)
insert into #testTable
select x.id , x.name ,isnull( y.id ,0), isnull(y.name,'') ,isnull(y.pid ,0)
from #parant as x
left outer join #ch as y
on x .id = y .pid
SELECT t.ID, t.name , STUFF(
(SELECT ',' + s.chname
FROM #TestTable s
WHERE s.ID = t.ID
FOR XML PATH('')),1,1,'') AS CSV
FROM #TestTable AS t
GROUP BY t.ID, t.name
GO
drop table #testTable
drop table #ch
drop table #parant
for the above data i got the following result
1 PA Ca,Cb,Cc,Ch
2 PB
3 PC Cd,Cf
SELECT COUNT(P.parentID),
P.ParentName,
C.Child_Name
FROM TBL_PARENT as P
INNER JOIN TBL_CHILDREN as C
WHERE P.parentID == c.ParentID
GROUP BY P.ParentName;
The line P.parentID == c.ParentID is doing the Join, and the line count(P.parentID) is doing the count of all the parents and the line GROUP BY P.ParentName is grouping all the rows by the name of the parent so you can display all the children of every single parent.