How to concatenate using in sql server - sql-server

I have a table where the data are like
Data
a
b
c
I need to write a SQL query to bring the following output
Data
abc
How to do the same by using in SQL Server 2000
Thanks

I don't know how/if it can be done with XML RAW. This approach works in SQL2000 though.
DECLARE #Data varchar(8000)
set #Data =''
select #Data = #Data + Data
FROM #t
ORDER BY Data
SELECT #Data
Edit Oh I've just seen your other question where Cade gave you a link. Doesn't KM's answer on that link work for you?
KM's test query
--combine parent and child, children are CSV onto parent row
CREATE TABLE #TableA (RowID int, Value1 varchar(5), Value2 varchar(5))
INSERT INTO #TableA VALUES (1,'aaaaa','A')
INSERT INTO #TableA VALUES (2,'bbbbb','B')
INSERT INTO #TableA VALUES (3,'ccccc','C')
CREATE TABLE #TableB (RowID int, TypeOf varchar(10))
INSERT INTO #TableB VALUES (1,'wood')
INSERT INTO #TableB VALUES (2,'wood')
INSERT INTO #TableB VALUES (2,'steel')
INSERT INTO #TableB VALUES (2,'rock')
INSERT INTO #TableB VALUES (3,'plastic')
INSERT INTO #TableB VALUES (3,'paper')
SELECT
a.*,dt.CombinedValue
FROM #TableA a
LEFT OUTER JOIN (SELECT
c1.RowID
,STUFF(REPLACE(REPLACE(
(SELECT
', ' + TypeOf as value
FROM (SELECT
a.RowID,a.Value1,a.Value2,b.TypeOf
FROM #TableA a
LEFT OUTER JOIN #TableB b ON a.RowID=b.RowID
) c2
WHERE c2.rowid=c1.rowid
ORDER BY c1.RowID, TypeOf
FOR XML RAW
)
,'<row value="',''),'"/>','')
, 1, 2, '') AS CombinedValue
FROM (SELECT
a.RowID,a.Value1,a.Value2,b.TypeOf
FROM #TableA a
LEFT OUTER JOIN #TableB b ON a.RowID=b.RowID
) c1
GROUP BY RowID
) dt ON a.RowID=dt.RowID

Related

How to get updated columns from a table?

I am working with SQL Server Triggers. And I need a sql query to find columns from a table whose values has been updated using of INSERTED and DELETED tables.
Can anyone help me out on this ? For ex -
DECLARE #T1 TABLE (Name NVARCHAR(MAX), LName nvarchar(max), Address1 Nvarchar(max),id int)
DECLARE #T2 TABLE (Name NVARCHAR(MAX), LName nvarchar(max), Address1 Nvarchar(max), id int)
insert into #T1 values('Ricky','Broad','a b road',1)
insert into #T1 values('Mike','Halls','m g road',2)
insert into #T2 values('Ricky_Update','Broad','a b road',1)
insert into #T2 values('Mike','Halls','m g road',2)
;WITH ChangedData AS (
SELECT d.name , d.LName FROM #T1 d
EXCEPT
SELECT i.name , i.LName FROM #T2 i
)
I tried to find out by "EXCEPT" but it's returning whole updated row. And I need only updated columns like in above example I only need-
Name column for id =1 because it's updated.
You have to do except for individual columns and then do Union.
SELECT NAME
FROM (
SELECT d.NAME
FROM #T1 d
WHERE id = 1
EXCEPT
SELECT i.NAME
FROM #T2 i
WHERE id = 1
) A
UNION
SELECT LName
FROM (
SELECT d.LName
FROM #T1 d
WHERE id = 1
EXCEPT
SELECT i.LName
FROM #T2 i
WHERE id = 1
) B

Matching Multiple Rows from a SubQuery into the main query

I would like to match multiple rows (exclusively) from a table to another table, and only return the rows that match ALL. Here is my example:
DECLARE #T1 TABLE (Gr int, Dim char(1), Val int)
INSERT INTO #T1 VALUES (1,'A',10)
INSERT INTO #T1 VALUES (1,'B',200)
INSERT INTO #T1 VALUES (1,'B',201)
INSERT INTO #T1 VALUES (1,'B',202)
INSERT INTO #T1 VALUES (1,'C',22)
INSERT INTO #T1 VALUES (1,'C',23)
INSERT INTO #T1 VALUES (1,'C',24)
DECLARE #T2 TABLE (eDim char(1), eVal int)
INSERT INTO #T2 VALUES ('B', 200)
INSERT INTO #T2 VALUES ('C', 29)
SELECT T1.Gr, T1.Dim, T1.Val FROM #T1 T1
WHERE EXISTS (SELECT * FROM #T2 T2 WHERE T2.eDim = T1.Dim AND T2.eVal = T1.Val)
In the example above, the query returns one row from T1 corresponding to the B-200 value pair. What I really need is to either return two records when both B and C values match T2, or return nothing if one or more of the records to not match. Something like "WHERE EXISTS ALL" but this is not recognized by SQL SERVER.
One to do it
SELECT Gr, eDim Dim, eVal Val
FROM
(
SELECT T1.Gr
FROM #T1 t1 JOIN #T2 t2
ON t1.dim = t2.edim
AND t1.val = t2.eval
GROUP BY t1.gr
HAVING COUNT(*) =
(
SELECT COUNT(*) FROM #T2
)
) q CROSS JOIN #T2
Here is SQLFiddle demo Try to uncomment last INSERT INTO #T1 and run query again
or
SELECT gr, dim, val
FROM
(
SELECT gr, dim, val, COUNT(*) OVER (PARTITION BY gr) cnt
FROM #T1 t1 JOIN #T2 t2
ON t1.dim = t2.edim
AND t1.val = t2.eval
GROUP BY gr, dim, val
) q
WHERE cnt =
(
SELECT COUNT(*) FROM #T2
)
Here is SQLFiddle demo Try to uncomment last INSERT INTO #T1 and run query again

Update between two tables when there is no relation between them

I need a SQL statement which fills the null values from the second column of #T1 table with values from #T2(C1).
There is no foreign key or match between the columns of those two tables.
Sample:
T1 (C1, T2C1)
A1, 1
A2, null
A3, null
A4, 4
A5, null
-------------
T2 (C1)
a
b
After update, the T1 will look like:
A1, 1
A2, a
A3, b
A4, 4
A5, null
I found two approaches:
Using CTE
create table #T1 (C1 varchar(10), T2C1 varchar(10))
create table #T2 (C1 varchar(10))
insert into #T1 values ('A1', '1')
insert into #T1 values ('A2', null)
insert into #T1 values ('A3', null)
insert into #T1 values ('A4', '4')
insert into #T1 values ('A5', null)
insert into #T2 values ('a')
insert into #T2 values ('b')
;with t2 as
(
select C1, row_number() over (order by C1) as Index2
from #T2
)
,t1 as
(
select T2C1, row_number() over (order by C1) as Index1
from #T1
where T2C1 is null
)
update t1
set t1.T2C1 = t2.C1
from t2
where t1.Index1 = t2.Index2
select * from #T1
drop table #T1
drop table #T2
With Derived Tables
create table #T1 (C1 varchar(10), T2C1 varchar(10))
create table #T2 (C1 varchar(10))
insert into #T1 values ('A1', '1')
insert into #T1 values ('A2', null)
insert into #T1 values ('A3', null)
insert into #T1 values ('A4', '4')
insert into #T1 values ('A5', null)
insert into #T2 values ('a')
insert into #T2 values ('b')
update #T1
set T2C1 = cj.C1
from #T1
join (select T2C1, row_number() over (order by C1) as Index1, C1
from #T1
where T2C1 is null) ci on ci.C1 = #T1.C1
join (select C1, row_number() over (order by C1) as Index2
from #T2) cj on ci.Index1 = cj.Index2
select * from #T1
drop table #T1
drop table #T2
My question is, can I achieve this without using windowing functions and with no cursors?
Update
#Damien_The_Unbeliever correctly points that to do this kind of update it is not possible without defining an ordering on tables, actually I think exactly said is without properly identify and link the rows from target table.
#Bogdan Sahlean has found another way, using table variables and IDENTITY column, which I'm happy with this solution, it's another way
However, in the real application I will still use the windowing functions
Thanks all
1.I suppose you have a pk in target table (#T1).
2.Instead of ROW_NUMBER this solution uses IDENTITY(1,1) columns and two table variables.
3.I didn't tested this solution.
DECLARE #t2_count INT = (SELECT COUNT(*) FROM #T2);
DECLARE #Target TABLE
(
MyId INT IDENTITY(1,1) PRIMARY KEY
,T1_pk INT NOT NULL UNIQUE
);
INSERT #Target (T1_pk)
SELECT TOP(#t2_count) pk
FROM #T1
WHERE T2C1 IS NULL;
DECLARE #Source TABLE
(
MyId INT IDENTITY(1,1) PRIMARY KEY
,C1 VARCHAR(10) NOT NULL
);
INSERT #Source (C1)
SELECT C1
FROM #T2;
UPDATE #T1
SET T2C1 = src.C1
FROM #T1 t
INNER JOIN #Target trg ON t.pk = trg.T1_pk
INNER JOIN #Source src ON trg.MyId = src.MyId;
I agree with Damien, anyway when you will rely on the engine and make a premise that the table is ordered by the C1 column (which depends only on the DB and you can not rely on that ) the you could issue an update statement which will update all the rows
declare #a int
set #a = 0
update #t1
set t2c1 = #a,
#a = #a+1
But I wouldn't do that.
I would use a CTE along with ROW_NUMBER:
WITH cte_t1 AS
(
SELECT
T2C1
,ROW_NUMBER() OVER (ORDER BY C1) AS id
FROM T1
WHERE T2C1 IS NULL
)
,cte_t2 AS
(
SELECT
C1
,ROW_NUMBER() OVER (ORDER BY C1) AS id
FROM T2
)
UPDATE t1
SET t1.T2C1 = t2.C1
FROM cte_t1 AS t1
INNER JOIN cte_t2 AS t2
ON t1.id = t2.id
;
The ROW_NUMBER creates an identifier based on the order the columns are in (which I am assuming is what you are looking for, but note that SQL does not have an order instead this query is relying on the physical order of the records which is not a good idea but it looks like that is what you are dealing with). We then join on this identifier and update the records in T1 with the values in T2.
I have placed this solution on SQL Fiddle.
If you can look into create new tables with some type of identifier that links them together, then you would not have to rely on the physical order of the records.

SQL Server Another simple question

I have 2 temp Tables [Description] and [Institution], I want to have these two in one table.
They are both tables that look like this:
Table1; #T1
|Description|
blabla
blahblah
blagblag
Table2; #T2
|Institution|
Inst1
Inst2
Inst3
I want to get it like this:
Table3; #T3
|Description| |Institution|
blabla Inst1
blahblah Inst2
blagblag Inst3
They are already in sort order.
I just need to get them next to each other..
Last time I asked was something almost the same.
I used this query
Create Table #T3
(
[From] Datetime
,[To] Datetime
)
INSERT INTO #T3
SELECT #T1.[From]
, MIN(#T2.[To])
FROM #T1
JOIN #T2 ON #T1.[From] < #T2.[To]
GROUP BY #T1.[From]
Select * from #T3
It did work for the date values, but it won't work here ? :s
Thank you.
One thing that concerns me is that you say that the values "are already in sort order". There really is no default sort order -- if you don't specify a sort order, you are at the mercy of SQL Server to determine the order in which the data is returned. The solution below assumes that there is some way to sort the data such that the records "match up" (using the ORDER BY clauses).
Hope this helps,
John
-- Table 1 test data
Create Table #T1
(
[Description] nvarchar(30)
)
INSERT INTO #T1 ([Description]) VALUES ('desc1')
INSERT INTO #T1 ([Description]) VALUES ('desc2')
INSERT INTO #T1 ([Description]) VALUES ('desc3')
-- Table 2 test data
Create Table #T2
(
[Institution] nvarchar(30)
)
INSERT INTO #T2 (Institution) VALUES ('Inst1')
INSERT INTO #T2 (Institution) VALUES ('Inst2')
INSERT INTO #T2 (Institution) VALUES ('Inst3')
-- Create table 3
Create Table #T3
(
[Description] nvarchar(30),
[Institution] nvarchar(30)
);
-- Use CTE2 to add row numbers to the data; use the row numbers to join the tables
-- you must specify the sort order for the data in the tables
WITH CTE1 (Description, RowNum) AS
(
SELECT [Description], ROW_NUMBER() OVER(ORDER BY [Description]) as RowNum
FROM #T1
),
CTE2 (Institution, RowNum) AS
(
SELECT Institution, ROW_NUMBER() OVER(ORDER BY Institution) as RowNum
FROM #T2
)
INSERT INTO #T3
SELECT CTE1.Description, CTE2.Institution
FROM CTE1
LEFT JOIN CTE2 ON CTE1.RowNum = CTE2.RowNum
Select * from #T3

How to merge XML in T-SQL?

It doesn't seem that any amount of reading the docs will help me. Consider the simplified example:
declare #table1 table ( id int, parent xml )
insert #table1 values( 1, '<Root></Root>' )
declare #table2 table ( id int, guts xml )
insert #table2 values( 1, '<Guts>hi mom!</Guts>' )
select t1.parent.query('')
from #table1 t1 inner join #table2 t2 on t1.id = t2.id
What would be passed to the query function to generate this result?
<Root><Guts>hi mom!</Guts></Root>
The following is not set based, but maybe it will help (SQL2008 only)
declare #table1 table ( id int, parent xml )
insert #table1 values( 1, '<Root></Root>' )
declare #table2 table ( id int, guts xml )
insert #table2 values( 1, '<Guts>hi mom!</Guts>' )
DECLARE #id int;
DECLARE #results table (id int, results xml);
DECLARE idCursor CURSOR FOR
select id from #table1
OPEN idCursor
FETCH NEXT FROM idCursor INTO #id
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #parent xml, #guts xml
SELECT #parent = parent FROM #table1 where id = 1;
SELECT #guts = guts FROM #table2 where id = 1;
SET #parent.modify('insert sql:variable("#guts") into (/Root[1])');
INSERT #results (id, results) values (#id, #parent);
FETCH NEXT FROM idCursor INTO #id
END
CLOSE idCursor
DEALLOCATE idCursor
select * from #results;
You are asking for an XML operation, not for a relational operation. What you want is to produce a new XML by inserting a fragment of XML into it, which means you have to use the xml.modify() method. Technically this is possible, but the modify() must be called within an update context, so it won't work in a SELECT. It can work in a SET or in an UPDATE:
UPDATE t1
SET parent.modify(N'insert sql:column("t2.guts") into (/Root)[1]')
FROM #table1 t1
JOIN #table2 t2 on t1.id = t2.id;
SELECT * from #table1;
If you must have the result in a SELECT then you'll have to shred the XML into relational table, join that and reconstruct the XML back using FOR XML.

Resources