I have two tables as decribe bellow:
Table1
id | table2_id | value
1 | 1 | AAA
2 | 1 | BBB
3 | 1 | CCC
Table2
id | value
1 | XXXX
and I want to update Table2 with combined value from Table1.
OUTPUT Expected on Table2
id | value
1 | AAA,BBB,CCC
How can I do or there are the best way to get expected result that explained above just using TSQL in sql server?
you can use Common Table Expression on this,
WITH record
AS
(
SELECT [table2_id],
STUFF((SELECT ',' + [value]
FROM Table1
WHERE [table2_id] = a.[table2_id]
FOR XML PATH ('')), 1, 1, '') AS val_list
FROM Table1 AS a
GROUP BY [table2_id]
)
UPDATE a
SET a.value = b.val_list
FROM table2 a
INNER JOIN record b
ON a.ID = b.table2_id
SQLFiddle Demo
After exploring JW 웃 answer, I have modify and do simplest way as query bellow:
UPDATE table2
SET table2.value = STUFF((SELECT ',' + [value]
FROM Table1
WHERE [table2_id] = a.[table2_id]
FOR XML PATH ('')), 1, 1, '')
FROM Table1 a
WHERE table2.ID = a.table2_id
Here at SQLFiddle Demo
Related
I have two tables. Can we split a string using STRING_SPLIT() in WHERE clause to compare the same with more than one value? It will be more clear with my query. Please check it below.
Table1
| columnA | columnB |
| ------- | ------- |
| 1 | A,B,C |
| 2 | A,B |
| 3 | B,C |
Table2
| value |
| ------- |
| A |
| B |
| C |
I tried the below query, but it didn't work.
select * from Table1 where STRING_SPLIT(columnB,',') IN (select value from Table2)
Thanks
You can use join:
select t1.*
from Table1 t1 cross apply
string_split(t1.b, ',') s join
table2 t2
on t2.value = s.value;
Or a subquery:
select t1.*
from table1 t1
where exists (select 1
from string_split(t1.b, ',') s join
table2 t2
on t2.value = s.value;
);
But you should really fix your data model so you are not storing multiple values in a string column.
This might work for you.
(Doesn't use STRING_SPLIT function)
select * from Table1
inner join Table2 on ',' + Table1.ColumnB + ',' like '%,' + Table2.Value + ',%'
Not sure about performance. You would need to time it yourself.
I have a query that joins several tables. In the result I have several fields, but I need to group by one of them concatenating the content of other field in a string.
The query result is like next table:
* query result
+-----------+-------------+
| element | option |
+-----------+-------------+
| 25 | foo 2 |
| 25 | bar 1 |
| 25 | baz 1 |
| 30 | foo 2 |
| 30 | baz 5 |
| 32 | baz 1 |
+-----------+-------------+
I have done similar things before with GROUP_CONCAT like this:
SELECT
result.element,
GROUP_CONCAT(result.options SEPARATOR ', ') AS 'options'
FROM (
-- place here an sql query with joins and some calculated fields --
) AS result
GROUP BY result.element
And it usually works, but it seems that the sql server that I have to do this query now, does not support GROUP_CONCAT.
The sql server version is Microsoft SQL Server 2014 (SP2-CU8) (KB4037356) - 12.0.5557.0 (X64) Standard Edition (64-bit) on Windows NT 6.3 (Build 9600: ) (Hypervisor)
What I need in the end is something like this:
* final result
+-----------+-----------------------------+
| element | option |
+-----------+-----------------------------+
| 25 | foo 2, bar 1, baz 1 |
| 30 | foo 2, baz 5 |
| 32 | baz 1 |
+-----------+-----------------------------+
I've searched a lot and I found a way to do this directly from a table, but not from another query result. How it can be done?
EDIT: please, remember that I have to do the xml path from a query result, not from a table. I understand how to use it from a table, but I do not understand how to use the xml path from a query result.
If I use something like:
SELECT
result.element,
( SELECT STUFF((SELECT ',' + options
FROM result T2
WHERE T2.element= result.element
ORDER BY element
FOR XML PATH('')), 1, 1, '') )AS 'options'
FROM (
SELECT
st.element AS 'element',
CONCAT(st.salesoriginid, ' ', COUNT(st.salesoriginid)) AS 'options'
FROM SALESTABLE AS st WITH (NOLOCK)
LEFT JOIN SALESLINE AS sl WITH (NOLOCK) ON sl.SALESID = st.SALESID AND sl.DATAAREAID = st.DATAAREAID
LEFT JOIN INVENTDIM AS idim WITH (NOLOCK) ON idim.INVENTDIMID = sl.INVENTDIMID AND idim.DATAAREAID = sl.DATAAREAID
WHERE st.salestype = 3
AND st.salesoriginid IS NOT NULL
AND st.salesoriginid != ''
GROUP BY st.element, st.salesoriginid
) AS result
GROUP BY result.element
Then I get error:
Invalid object name 'result' [SQL State=S0002, DB Errorcode=208]
You can use STUFF
Select Distinct element, (
SELECT STUFF((SELECT ',' +option
FROM #T T2
Where T2.element = T1.element
ORDER BY element
FOR XML PATH('')), 1, 1, '') )AS [Options]
From #T T1
This should work:
select element,option= stuff((select ',' + option from table t1 where
t1.element=t2.element for xml path ('')),'',1,1) from table t2
group by element
How about using a CTE?
with t as (
<your query here>
)
select e.element,
stuff( (select ',' + t2.option
from t t2
where t2.element = e.element
for xml path ('')
), 1, 1, ''
) as options
from (select distinct element from t) e;
You can probably simplify this by pulling the elements directly from a base table.
I have 2 tables
Table 1:
Query_code | Item_code | Column_Name
2 | 1 | CN1
2 | 2 | CN2
2 | 3 | CN3
Table 2:
Query_code | Source_item| dest_item | pair_code
2 | 1 | 2 | 1
2 | 2 | 3 | 2
What i want to achive is to get source_item-dest_item as result.
According to data that will be:
CN1-CN2
CN2-CN3
What i tried is:
SELECT A.Column_Name
FROM TABLE1 A inner join
TABLE2 B
ON A.QUERY_CODE=B.QUERY_CODE
But this is not even close to my goal
What you need to do is use TABLE2 to identify the source_item and dest_item, then join with TABLE1 the first time to replace source_item with the column name, and join again with TABLE1 to replace dest_item with the other column name.
SELECT A.Column_Name, B.Column_Name
FROM t2 C
LEFT JOIN t1 A
ON C.Source_item=A.Item_code
LEFT JOIN t1 B
ON C.Dest_item=B.Item_code
WHERE C.Query_code=A.Query_code
AND C.Query_code=B.Query_code
Running Example on SQLFiddle
This should work. It is unclear what your Query_Code is meant to do, so I omitted it from the query.
EDIT Inserted Query_code condition as well.
SELECT
Source.Column_Name || '-' || Dest.Column_Name AS ResultPair
FROM
TABLE2 B
INNER JOIN TABLE1 Source
ON B.source_item = Source.item_code AND B.Query_code = Source.Query_code
INNER JOIN TABLE1 Dest
ON B.dest_item = Dest.item_code AND B.Query_code = Dest.Query_code;
Here you go
WITH table1 (query_code, item_code ,column_name ) AS
(SELECT 2,1,'cn1' UNION ALL
SELECT 2,2,'cn2' UNION ALL
SELECT 2,3,'cn3'),
table2 (query_code , source_item, dest_item , pair_code) AS
(SELECT 2,1,2,1 UNION ALL
SELECT 2,2,3,2)
SELECT a.column_name || '-' || c.column_name
FROM table1 a
INNER JOIN table2 b ON a.item_code=b.source_item
INNER JOIN table1 c ON c.item_code=b.dest_item;
i am new to stackoverflow. Am stuck with this problem for weeks but am unable to find similar examples to this (correct me if i am wrong). What i am trying to achieve is updating the values of one table from another table but using a look alike keywords eg. I have 2 tables
table1 (id, item) values:
id | item
-------------
10 | book
20 | copy
30 | pen
table2 (id,item) values:
id | item
-------------
null | the big book
null | the copy machine
null | penpal
Now I want to:
Update table2 A
Set id = Select id From table1 B
Where A.item Like B.item;
My desired outcome is:-
id | item
-------------
10 | the big book
20 | the copy machine
30 | penpal
How do it do it? Thank you all.
update table2 set id =
(select min(id) from table1
where table2.item like '%' || table1.item ||'%' );
Merge :
MERGE INTO Table2 tar
USING
(
SELECT MIN(T1.ID) AS ID, T2.item AS item
Table2 T2
LEFT JOIN
Table1 T1
ON (T2.item LIKE '%'||T1.item||'%')
GROUP BY T2.item
) src
ON (tar.item = src.item)
WHEN MATCHED THEN UPDATE
SET tar.id = src.id;
This solution may be faster.
update table2 t2
set id = ( select min(id) from table1 t1 where item like '%' || t1.item || '%')
where exists ( select 1 from table1 t1 where item like '%' || t1.item || '%');
I need to write a sql query on the table such that the result would have the group by column along with the aggregated column with comma separators.
My table would be in the below format
|`````````|````````|
| ID | Value |
|_________|________|
| 1 | a |
|_________|________|
| 1 | b |
|_________|________|
| 2 | c |
|_________|________|
Expected result should be in the below format
|`````````|````````|
| ID | Value |
|_________|________|
| 1 | a,b |
|_________|________|
| 2 | c |
|_________|________|
You want to use FOR XML PATH construct:
select
ID,
stuff((select ', ' + Value
from YourTable t2 where t1.ID = t2.ID
for xml path('')),
1,2,'') [Values]
from YourTable t1
group by ID
The STUFF function is to get rid of the leading ', '.
You can also see another examples here:
SQL same unit between two tables needs order numbers in 1 cell
SQL and Coldfusion left join tables getting duplicate results as a list in one column
Just for a balanced view, you can also do this with a CTE but its not as good as the cross apply method I don't think. I've coded this of the hoof so apologies if it doesn't work.
WITH CommaDelimitedCTE (RowNumber,ID,[Value],[Values]) AS
(
SELECT 1,MT.ID , MIN(MT.Value), CAST(MIN(MT.Value) AS VARCHAR(8000))
FROM MyTable MT
GROUP BY MT.ID
UNION ALL
SELECT CT.RowNumber + 1, MT.ID, MT.Value, CT.[Values] + ', ' + MT.Value
FROM MyTable MT
INNER JOIN CommaDelimitedCTE CT ON CT.ID = MT.ID
WHERE MT.[Value] > CT.[Value]
)
Select CommaDelimitedCTE.* from CommaDelimitedCTE
INNER JOIN (SELECT MT.ID,MAX(RowNumber) as MaxRowNumber from CommaDelimitedCTE GROUP BY MT.ID) Q on Q.MT.ID = CommaDelimitedCTE.MT.ID
AND Q.MaxRowNumber = CommaDelimitedCTE.RowNumber
In SQL Server 2017 (14.x) and later you can use the STRING_AGG function:
https://learn.microsoft.com/en-us/sql/t-sql/functions/string-agg-transact-sql?view=sql-server-ver16
SELECT
ID,
STRING_AGG(Value, ',')
FROM TableName
GROUP BY ID
Depending on the data type of Value you might need to convert it:
SELECT
ID,
STRING_AGG(CONVERT(NVARCHAR(max), Value), ',')
FROM TableName
GROUP BY ID