concatenate rows and columns in sql server 2008 - sql-server

I have three columns FirstName,LastNAme,MiddleName
Table A
FirstNAme LastName MiddleName ID
James Tony peter 1
Jack Kallis end 1
nnnn nnn nnn 2
mmm mm aa 3
(there may be ten names with one id or one name with id )
Output for FullName where ID=1 should be:
FullName
James Tony Peter,Jack Kallis end

You can do this with the STUFF and FOR XML PATH method:
SELECT
STUFF(
(SELECT
',' + ISNULL(FirstName, '') + ' ' + ISNULL(LastName, '') + ' ' + ISNULL(MiddleName, '')
FROM
dbo.TableA
WHERE
ID = 1
FOR XML PATH('')), 1, 1, '')
This should rendered your desired output.

Related

Substring in T-SQL

I want to Change the full name if the first letter of the first name and last name are both same
This is my code:
SELECT
Id, FName + ' ' + LName 'Full Name',
SUBSTRING(LTRIM(RTRIM(FName)), 1, 1) + '. ' + LTRIM(RTRIM(LName)) 'Short Name'
FROM
testMe
Output:
Full Name Short Name Desired Result
1 John Smith J. Smith John Smith
2 Jack Smith J. Smith Jack Smith
3 Jule Smith J. Smith Jule Smith
4 Paul Smith P. Smith P. Smith
5 Steve Mark S. Mark S. Mark
6 Ashley Howard A. Howard Ashley Howard
7 Adam Campbell A. Campbell Adam Campbell
8 Alex Campbell A. Campbell Alex Campbell
Screenshot for illustration:_
I think I know what you need. If I guessed correctly...
Try this:
DECLARE #Name TABLE (ID int, FName varchar(50), LName varchar(50))
INSERT INTO #Name VALUES
(1, 'John' , 'Smith' )
, (2, 'Jack' , 'Smith' )
, (3, 'Jule' , 'Smith' )
, (4, 'Paul' , 'Smith' )
, (5, 'Steve' , 'Mark' )
, (6, 'Ashley', 'Howard' )
, (7, 'Adam' , 'Campbell')
, (8, 'Alex' , 'Campbell')
;
WITH DupFNameFirst AS
(
SELECT
FName = MAX(FName)
, Qty = SUM(1)
FROM #Name
GROUP BY LEFT(FName, 1) + LName
)
, DupLName AS
(
SELECT
LName
, Qty = SUM(1)
FROM #Name
GROUP BY LName
)
, FinalName AS
(
SELECT
ID
, FullName = FName + ' ' + LName
, ShortName = LEFT(FName,1) + '. ' + LName
, FName
, LName
FROM #Name
)
SELECT
ID
, FullName
, ShortName
, DesiredName = CASE WHEN F.Qty = 1 OR D.Qty = 1 THEN N.ShortName ELSE N.FullName END
FROM FinalName N
LEFT JOIN DupFNameFirst F ON F.FName = N.FName
INNER JOIN DupLName D ON D.LName = N.LName
ORDER BY ID
You can count short names with a window function
select [Full Name]
, case when count(*) over(partition by Short_Name) >1 then [Full Name] else Short_Name end Short_Name
from(
SELECT
FName, FName + ' ' + LName [Full Name],
SUBSTRING(LTRIM(RTRIM(FName)), 1, 1) + '. ' + LTRIM(RTRIM(LName)) Short_Name
FROM
testMe
) t
Hard to tell exactly what you need, but maybe a CASE statement would help:
SELECT
CASE
WHEN LEFT(LTRIM(RTRIM(FName)), 1) = LEFT(LTRIM(RTRIM(LName)), 1 ) THEN SUBSTRING(LTRIM(RTRIM(FName)), 1, 1) + '. ' + LTRIM(RTRIM(LName))
ELSE FName + ' ' + LName
END As FullName
The first CASE condition is when the first letter of first name = first letter of last name. 2nd condition is when they do not match.

Concatenate comma separated strings using STUFF

I want to concatenate comma-separated string. I have a query where I am using the function to get the staff.
Currently, I am using [dbo].fn_fullname(A.REFNO) as Staff to get the staff but I want to include some conditions if the count of cast(S.SCH_NO as varchar) as ReferenceIdentifier is greater than 1 then concatenate the value. But not sure how it can be achieved inside the view itself.
Here I am trying to use STUFF to concatenate.
Here is the query:
Alter View vw_TestDB
AS
select
NEWID() as UniqueKey,
P.ID as Number,
cast(S.SCH_NO as varchar) as ReferenceIdentifier,
cast(S.START_D as datetime2) as StartDateTime,
staff = STUFF((
SELECT ',' + [dbo].fn_fullname(A.REFNO)
FROM [dbo].[vw_TESTDB]
FOR XML PATH('')
), 1, 1, '')
FROM [dbo].[vw_TestDB]
group by ReferenceIdentifier
having count(ReferenceIdentifier)>1,
[dbo].fn_fullname(A.REFNO) as Staff,
from [dbo].V_SCHEDULES S WITH (NOLOCK)
inner join [dbo].V_PAT P WITH (NOLOCK) on P.PAT_REFNO = S.PAT_REFNO
Here the function:
ALTER FUNCTION [dbo].[fn_fullname]
(
#refno as numeric(10, 0)
)
RETURNS varchar(100)
AS
BEGIN
DECLARE #name as varchar(100)
SELECT #name = Stuff(Coalesce(' ' +
CASE
WHEN proca.TITLE_REFNO = 3104
THEN NULL
ELSE
NullIf(dbo.fn_rfval(proca.TITLE_REFNO), '')
END,
'') +
Coalesce(' ' + proca.forename, '') +
Coalesce(' ' + proca.surname, ''),
1,
1,
'')
FROM dbo.v_carers_active proca (nolock)
WHERE refno = #refno
return #name
END
GO
Here are sample data
UniqueKey
Number
ReferenceIdentifier
StartDateTime
staff
70DB83D1-2900-4CF1-9CC4-CA6948AC0E91
A4286
2182823
2015-03-26 08:00:00.0000000
Ms S Taylor
310745CB-4724-4724-A5F0-7D9088317E58
A4286
2182823
2015-03-26 08:00:00.0000000
Ms D Kirkpatrick
CA6DDB25-AADD-4FC1-ABAA-2AF84016E6E5
A4286
2182834
2015-03-19 08:00:00.0000000
Ms D Kirkpatrick
6A3C0A3B-EAA3-4523-B4FD-2882E2C02B4A
A4286
2182844
2015-03-30 08:00:00.0000000
Mrs Nel McKinnon
6399662A-EC4D-4993-8D4F-0BC396D12C2C
A4286
2182844
2015-03-30 08:00:00.0000000
Ms Deb Kirkpatrick
Expected output
UniqueKey
Number
ReferenceIdentifier
StartDateTime
staff
70DB83D1-2900-4CF1-9CC4-CA6948AC0E91
A4286
2182823
2015-03-26 08:00:00.0000000
Ms S Taylor,Ms D Kirkpatrick
CA6DDB25-AADD-4FC1-ABAA-2AF84016E6E5
A4286
2182834
2015-03-19 08:00:00.0000000
Ms D Kirkpatrick
6A3C0A3B-EAA3-4523-B4FD-2882E2C02B4A
A4286
2182844
2015-03-30 08:00:00.0000000
Mrs Nel McKinnon,Ms Deb Kirkpatrick
Not quite understand what you wanted. Based on the sample data and expected output, it seems like you wanted
SELECT t.[Number], t.[ReferenceIdentifier], t.[StartDatetime],
STUFF (
(SELECT ',' + [dbo].fn_fullname(x.REFNO)
FROM yourtable AS x
WHERE x.[Number] = t.[Number]
AND x.[ReferenceIdentifier] = t.[ReferenceIdentifier]
AND x.[StartDatetime] = t.[StartDatetime]
FOR XML PATH('')),
1, 1, '') AS Staff
FROM yourtable t
GROUP BY t.[Number], t.[ReferenceIdentifier], t.[StartDatetime]
HAVING COUNT(*) > 1

Many to many relationship without duplicates

I'm trying to solve a problem with many-to-many relation.
I have 3 tables:
Article
-------
ArticleID
FilePath
Title
Description
Author
--------
AuthorID
AuthorFName /* Father last name */
AuthorMName /* Mother last name */
AuthorName
ArticleAuthor
-------------
AuthorID
ArticleID
Foreign KEY (AuthorID) REFERENCES Author(AuthorID),
FOREIGN KEY (ArticleID) REFERENCES Article(ArticleID),
PRIMARY KEY (AuthorID, ArticleID)
The Author table has 2 authors:
ID FName MName Name
-- ----- ----- ----
1 XXX YYY AAA
2 MMM NNN BBB
The Article:
ID FilePath Title Description (optional)
-- -------- ----- ----------------------
1 /path/file '....' ''
And the ArticleAuthor
ArticleID AuthorID
--------- --------
1 1
1 2
The query I'm using now is:
SELECT DISTINCT ArticleAuthor.ArticleID,
STUFF(
(
SELECT ',' + CONCAT(AuthorFName, ' ', AuthorMName, ' ', AuthorName)
FROM FinderSchema.Author
WHERE Author.AuthorID = ArticleAuthor.AuthorID
FOR XML PATH(''), TYPE
).value('.', 'varchar(max)'), 1, 1, ''
) AS Authors
FROM FinderSchema.ArticleAuthor
LEFT JOIN FinderSchema.Author ON ArticleAuthor.AuthorID = Author.AuthorID
GROUP BY ArticleAuthor.ArticleID, ArticleAuthor.AuthorID
But it returns duplicates:
ArticleID Authors
--------- -------
1 XXX YYY AAA
1 MMM NNN BBB
So, is there a way to remove the duplicates? I have been reading about simulating GROUP_CONCAT (I'm targeting sql server 2008 RC 2), and that's the answer I've found (in stackoverflow, actually), but does not work for me (or many to many relationship, maybe).
Well, if someone can help me, I'll be grateful.
Thanks in advance :)
Try
SELECT ArticleID,
STUFF((SELECT DISTINCT ',' + a.AuthorFName + ' ' + a.AuthorMName + ' ' + a.AuthorName
FROM ArticleAuthor aa JOIN Author a
ON aa.AuthorID = a.AuthorID
WHERE aa.ArticleID = aa2.ArticleID
FOR XML PATH('')) , 1 , 1 , '' ) Authors
FROM ArticleAuthor aa2
GROUP BY ArticleID
Output:
| ARTICLEID | AUTHORS |
---------------------------------------
| 1 | MMM NNN BBB,XXX YYY AAA |
Here is SQLFiddle demo

sql query group by sql server

I have a sql server database table with columns as shown below :
Table1
Id Name ErrorId
1 AB
2 CD
3 AB 3
4 AB 4
I want to get an output something like this :
Name IdCount ErrorIdCount ErrorIds
AB 3 2 4,3
CD 1 0 0
I wrote a query which looks like this currently :
select Name, Count(Id) as IdCount,
Count(Distinct case when ErrorId != ' ' then Id END) as ErrorIdCount
from Table1
group by Name;
It gives me something like this below :
Name IdCount ErrorIdCount.
AB 3 2
CD 1 0
I cannot figure out how I can include the ErrorIds too in my query ?
Can anyone point me out how I can solve this ?
Declare #a table (Id int, Name varchar(10),ErrorId int)
insert into #a Values (1,'AB',null),(2,'CD',null),(3,'AB',3),(4,'AB',4);
Select Name, Count(Id) as IdCount,
Count(Distinct case when ErrorId != ' ' then Id END) as ErrorIdCount
,[ErrorIds]=
STUFF((SELECT ', ' + Cast(ErrorId as Varchar(10))
FROM #a iup
WHERE iup.Name = a.Name
order by ErrorId
FOR XML PATH('')), 1, 1, '')
from #a a
Group by Name

Create query with dynamic columns from different tables

I'm trying to create a query with dynamic columns, based on data from three tables.
This is the database structure:
STUDENT
studentID int,
studentNumber int,
studentName nvarchar(100).
EXAM:
examID int,
examName varchar(100),
examenDate datetime,
EXAM_REGISTRATION:
studentID int,
examID int,
A record is added to the EXAM_REGISTRATION table when a student has registered for an exam.
What I'm trying to get is a list of all the exams and all the students in a pivot table to see which students have registered for which exams, like this:
Quite frankly I don't know where to start.
I can query everything individually and put it all together but how can I combine it into one query?
I've been researching pivot tables, but every example seems to query only from one table and uses numbers and functions like MIN, AVG etc.
Can someone help me along?
ok lets go
some data to play with
create table #student
(studentID int, studentNumber int, studentName nvarchar(100))
create table #exam
(examID int, examName nvarchar(100), examDate datetime)
create table #examReg
(studentID int, examID int)
insert into #student
values (1, 787878, 'pierwszy')
,(2, 89898, 'drugi')
,(3, 343434, 'trzeci')
,(4, 121212, 'czwarty')
insert into #exam
values (1, 'exPierwszy', GETDATE())
,(2, 'exDrugi', GETDATE())
,(3, 'exTrzeci', GETDATE())
insert into #examReg
values (1,2),(1,3)
, (2,2),(2,3)
,(3,1),(3,2)
,(4,1),(4,2),(4,3)
and now the main part, and explanation
first of all you have to get pivot query
select examName, examDate , min([1]) , min([2]), min([3]) ,min([4])--studentID as studentID, examDate --,studentNumber
from
(select a.studentID , studentNumber, examDate, examName
from #student a
join #examReg b on a.studentID = b.studentID
join #exam c on c.examID = b.examID ) as m
pivot
(min(studentNumber) FOR studentID in ([1],[2],[3],[4])) as t
group by examName, examDate
as you have it , just change it select statement and studentID list in pivot declaration, you have to generate those parts dynamicly , so we just copy previously written query and replace columns with our token
declare #sqlTemplate nvarchar(max) =
'select examName, examDate ##sqlColumnList##
from
(select a.studentID , studentNumber, examDate, examName
from #student a
join #examReg b on a.studentID = b.studentID
join #exam c on c.examID = b.examID ) as m
pivot
(min(studentNumber) FOR studentID in (##sqlStudentIDList##)) as t
group by examName, examDate
'
after that you generate column list and studentID list by concatenting strings in tsql
declare #sqlColumnList nvarchar(max) = ''
select #sqlColumnList += ',min([' + cast(studentID as nvarchar(10)) + ']) as [' + studentName +'(' + cast(studentNumber as nvarchar(10)) + ')]'
from #student
declare #sqlStudentIDList nvarchar(max) = ''
select #sqlStudentIDList += '[' + CAST(studentID as nvarchar(10)) + '],'
from #student
set #sqlStudentIDList = SUBSTRING(#sqlStudentIDList, 0, LEN(#sqlStudentIDList))
select #sqlStudentIDList
once you have it , all you have to do is to replace tokens in previous template
set #sqlTemplate = REPLACE(#sqlTemplate, '##sqlColumnList##', #sqlColumnList)
set #sqlTemplate = REPLACE(#sqlTemplate, '##sqlStudentIDList##', #sqlStudentIDList)
select #sqlTemplate
exec sp_executesql #sqlTemplate
and thats it
if you want to read more about pivot go for msdn
if you want to read about dynamic go for this link
edit: to adjust the query for the question from comment you would have to change #sqlColumnList like that
select #sqlColumnList += ',min(' + QUOTENAME(studentID) + ') as Student' + CAST(studentID as nvarchar(10)) + '_REG,
'''+ studentName + ''' as Student' + cast(studentID as nvarchar(10)) + '_NAME,
'+ cast(studentID as nvarchar(10)) + ' as Student' + cast(studentID as nvarchar(10)) + '_ID'
from #student
This is a pivot of the data. I would perform this slightly different than the other answer. If you know all of the values, then you can hard-code the values.
A static version will be:
select examname,
examendate,
IsNull([Smith, John (14323)], 'false') [Smith, John (14323)],
IsNull([Craft, Peter (14334)], 'false') [Craft, Peter (14334)],
IsNull([Davis, Alan (13432)], 'false') [Davis, Alan (13432)],
IsNull([Newman, Ted (133123)], 'false') [Newman, Ted (133123)]
from
(
select e.examname,
e.examenDate,
s.studentName + ' ('+cast(s.studentnumber as varchar(50))+')' studentNameNum,
'true ' as Flag
from exam e
left join exam_registration er
on e.examid = er.examid
right join student s
on er.studentid = s.studentid
) src
pivot
(
max(flag)
for studentNameNum in ([Smith, John (14323)], [Craft, Peter (14334)],
[Davis, Alan (13432)], [Newman, Ted (133123)])
) piv
See SQL Fiddle with Demo
If your values are unknown then the query will be:
DECLARE #cols AS NVARCHAR(MAX),
#colsNull AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(s.studentName + ' ('+cast(s.studentnumber as varchar(50))+')')
from student s
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #colsNull = STUFF((SELECT distinct ',IsNull(' + QUOTENAME(s.studentName + ' ('+cast(s.studentnumber as varchar(50))+')')+', ''false'')'+' as '+QUOTENAME(s.studentName+' ('+cast(s.studentnumber as varchar(50))+')')
from student s
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT examname,
examenDate,' + #colsNull + ' from
(
select e.examname,
e.examenDate,
s.studentName + '' (''+cast(s.studentnumber as varchar(50))+'')'' studentNameNum,
''true '' as Flag
from exam e
left join exam_registration er
on e.examid = er.examid
right join student s
on er.studentid = s.studentid
) x
pivot
(
max(flag)
for studentNameNum in (' + #cols + ')
) p '
execute(#query)
See SQL Fiddle with Demo
The result will be:
| EXAMNAME | EXAMENDATE | CRAFT, PETER (14334) | DAVIS, ALAN (13432) | NEWMAN, TED (133123) | SMITH, JOHN (14323) |
----------------------------------------------------------------------------------------------------------------------------
| Exam 1 | 2013-01-01 12:00:00 | false | false | true | false |
| Exam 2 | 2013-01-01 14:00:00 | true | false | false | true |
| Exam 3 | 2013-01-02 12:00:00 | true | true | false | false |
| Exam 4 | 2013-01-02 14:00:00 | false | false | true | false |
| Exam 5 | 2013-01-03 12:00:00 | false | false | false | true |

Resources