create one row from two columns sql - sql

How to create one row from two columns?
Example:
id description
------------------
1 one
2 two
3 three
In result:
1: one, 2: two, 3: three
I use follow statment:
select Id,
stuff((SELECT distinct ', ' + cast(Description as varchar(10))
FROM dbo.tbl t2
where t2.Id = t1.Id
FOR XML PATH('')),1,1,'')
from dbo.tbl t1
group by Id
But in result I have two columns. I need one such as string

You can try this query.
CREATE TABLE T (
id int,
description varchar(50)
);
INSERT INTO T VALUES (1,'one');
INSERT INTO T VALUES (2,'two');
INSERT INTO T VALUES (3,'three');
Query 1:
select
stuff((SELECT ', ' + CAST(t2.ID AS VARCHAR(5)) + ':'+ t2.description
FROM t t2
FOR XML PATH('')),1,1,'')
Results:
| |
|------------------------|
| 1:one, 2:two, 3:three |

i think you are asking for this
select stuff((SELECT ', ' + CAST(tbl.id AS varchar) + ':' + tbl.description
FROM tablename tbl FOR XML PATH('')), 1, 1, '') as Columnname

You were close..
declare #T TABLE (
id int,
description varchar(50)
);
INSERT INTO #T VALUES (1,'one');
INSERT INTO #T VALUES (2,'two');
INSERT INTO #T VALUES (3,'three');
select Id,
stuff((SELECT distinct ', ' + +cast(id as nvarchar) +':'+description
FROM #T t2
where t2.Id = t1.Id
FOR XML PATH('')),1,1,'')
from #T t1
group by Id
OR If you want all the ids in a sing row use the below query
select stuff((select ',' +cast(id as nvarchar) +':'+description
from #T for xml path('')),1,1,'')

select statement is like a for loop or an iterator and you you need a space to save you data and it's not possible with select only because in the moment select statement only access to a row not previous row and not next row so
please use a scaler-value function
create function test()
return
nvarchar(max)
as
begin
declare #s nvarchar(max)
select #s = concate(#s, id, description)
from yourTable
return #s
end

Related

Using SQL REPLACE where the replaced string and replacement are the result of another replacement

Trying to replace some strings on my database where I've got two tables. The replacement on table_2 uses the results of the first replacement as an input:
Current state (string is only a stand-in, it can be anything, the important part is the dash):
|table_1 - col1| |table_2 - col1 |
---------------- ------------------------------
|string-1 | |text string-1 text string-3 |
|string-2 | |text string-3 string-2 t-ext|
|string-3 | |string-2 text string-3 te-xt|
Desired Result:
|table_1 - col1 | |table_2 - col1 |
----------------- ------------------------------
|string_1 | |text string_1 text string_3 |
|string_2 | |text string_3 string_2 t-ext|
|string_3 | |string_2 text string_3 te-xt|
Simply put I want to replace the - with _ in table_1 and also perform a corresponding replacement on table_2.
Came up with the first part, but I can't figure out the replacement part on table_2:
SELECT col1, REPLACE(col1, '-', '_') as Replacement
FROM table_1
where col1 like '%-%'
I need to do something like this (this code is INCORRECT):
SELECT REPLACE(col1,
SELECT [col1] FROM [table_1] where col1 like '%-%',
SELECT REPLACE([col1], '-', '_') FROM [table_1] where col1 like '%-%')
from table_2
For no more then 2 replacements
SELECT t2.col2, REPLACE(REPLACE(t2.col2,t1.col1,REPLACE(t1.col1, '-', '_')),t3.col1,REPLACE(t3.col1, '-', '_'))
FROM table_2 t2
JOIN table_1 t1 ON t2.col2 like '%' +t1.col1+'%' AND t1.col1 LIKE '%-%'
LEFT JOIN table_1 t3 ON t3.col1 <> t1.col1 AND t2.col2 LIKE '%'+t3.col1+'%' AND t3.col1 LIKE '%-%'
WHERE t2.col2 LIKE '%-%'
This is fully ad-hoc, no recursion needed:
DECLARE #table_1 TABLE(ID INT IDENTITY,col1 VARCHAR(100));
INSERT INTO #table_1 VALUES
('string-1'),('string-2'),('string-3');
DECLARE #table_2 TABLE(ID INT IDENTITY,col1 VARCHAR(100));
INSERT INTO #table_2 VALUES
('text string-1 text string-3'),('text string-3 string-2 t-ext'),('string-2 text string-3 te-xt');
--The first CTE replaces the value in t1
WITH t1New AS
(
SELECT ID AS t1_ID
,t1.col1 AS t1c1
,REPLACE(t1.col1,'-','_') AS new_t1c1
FROM #table_1 AS t1
)
--The second CTE splits the strings of t2 on the blanks
,t2Splitted AS
(
SELECT ID
,col1 AS t2c1
,CAST('<x>' + REPLACE(t2.col1,' ','</x><x>') + '</x>' AS XML) AS Casted
FROM #table_2 AS t2
)
--This CTE maps the values to the splitted parts
,Mapped AS
(
SELECT t1New.*
,t2Splitted.ID AS t2_ID
,ROW_NUMBER() OVER(PARTITION BY t2Splitted.ID ORDER BY (SELECT NULL)) AS PartIndex
,part.value('.','nvarchar(max)') AS Part
FROM t2Splitted
CROSS APPLY t2Splitted.Casted.nodes('/x') AS A(part)
LEFT JOIN t1New ON t1New.t1c1=part.value('.','nvarchar(max)')
)
--If there is a mapping, the new value is taken, else take the old value
,NewValues AS
(
SELECT *
,CASE WHEN t1c1 IS NOT NULL THEN new_t1c1 ELSE Part END AS newValue
FROM Mapped
)
--The final CTE re-concatenates the string with blanks in the original order
,Final AS
(
SELECT nv1.t2_ID
,(SELECT ' ' + nv2.newValue
FROM NewValues AS nv2
WHERE nv2.t2_ID=nv1.t2_ID
ORDER BY PartIndex
FOR XML PATH('')) AS FinalValue
FROM NewValues AS nv1
GROUP BY nv1.t2_ID
)
--This last value is used to update the original table
UPDATE t2 SET t2.col1=Final.FinalValue
FROM #table_2 AS t2
INNER JOIN Final ON Final.t2_ID=t2.ID
What's up to you: UPDATE t1, that's a one-liner and get rid of the trailing space in FinalValue :-)
SELECT * FROM #table_2
Variable based replacement can be done as replacing with a table.
DECLARE #Raw NVARCHAR(MAX) = '...';
SELECT #Raw= REPLACE(#Raw, P, R)
FROM (VALUES ('string-1', 'string_1'),
('string-2','string_2'),
('string-3','string_3'),
('string-4','string_4'),
) AS T(P, R);
To execute the same logic against table, think about some statements like
SELECT col1, MultipleReplace(col1, replacement_table(P, R))
FROM some_table
So create a function that accepts a string input and a replacement table. In order to pass table to function, we have to create a table type.
CREATE TYPE dbo.MulReplacements AS TABLE
(
Pattern NVARCHAR(MAX) NOT NULL,
Replacement NVARCHAR(MAX) NOT NULL
)
Then the function would be
CREATE FUNCTION dbo.MulReplace(
#string AS NVARCHAR(MAX),
#replacements AS dbo.MulReplacements READONLY
)
RETURNS NVARCHAR(MAX)
AS
BEGIN
DECLARE #result AS NVARCHAR(MAX) = #string;
SELECT #result = REPLACE(#result, R.Pattern, R.Replacement)
FROM #replacements AS R;
RETURN #result;
END
Put all together
DECLARE #replacement AS dbo.MulReplacements;
INSERT INTO #replacement
SELECT col1, REPLACE(col1, '-', '_')
FROM (VALUES ('string-1'), ('string-2'), ('string-3')) AS table_1(col1)
SELECT col1, dbo.Mulreplace(col1, #replacement)
FROM (VALUES ('text string-1 text string-3'), ('text string-3 string-2 t-ext'), ('string-2 text string-3 te-xt')) AS table_2(col1)
One way of doing it with Dynamic query. Replace the actual table name and column names (commented where to change).
DECLARE #colNames VARCHAR(MAX) = ''
SELECT #colNames = #colNames + ', [' + table1_Col1 + ']' FROM tableName1 -- Table1 Column and Table1 Name
DECLARE #ReqColNames VARCHAR(MAX) = STUFF(#colNames, 1, 1, '')
DECLARE #int int
SELECT #int = count(*) FROM tableName1 -- Table1 Name
DECLARE #replace varchar(max) = replicate('REPLACE(', #int) + 't2.table2_Col2' -- Table2 Column
DECLARE #replaceCols varchar(max) = ''
SELECT #replaceCols = #replaceCols + ', r.[' + table1_Col1 + '], replace(r.[' + table1_Col1 + '], ''-'', ''_''))' FROM tableName1 -- Table1 Column and Table1 Name
DECLARE #ReplaceString varchar(max) = #replace + #replaceCols
DECLARE #cmd varchar(max) = 'SELECT ' + #ReplaceString + ' FROM
(
SELECT * FROM tableName1
PIVOT
(MAX (table1_Col1) FOR table1_Col1 IN (' + #ReqColNames + ')) x
) r
CROSS JOIN tableName2 t2'
EXEC(#cmd)
Static Query: for above code (to show what the above dynamic code is generating):
Select replace(replace(replace(t2.table2_Col2
, r.[string-1], replace(r.[string-1], '-', '_'))
, r.[string-2], replace(r.[string-2], '-', '_'))
, r.[string-3], replace(r.[string-3], '-', '_'))
from
(
Select * from tableName1
PIVOT
(MAX (table1_Col1) FOR table1_Col1 IN ([string-1], [string-2], [string-3])) x
) r
CROSS JOIN tableName2 t2
Output:
text string_1 text string_3
text string_3 string_2 t-ext
string_2 text string_3 te-xt

sql Id concatenation in sequence in a separate column like running total

I need running Id concatenation just like running balance or total..
Concatenate the previous Ids to current Id row wise just like shown in picture
query is
with relation (Id, [orderSequence])
as
(
select Id,cast(Id as varchar(20))
from [ACChartofAccount]
union all
select p.Id, cast(Cast(r.Id as varchar) + ',' + cast(p.Id as varchar) as varchar(20))
from [ACChartofAccount] p
inner join relation r on p.ParentId = r.Id
)
select Id,orderSequence
from relation
order by orderSequence
You can use below query to get above result.
DECLARE #Table TABLE(ID VARCHAR(10));
INSERT INTO #table(ID) VALUES ('320'),(332),(333),(334),(335);
SELECT mt.ID,
STUFF((
SELECT ', ' + ID
FROM #table t
WHERE t.ID <= mt.ID
FOR XML PATH('')), 1, 2, '') AS oldersequence
FROM #table mt
ORDER BY ID

Combine two rows into one row. like average function but instead it will concat

I'm using SQL Server 2000.
What I want to do is like average function but instead it will concat.
Is there a way that I can do that?
For example I have this data.
Name | Score
Name1 | 50
Name1 | 70
and the output should be like this.
Name | Score
Name1 | 50,70
Use below query for your reference.
Query
Select main.doctorID,
Left(Main.submain,Len(Main.submain)-1) As 'Title'
From
(
Select distinct ST2.doctorID,
(
Select convert(varchar,ST1.encounterid) + ',' AS [text()]
From dbo.enc ST1
Where ST1.doctorID = ST2.doctorID
ORDER BY ST1.doctorID
For XML PATH ('')
) submain
From dbo.enc ST2
) [Main]
If you can use CLR, look at this example :
https://msdn.microsoft.com/en-us/library/ms165055%28v=vs.90%29.aspx
It provides a custom aggregate that concatenates values, which results in very clean code.
You can do it by this simple query.
Select Name, (Select SUBSTRING((SELECT ', '+Score from TableName for XML
Path('')) ,2,8000)) from TableName
You will have result like
ColumnName | val1, val2, ....
check this.
INSERT INTO #T VALUES
('name1', 50),
('name1', 70)
SELECT * FROM #T
Select name ,
STUFF((SELECT ',' + cast( score as varchar(50)) FROM #T WHERE (
name=Result.name) FOR XML PATH ('')),1,1,'') AS BATCHNOLIST
From #T AS Result
GROUP BY name
Can I Comma Delimit Multiple Rows Into One Column?
Query
SELECT Name,
(SELECT SUBSTRING((SELECT ', '+CAST(Score AS VARCHAR(MAX)) FROM my_table FOR XML Path('')) ,2,1000)) AS Score
FROM my_table
GROUP BY name;
Fiddle for reference
If you are using SQL Server 2000, then try to create a function as follows.
CREATE TABLE my_table(name VARCHAR(50),score INT);
INSERT INTO my_table VALUES('Name1',50);
INSERT INTO my_table VALUES('Name1',70);
Function
CREATE FUNCTION commaseparated(#name VARCHAR(MAX))
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE #score VARCHAR(MAX)
SELECT #score = COALESCE(#score + ', ', '') + CAST(score AS VARCHAR(MAX))
FROM my_table
WHERE name = #name
RETURN #score
END
SELECT
name,
score = dbo.commaseparated(name)
FROM my_table
GROUP BY name;

How to make 2 rows into single row in sql

I have a query
example
Title Description
A XYZ
A ABC
now i want a sql query so that i can get a single row
Output :
Title Description
A XYZ | ABC
Declare #tbl table(Title nvarchar(1),[Description] nvarchar(100))
Insert into #tbl values('A','XYZ');
Insert into #tbl values('A','ABC');
Insert into #tbl values('A','PQR');
DECLARE #CSVList varchar(100)
SELECT #CSVList = COALESCE(#CSVList + ' | ', '') +
[Description]
FROM #tbl
WHERE Title='A'
SELECT #CSVList
declare #table table (i int, a varchar(10))
insert into #table
select 1, 'ABC' union all
select 1, 'XYZ' union all
select 2, '123'
select t.i,
max(stuff(d.i, 1, 1, '')) [iList]
from #table t
cross
apply ( select '|' + a
from #table [tt]
where t.i = tt.i
for xml path('')
) as d(i)
group
by t.i;
In mysql there is a group_concat function, that can help you.
Use it like this:
SELECT Title,GROUP_CONCAT(Description) FROM table_name GROUP BY Title
The output will be
Title Description
A XYZ,ABC
Then you can replace "," with "|" if you want(it can be done with replace function)
For 2 rows you can self join in SQL Server. This avoids the assorted "concatenate rows into a column" tricks. You can use a LEFT JOIN and NULL handling too for 1 or 2 rows
SELECT
T1.Title,
T1.Description + '|' + T2.Description
FROM
MyTable T1
JOIN
MyTable T2 ON T1.Title = T2.Title
SELECT
T1.Title,
T1.Description + ISNULL('|' + T2.Description, '') --COALESCE for the pedants)
FROM
MyTable T1
LEFT JOIN
MyTable T2 ON T1.Title = T2.Title
If you are using SQL Server, try this: How to return 1 single row data from 2 different tables with dynamic contents in sql

Help with TSQL join query

Based on below 2 tables
declare #t1 table
(
Id int,
Title varchar(100),
RelatedId int
)
insert into #t1 values(1,'A',2)
insert into #t1 values(1,'A',3)
declare #t2 table
(
Id int,
Title varchar(100)
)
insert into #t2 values
(2,'B'),
(3,'C')
I am trying to get the below output
Id Title RelatedItems
---------------------------------
1 A 2 (B), 3 (C)
I tried the following:
select t1.Id,t1.Title, cast(t2.Id as varchar) + ' (' + t2.Title + ')' from #t1 as t1
left outer join #t2 as t2
on t1.RelatedId=t2.Id
But that gives 2 different rows. I want just one row with the data combined in the third column (as shown above). Pls. suggest.
Use:
SELECT DISTINCT
b.id,
b.title,
STUFF((SELECT ','+ CAST(t2.id AS VARCHAR(100)) + ' ('+ t2.title +')'
FROM t2
JOIN t1 a ON a.relatedid = t2.id
WHERE a.id = b.id
FOR XML PATH('')), 1, 1, '')
FROM t1 b