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
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
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
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;
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
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