SQL SELF JOIN TO CONCATENATE COLUMNS [duplicate] - sql

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Simulating group_concat MySQL function in MS SQL Server 2005?
I have two table namely ServiceEntryPart and Part. One service entry could have multiple parts. What I am trying to do is to concatenate different parts for the same service entry. The final entry I am looking for is to have something like below"
ServiceEntryID PartDescription
3 2 ~ xyz Manager | 3 ~ Elevator
In the Column Part Description, different part ids are concatenated in one column by using part id first followed by a tilda and part description followed by a Pipe character and the same format for different parts in the serviceentry part. Any help would be appriciated. thanks
please find the structure below
dbo.ServiceEntryPart
ID ServiceEntryID PartID
266 2 1
234 3 2
234 3 3
233 5 4
dbo.Part
ID PartDescription
1 Sample Manager
2 xyz Manager
3 Elevator

SELECT ServiceEntryID, PartDescription =
STUFF((SELECT ' | ' + CAST(b.ID AS NVARCHAR) + ' ~ ' + PartDescription
FROM Part b
INNER JOIN ServiceEntryPart c
ON c.PartId = b.ID
WHERE c.ServiceEntryID = a.ServiceEntryID
FOR XML PATH('')), 1, 3, '')
FROM ServiceEntryPart a
GROUP BY ServiceEntryID

http://www.simple-talk.com/sql/t-sql-programming/concatenating-row-values-in-transact-sql/

In the next url you can find many methods to do this job, I recommend you to use The blackbox XML methods described in that tutorial, is the easiest way to do it.
Concatenating Row Values in Transact-SQL
Something Like this...
SELECT dbo.ServiceEntryPart.ServiceEntryID,
( SELECT dbo.Part.ID + '~' + dbo.Part.PartDescription + ','
FROM dbo.Part
WHERE dbo.ServiceEntryPart.PartID = dbo.Part.ID
ORDER BY dbo.Part.ID
FOR XML PATH('') ) AS PartDescription
FROM dbo.ServiceEntryPart
GROUP BY dbo.ServiceEntryPart.ServiceEntryID

Related

Combining row values from multiple tables into one result cell

I'm looking to create a report of sorts and am having a hard time wrapping my head around how this portion could be done with a single select in SQL (my experience is limited to a database course and some working knowledge - more of a front end dev).
I should mention that joining the question table and question tag bindings/tags table isn't an issue for me - what I can't wrap my head around is how multiple values could be added to the same result cell without multiple nasty T-SQL loops.
Any tips on how to get started would be a huge help.
Table 1: Question Table
ID Content CategoryName
---------------------------
1 ABC Q1
2 DEF Q3
3 GEH Q3
Table 2: Tag Table
Tag Id Tag Name
---------------------------------
4 Dream
5 Light
6 Recover
Table 3: Question Tag Bindings
BoundQuestion ID BoundTagId
---------------------------------
1 4
2 5
3 6
3 4
Desired Result Table (Question table with added Tags column)
ID Content CategoryName Tags
----------------------------------------
1 ABC Q1 Dream
2 DEF Q3 Light
3 GEH Q3 Recover, Light
Thanks to anybody who looks at this, hope you're all staying safe.
You could join the three tables and aggregate to generate tag list. I guess that a lateral join should also be an efficient option here, since it avoids outer aggregation:
select q.*, t.*
from questions q
outer apply(
select string_agg(tag_name, ', ') tags
from questionTags qt
inner join tags t on t.TagID = qt.BoundTagID
where qt.BoundQuestionID = q.ID
) t
Note that string_agg() was added in SQL Server 2017.
In earlier versions, we can resort the for xml path solution:
select
q.*,
stuff(
(
', ' + tag_name tags
from questionTags qt
inner join tags t on t.TagID = qt.BoundTagID
where qt.BoundQuestionID = q.ID
order by tag_name
for xml path('')
),
1, 2, ''
) tags
from questions q

sql concatenate line [duplicate]

This question already has answers here:
How to concatenate text from multiple rows into a single text string in SQL Server
(47 answers)
Closed 7 years ago.
I'm looking for a sql query that will find all values in "PartNumber below" and concat. using a comma if the material is listed multiple times with different sales orgs. I've been racking my brain trying to figure it out. I'm running SQL 2008 R2
Assume the following SQL table
PartNumber Org
ABC 1
DEF 2
FGH 3
ABC 2
FGH 5
My expected output would be:
PartNumber Org
ABC 1,2
DEF 2
FGH 3,5
You can use XML PATH for getting the desired result.
SELECT PartNumber , STUFF(( SELECT ','+ org FROM t1 a
WHERE b.PartNumber = a.PartNumber FOR XML PATH('')),1 ,1, '') org
FROM t1 b
GROUP BY PartNumber;

Concatenate many rows into comma-separated list based on unique id [duplicate]

This question already has answers here:
Simulating group_concat MySQL function in Microsoft SQL Server 2005?
(12 answers)
Closed 8 years ago.
I'm new to SQL (running SQL Server 2012), the query I'm running is returning these results.
IDNum Email
----------------
1 a#a.com
1 b#b.com
1 c#c.com
2 d#d.com
2 e#e.com
3 f#f.com
3 g#g.com
3 h#h.com
4 i#i.com
5 j#j.com
5 k#k.com
I would like to get the following result set (a comma separated list unique to each id)
IDNum Emails
---------------------------------
1 a#a.com,b#b.com,c#c.com
2 d#d.com,e#e.com
3 f#f.com,g#g.com,h#h.com
4 i#i.com
5 j#j.com,k#k.com
I've been trying to follow some of the answers from other questions but not having any luck. I'm sure it's some combination of my inexperience & all the other questions I'm finding with this are just results from a single table. My query is getting results from multiple tables if that makes a difference, would be similar to
SELECT DISTINCT
s.idnum, e.email
FROM
student s
JOIN
email e ON e.guid = s.guid
WHERE
s.activeYear = 1 AND e.activeEmail = 1
Can anyone help? Thanks.
******UPDATE******
I ended up using the following query after reading a few more articles here and on another website. Hope this helps someone in the future.
USE databaseName
SELECT s.idnum,
STUFF(( SELECT ',' + e.email AS [text()]
FROM email e
WHERE
e.guid = s.guid AND e.activeEmail = 1
FOR XML PATH('')
), 1, 1, '' )
AS emails
FROM student s
WHERE s.activeYear = 1
In Oracle you would do this with a LISTAGG function, but for SQL-Server try this question, there's a few different options there:
ListAGG in SQLSERVER

How to write query using self join and group by?

I have sql server 2008 db table FILE_DETAILS in following format.
ID FileName Filesize_in_MB
--------------------------------
1 a.txt 5
2 b.txt 2
3 c.txt 2
3 d.txt 4
4 e.txt 6
4 f.txt 1
4 g.txt 2
5 h.txt 8
6 i.txt 7
now what i want to fetch is as bellow
ID FileName Filesize_in_MB
--------------------------------
1 a.txt 5
2 b.txt 2
3 c.txt;d.txt 6
4 e.txt;f.txt;g.txt 9
5 h.txt 8
6 i.txt 7
In above results what happens ID became unique key and FILENAME has get attached and separated by ; and also FILESIZE_IN_MB field in sum of group by ID
I tried with various combination like groupby + self join, also sub queries and all that
but i think i missing something.
is it possible to handle this in SQL query?
Thanks in advance
Try this:
SELECT ID,
STUFF(( SELECT ';' + [FileName]
FROM FILE_DETAILS
WHERE ID = f.ID FOR XML PATH('')), 1, 1, ''),
SUM(Filesize_in_MB)
FROM FILE_DETAILS f
GROUP BY ID
Here's some more information:
Concatenate many rows into a single text string?
You should be able to do this using a group by. Aggregating Filesize_IN_MB can be done using sum as aggregator. However, to aggregate FileName you may need to create an AGGREGATE in SQL SERVER 2008R2. This will allow you to use Concatenate as an aggregation function.
select Concatenate(FileName), sum(Filesize_IN_MB) FROM FILE_DETAILS group by ID
There is another way of aggregate concatenation which seems fairly simple but I haven't tried.

Concatenate several fields into one with SQL

I have three tables tag, page, pagetag
With the data below
page
ID NAME
1 page 1
2 page 2
3 page 3
4 page 4
tag
ID NAME
1 tag 1
2 tag 2
3 tag 3
4 tag 4
pagetag
ID PAGEID TAGID
1 2 1
2 2 3
3 3 4
4 1 1
5 1 2
6 1 3
I would like to get a string containing the correspondent tag names for each page with SQL in a single query. This is my desired output.
ID NAME TAGS
1 page 1 tag 1, tag 2, tag 3
2 page 2 tag 1, tag 3
3 page 3 tag 4
4 page 4
Is this possible with SQL?
I am using MySQL. Nonetheless, I would like a database vendor independent solution if possible.
Sergio del Amo:
However, I am not getting the pages without tags. I guess i need to write my query with left outer joins.
SELECT pagetag.id, page.name, group_concat(tag.name)
FROM
(
page LEFT JOIN pagetag ON page.id = pagetag.pageid
)
LEFT JOIN tag ON pagetag.tagid = tag.id
GROUP BY page.id;
Not a very pretty query, but should give you what you want - pagetag.id and group_concat(tag.name) will be null for page 4 in the example you've posted above, but the page shall appear in the results.
Yep, you can do it across the 3 something like the below:
SELECT page_tag.id, page.name, group_concat(tags.name)
FROM tag, page, page_tag
WHERE page_tag.page_id = page.page_id AND page_tag.tag_id = tag.id;
Has not been tested, and could be probably be written a tad more efficiently, but should get you started!
Also, MySQL is assumed, so may not play so nice with MSSQL! And MySQL isn't wild about hyphens in field names, so changed to underscores in the above examples.
As far as I'm aware SQL92 doesn't define how string concatenation should be done. This means that most engines have their own method.
If you want a database independent method, you'll have to do it outside of the database.
(untested in all but Oracle)
Oracle
SELECT field1 | ', ' | field2
FROM table;
MS SQL
SELECT field1 + ', ' + field2
FROM table;
MySQL
SELECT concat(field1,', ',field2)
FROM table;
PostgeSQL
SELECT field1 || ', ' || field2
FROM table;
I got a solution playing with joins. The query is:
SELECT
page.id AS id,
page.name AS name,
tagstable.tags AS tags
FROM page
LEFT OUTER JOIN
(
SELECT pagetag.pageid, GROUP_CONCAT(distinct tag.name) AS tags
FROM tag INNER JOIN pagetag ON tagid = tag.id
GROUP BY pagetag.pageid
)
AS tagstable ON tagstable.pageid = page.id
GROUP BY page.id
And this will be the output:
id name tags
---------------------------
1 page 1 tag2,tag3,tag1
2 page 2 tag1,tag3
3 page 3 tag4
4 page 4 NULL
Is it possible to boost the query speed writing it another way?
pagetag.id and group_concat(tag.name) will be null for page 4 in the example you've posted above, but the page shall appear in the results.
You can use the COALESCE function to remove the Nulls if you need to:
select COALESCE(pagetag.id, '') AS id ...
It will return the first non-null value from it's list of parameters.
I think you may need to use multiple updates.
Something like (not tested):
select ID as 'PageId', Name as 'PageName', null as 'Tags'
into #temp
from [PageTable]
declare #lastOp int
set #lastOp = 1
while #lastOp > 0
begin
update p
set p.tags = isnull(tags + ', ', '' ) + t.[Tagid]
from #temp p
inner join [TagTable] t
on p.[PageId] = t.[PageId]
where p.tags not like '%' + t.[Tagid] + '%'
set #lastOp == ##rowcount
end
select * from #temp
Ugly though.
That example's T-SQL, but I think MySql has equivalents to everything used.