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

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

Related

How to use pivot for columns of type varchar

My table is:
SBType|SBName|Qty
===================
SMDB SB01 1
SMDB SB01 4
SMDB SB02 2
SMDB SB02 5
SMDB SB03 3
SMDB SB03 6
My desired output is:
SB01 | SB02 | SB03
==================
1 2 3
4 5 6
This is what my code looks like:
SELECT *
FROM (
SELECT
SM.SBName,ISNULL(ES.Qty,0)Qty
FROM RE_ES_SwitchBoard_Mast SM
left outer join RE_ES_Estimations ES on SM.PrCode=ES.PrCode and
Sm.SBType=ES.SBType and SM.SBName=ES.SBName
Where SM.PrCode='PR004' and SM.SBType='SMDB'
) as s
PIVOT
(
Max(Qty)
FOR [SBName] IN (SB01, SB02, SB03)
)AS pvthere
and the result of my attempt looks like:
SB01 SB02 SB03
1 2 3
I have tried with MAX(Qty) but it is not working.
Thanks in advance.
You are almost there.
By adding ROW_NUMBER() OVER (PARTITION BY SBName ORDER BY Qty) rn to the source of PIVOT clause you get multiple rows for different SBName instead of one grouped row. Your query should look like:
SELECT SB01, SB02, SB03
FROM (
SELECT
ROW_NUMBER() OVER (PARTITION BY SB.SBName ORDER BY Qty) rn,
SB.SBName,ISNULL(ES.Qty,0) Qty
FROM RE_ES_SwitchBoard_Mast SM
left outer join RE_ES_Estimations ES on SM.PrCode=ES.PrCode and
Sm.SBType=ES.SBType and SM.SBName=ES.SBName
Where SM.PrCode='PR004' and SM.SBType='SMDB'
) as s
PIVOT
(
Max(Qty)
FOR [SBName] IN (SB01, SB02, SB03)
)AS pvthere
A verifiable example here:
CREATE TABLE #sample
(
SBType varchar(MAX),
SBName varchar(MAX),
Qty int
)
INSERT INTO #sample VALUES ('SMDB','SB01',1)
INSERT INTO #sample VALUES ('SMDB','SB01',4)
INSERT INTO #sample VALUES ('SMDB','SB02',2)
INSERT INTO #sample VALUES ('SMDB','SB02',5)
INSERT INTO #sample VALUES ('SMDB','SB03',3)
INSERT INTO #sample VALUES ('SMDB','SB03',6)
SELECT SB01, SB02, SB03
FROM (
SELECT
ROW_NUMBER() OVER (PARTITION BY SBName ORDER BY Qty) rn, SBName,ISNULL(Qty,0) Qty
FROM #sample
) as s
PIVOT
(
Max(Qty)
FOR [SBName] IN (SB01, SB02, SB03)
) AS pvthere
DROP TABLE #sample
Dynamic query is the only way to use varchar columns in pivot. Have a look at below code to get idea.
First step is to generate comma separated list of items for column you need to use in pivot.
Then you can use this generated list in dynamic query for pivot columns.
Note: For example purpose I have used temp table. Replace it with your actual table.
CREATE TABLE #temptable
(
SBType VARCHAR(20),
SBName VARCHAR(20),
Qty INT
)
INSERT INTO #temptable SELECT 'SMDB','SB01',1
INSERT INTO #temptable SELECT 'SMDB','SB01',4
INSERT INTO #temptable SELECT 'SMDB','SB02',2
INSERT INTO #temptable SELECT 'SMDB','SB02',5
INSERT INTO #temptable SELECT 'SMDB','SB03',3
INSERT INTO #temptable SELECT 'SMDB','SB03',6
SELECT * FROM #temptable
DECLARE #cols AS NVARCHAR(MAX)
SELECT #cols = STUFF((SELECT ',' + QUOTENAME(SBName)
from #temptable
group by SBName
order by SBName
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SELECT #cols
DECLARE #query NVARCHAR(MAX)
SET #query = '
SELECT *
FROM
(
SELECT SBType,SBName,Qty,
row_number() over (partition by SBName order by Qty) as rn
FROM #temptable
) src
PIVOT
(
MIN(Qty)
FOR SBName IN (' + #cols + ')
) piv;'
EXEC(#query)
DROP TABLE #temptable

Converting row values separated by comma with inner joins tables query

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

Showing data as a column name

I have three tables. I called them as Table A,Table B,Table C.
And I have desired view which I want to get.
Table A
Aid RegNum BID Value
2CE7D0A7 2000000 D5981DFC OFFCRO
9D3C13AA 2000000 C58566C5 YCH - from
9DDB90C4 2000000 812E9E75 Y
Table B is connected to Table A by Table B's foreign key in Table A
Table B
BID Label ColumnName Order
D5981DFC Offered/Change Role StatusChangeCode 0
C58566C5 Offered/Role Change Comments StatusChangeComments 1
812E9E75 Assessed StatusChangeAssessed 2
Table C has foreign key in Table A as well. Reg Num. Reg num is primary key in Table C
Table C
Name Surname RegNum
Etibar Hasanov 2000000
As you see there are column's names which are datas in Table B
DesiredView
Name Surname RegNum StatusChangeCode StatusChangeComments StatusChangeAssessed
Etibar Hasanov 2000000 OFFCRO YCH - from Y
You can achieve this by using PIVOT table. Try something like this,
Create Table TableA(Aid varchar(50), RegNum int, BID Varchar(20), Value varchar(50))
insert into TableA values
('2CE7D0A7', 2000000, 'D5981DFC', 'OFFCRO'),
('9D3C13AA', 2000000, 'C58566C5', 'YCH - from' ),
('9DDB90C4', 2000000, '812E9E75', 'Y')
create Table TableB(BID Varchar(20), Label Varchar(50), ColumnName
Varchar(50), [Order] int)
insert into TableB values
('D5981DFC', 'Offered/Change Role', 'StatusChangeCode', 0),
('C58566C5', 'Offered/Role Change Comments', 'StatusChangeComments', 1),
('812E9E75', 'Assessed', 'StatusChangeAssessed', 2)
Create Table TableC (Name Varchar(20), Surname Varchar(20), RegNum int)
insert into TableC values
('Etibar', 'Hasanov', 2000000)
SELECT *
FROM (
SELECT
Name, SurName, C.RegNum, Value, B.ColumnName
FROM TableC C
JOIN TableA A ON C.RegNum = A.RegNum
JOIN TableB B on B.BID = A.BID
) AS Source
PIVOT
(
MAX(Value)
FOR [ColumnName]
in ( [StatusChangeCode], [StatusChangeComments], [StatusChangeAssessed] )
)AS Pvot
Sql Fiddle Demo
If you are using SQL server 2005, according to Microsoft Technet,
When PIVOT and UNPIVOT are used against databases that are upgraded to
SQL Server 2005 or later, the compatibility level of the database must
be set to 90 or higher.
I first selected columns names. In this table it brings [StatusChangeAssessed],[StatusChangeCode],[StatusChangeComments] . Then in the next query I setted #col ( column names ).
declare #nregnumber nvarchar(10)='2000000';
DECLARE #cols AS NVARCHAR(MAX), #runningquery as nvarchar(max);
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(rn)
from
(
select columnname rn from tableb where exists ( select * from tablea where tablea.bid=tableb.bid and regnum=#nregnumber)
) t
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'');
set #runningquery='
SELECT *
FROM (
SELECT
Name, SurName, C.RegNum, Value, B.ColumnName
FROM TableC C
JOIN TableA A ON C.RegNum = A.RegNum
JOIN TableB B on B.BID = A.BID
) AS Source
PIVOT
(
MAX(Value)
FOR [ColumnName]
in ( '+#cols+')
)AS Pvot'
exec (#runningquery)
Special thanks to Selva.

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.

Delete duplicated rows and Update references

How do I Delete duplicated rows in one Table and update References in another table to the remaining row? The duplication only occurs in the name. The Id Columns are Identity columns.
Example:
Assume we have two tables Doubles and Data.
Doubles table (
Id int,
Name varchar(50)
)
Data Table (
Id int,
DoublesId int
)
Now I Have Two entries in the Doubls table:
Id Name
1 Foo
2 Foo
And two entries in the Data Table:
ID DoublesId
1 1
2 2
At the end there should be only one entry in the Doubles Table:
Id Name
1 Foo
And two entries in the Data Table:
Id DoublesId
1 1
2 1
In the doubles Table there can be any number of duplicated rows per name (up to 30) and also regular 'single' rows.
I've not run this, but hopefully it should be correct, and close enough to the final soln to get you there. Let me know any mistakes if you like and I'll update the answer.
--updates the data table to the min ids for each name
update Data
set id = final_id
from
Data
join
Doubles
on Doubles.id = Data.id
join
(
select
name
min(id) as final_id
from Doubles
group by name
) min_ids
on min_ids.name = Doubles.name
--deletes redundant ids from the Doubles table
delete
from Doubles
where id not in
(
select
min(id) as final_id
from Doubles
group by name
)
Note: I have taken the liberty to rename your Id's to DoubleID and DataID respectively. I find that eassier to work with.
DECLARE #Doubles TABLE (DoubleID INT, Name VARCHAR(50))
DECLARE #Data TABLE (DataID INT, DoubleID INT)
INSERT INTO #Doubles VALUES (1, 'Foo')
INSERT INTO #Doubles VALUES (2, 'Foo')
INSERT INTO #Doubles VALUES (3, 'Bar')
INSERT INTO #Doubles VALUES (4, 'Bar')
INSERT INTO #Data VALUES (1, 1)
INSERT INTO #Data VALUES (1, 2)
INSERT INTO #Data VALUES (1, 3)
INSERT INTO #Data VALUES (1, 4)
SELECT * FROM #Doubles
SELECT * FROM #Data
UPDATE #Data
SET DoubleID = MinDoubleID
FROM #Data dt
INNER JOIN #Doubles db ON db.DoubleID = dt.DoubleID
INNER JOIN (
SELECT db.Name, MinDoubleID = MIN(db.DoubleID)
FROM #Doubles db
GROUP BY db.Name
) dbmin ON dbmin.Name = db.Name
/* Kudos to quassnoi */
;WITH q AS (
SELECT Name, ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Name) AS rn
FROM #Doubles
)
DELETE
FROM q
WHERE rn > 1
SELECT * FROM #Doubles
SELECT * FROM #Data
Take a look at this one, i have tried this, working fine
--create table Doubles ( Id int, Name varchar(50))
--create table Data( Id int, DoublesId int)
--select * from doubles
--select * from data
Declare #NonDuplicateID int
Declare #NonDuplicateName varchar(max)
DECLARE #sqlQuery nvarchar(max)
DECLARE DeleteDuplicate CURSOR FOR
SELECT Max(id),name AS SingleID FROM Doubles
GROUP BY [NAME]
OPEN DeleteDuplicate
FETCH NEXT FROM DeleteDuplicate INTO #NonDuplicateID, #NonDuplicateName
--Fetch next record
WHILE ##FETCH_STATUS = 0
BEGIN
--select b.ID , b.DoublesID, a.[name],a.id asdasd
--from doubles a inner join data b
--on
--a.ID=b.DoublesID
--where b.DoublesID<>#NonDuplicateID
--and a.[name]=#NonDuplicateName
print '---------------------------------------------';
select
#sqlQuery =
'update b
set b.DoublesID=' + cast(#NonDuplicateID as varchar(50)) + '
from
doubles a
inner join
data b
on
a.ID=b.DoublesID
where b.DoublesID<>' + cast(#NonDuplicateID as varchar(50)) +
' and a.[name]=''' + cast(#NonDuplicateName as varchar(max)) +'''';
print #sqlQuery
exec sp_executeSQL #sqlQuery
print '---------------------------------------------';
-- now move the cursor
FETCH NEXT FROM DeleteDuplicate INTO #NonDuplicateID ,#NonDuplicateName
END
CLOSE DeleteDuplicate --Close cursor
DEALLOCATE DeleteDuplicate --Deallocate cursor
---- Delete duplicate rows from original table
DELETE
FROM doubles
WHERE ID NOT IN
(
SELECT MAX(ID)
FROM doubles
GROUP BY [NAME]
)
Please try and let me know if this helped you
Thanks
~ Aamod
If you are using MYSQL following worked for me. I did it for 2 steps
Step 1 -> Update all Data rows to one Double table reference (with lowest id)
Step 2 -> Delete all duplicates with keeping lowest id
Step 1 ->
update Data
join
Doubles
on Data.DoublesId = Doubles.id
join
(
select name, min(id) as final_id
from Doubles
group by name
) min_ids
on min_ids.name = Doubles.name
set DoublesId = min_ids.final_id;
Step 2 ->
DELETE c1 FROM Doubles c1
INNER JOIN Doubles c2
WHERE
c1.id > c2.id AND
c1.name = c2.name;