blogs.conchango.com

welcome to the conchango blogging site
Welcome to blogs.conchango.com Sign in | Join | Help
in Search

SSIS Junkie

I am currently on holiday until 13th October so comments are disabled until then. Feel free to use the "Email" link but don't expect an answer.

Conchango are busy and need top level Technical Architects for Microsoft & Open Source platforms in and around London. Interested? Email me or send me a message

T-SQL: A T-SQL poser - Part 1

Today one of my colleagues, Saivendra Kayal, posed a problem and wondered if it could be solved in T-SQL.

He wanted to turn a set of data that looks like this:

into this:

There's one proviso though. The solution can't contain any procedural logic. So no variables, no cursors, and it has to be one single SQL statement. CTEs are OK. To put it another way, it has to be something you can put into a view definition.

I managed to come up with a fairly elongated solution but then Saivendra trumped me with a much more concise one.  I'll post those in my next post but in the meantime, have a go and see if you can solve it. I'm going away for a couple of days (to Las Vegas Smile) so you've got a while to come up with an answer.

Here's a script that produces the sample data:

USE tempdb

GO

CREATE TABLE t1 (id INT, NAME VARCHAR(MAX))

INSERT t1 values (1,'Jamie')

INSERT t1 values (1,'Joe')

INSERT t1 values (1,'John')

INSERT t1 values (2,'Sai')

INSERT t1 values (2,'Sam')

 

-Jamie

Published 20 March 2007 23:45 by jamie.thomson
Filed under: ,

Comments

 

Nick Barclay said:

I'm sure there are a handful of (probably more efficient) alternatives to the below but here is a first pass.

Cheers,

Nick

with ConcatNamesCTE (id, [name], rn)

as

(

select

 id, [name], rn

from

 (select id, [name],

row_number() over(partition by id order by id) as rn

 from t1) a

where rn = 1

union all

select

 b.id, cn.[name] + ',' + b.[name], b.rn

from

 (select id, [name],

row_number() over(partition by id order by id) as rn

 from t1) b

 inner join ConcatNamesCTE cn

 on cn.id = b.id

 and cn.rn + 1 = b.rn

)

select

 d.id, d.[name]

from

 (select max(rn) as rn, id

from ConcatNamesCTE

group by id) c

 inner join ConcatNamesCTE d

on d.id = c.id

and d.rn = c.rn

order by id asc

March 21, 2007 21:24
 

Adrian Downes said:

--hope the tab formatting looks better posted than it did in the comments field!

select res.id, max(res.name) as [name]

from

(

select c.id,

case when PATINDEX('%' + d.name + '%', c.name) = 0 and c.id = d.id

then c.name + ', ' + d.name

else c.name

end as [name]

from

( select a.id, min(a.name) as [name]

from

( select y.id,

case when PATINDEX('%' + z.name + '%', y.name) = 0 and y.id = z.id

then y.name + ', ' + z.name

end as [name]

from t1 y

inner join t1 z on y.id = z.id

) a

group by a.id

) c

inner join t1 d on c.id = d.id

) res

group by res.id

March 22, 2007 07:59
 

Jamie Hunter said:

select distinct

  id

,  stuff(

  (

     select ',' + name as [text()]

     from t1 b

     where

           b.id = a.id

     for xml path('')

  )

,  1

,  1

,  ''

) as name_csv

from t1 a

order by 1

March 22, 2007 09:34
 

David Portas' Blog said:

In response to Jamie Thomson's T-SQL poser , here's one very efficient method of concatenation

March 22, 2007 09:39
 

Jamie Hunter said:

Hi David,

I think using the Stuff function is a much cleaner solution than using the Substring function.  But you are correct, the XML PATH does have some side effects!

And I did miss the order by name in my solution!

Jamie

March 22, 2007 10:04
 

Rick R said:

CREATE TABLE #n (id int, name varchar(50))

INSERT #n SELECT 1, 'Jamie'

INSERT #n SELECT 1, 'Joe'

INSERT #n SELECT 1, 'John'

INSERT #n SELECT 1, 'Jamie'

INSERT #n SELECT 2, 'Sai'

INSERT #n SELECT 2, 'Sam'

INSERT #n SELECT 3, 'Roger'

INSERT #n SELECT 4, 'Walter'

INSERT #n SELECT 4, 'Teddy'

WITH n1 AS (

SELECT id, CONVERT(varchar(500), MIN(name)) name

FROM #n

GROUP BY id

UNION ALL

SELECT a.id, CONVERT(varchar(500), a.name + ',' + b.name) name

FROM #n a JOIN n1 b ON a.id = b.id AND a.name > b.name

)

SELECT id, MAX(name)

FROM n1

GROUP BY id

March 23, 2007 17:40
 

Rick R said:

Sorry, I copied my temp table version in there.  Here's the correct version:

WITH t2 AS (

SELECT id, MIN(name) name

FROM t1

GROUP BY id

UNION ALL

SELECT a.id, a.name + ',' + b.name name

FROM t1 a JOIN t2 b ON a.id = b.id AND a.name > b.name

)

SELECT id, MAX(name)

FROM t2

GROUP BY id

March 23, 2007 17:44
 

Rob Farley said:

Mine is similar to JamieH's, but I prefer to use 'group by' instead of 'distinct', as 'distinct' will calculate the CSV for every row (and then check them for uniqueness), whereas 'group by' will start by finding the distinct ids first, and then only create the CSVs for the unique ids.

If you duplicate the rows in the tables a few times, you'll see the effect quite clearly. Execution plans will also demonstrate it here. I might write a blog entry on this myself...

select

id,

stuff((

select ',' + t.[name]

from t1 t

where t.id = t1.id

order by t.[name]

for xml path('')

),1,1,'') as name_csv

from t1

group by id

;

March 24, 2007 05:13
 

Rob Farley said:

Jamie Thomson (SQL Server MVP from the UK) threw out a challenge recently, and it was interesting to

March 24, 2007 06:30
 

Paul McMillan said:

Jamie

Deja Vu????

http://www.sqlteam.com/item.asp?ItemID=256

But as I said, you can write Procedural Logic in a View.. Just use a UDF!!!!!

Paul

March 28, 2007 12:27
 

Sinix said:

Hmm... I'm prefer to realize such things as CLR aggregates. Any better solution?

June 9, 2007 01:47
 

c.m.saravanakumar said:

$query = "SELECT content_id from tbl_content ORDER BY limit 1 ";

i have to select all id from one table and the id can display in the same order in the another table in database

for ex:content_id(1234567)

nexttable:menu_id(1234567)content_id(1234567)get from content_id and link to display same as

April 23, 2008 07:40
 

c.m.saravanakumar said:

how to select a complete id in one table and equally link to another in the another table in the same databade

April 23, 2008 08:33
New Comments to this post are disabled

This Blog

Syndication

News

Powered by Community Server (Personal Edition), by Telligent Systems