Query for Splitting a Name Field in SQL Server - sql-server

I have a field [Name] which I need to break up into separate parts in a query. The field is in the format:
LastName,FirstName PossibleMiddle
Sample values:Doe,John Andrew
Smith,Jane
Goal for output:
[LastName] [FirstName] [MiddleName]
---------------- ---------------- ----------------
Doe John Andrew
Smith Jane
Here is the code I've been able to work out until now:
SELECT
LEFT([Name], CHARINDEX(',', [Name]) - 1) AS [Last Name],
SUBSTRING([Name], CHARINDEX(',', [Name]) +1, LEN([Name])) AS [First and Middle Name],
SUBSTRING([Name], CHARINDEX(',', [Name]) +1, (CHARINDEX(' ', [Name])-1)) AS [First Name]
FROM t1
This code is not right for a couple of reasons:
1. It fails because the second SUBSTRING is not correctly formulated. It assumes that there will always be a space, but there will actually only be a space if there is a middle name.
2. I don't want [First and Middle Name] as one (but I think once the first issue is resolved the rest will fall into place).
I feel like I'm missing something obvious with this but it's been a long morning of trying, searching and no solution yet. Thanks in advance for taking the time to look and respond.

using cross apply() so we do not have to repeat a function all over the place for the second part:
select
lastname = left(t.str,charindex(',',t.str)-1)
, firstname = left(x.val,charindex(' ',x.val+' '))
, middlename = nullif(right(x.val,len(x.val)-charindex(' ',x.val)),x.val)
from t
cross apply (
select val = stuff(t.str,1,charindex(',',t.str),'')
) x(val)
rextester demo: http://rextester.com/TUJNX20615
returns:
+----------+-----------+------------+
| lastname | firstname | middlename |
+----------+-----------+------------+
| Doe | John | Andrew |
| Smith | Jane | NULL |
+----------+-----------+------------+
To extend your example to include mononymous individuals:
create table t (str varchar(32))
insert into t values
('Doe,John Andrew')
,('Smith,Jane')
,('Sting') -- mononymous
select
lastname = left(t.str,charindex(',',t.str+',')-1)
, firstname = nullif(left(x.val,charindex(' ',x.val+' ')),t.str)
, middlename = nullif(right(x.val,len(x.val)-charindex(' ',x.val)),x.val)
from t
cross apply (
select val = stuff(t.str,1,charindex(',',t.str),'')
) x(val)
rextester demo: http://rextester.com/WPZXC58652
returns:
+----------+-----------+------------+
| lastname | firstname | middlename |
+----------+-----------+------------+
| Doe | John | Andrew |
| Smith | Jane | NULL |
| Sting | NULL | NULL |
+----------+-----------+------------+

I believe I have this working correctly. Basically, I used two case statements, based on whether or not there was a space in the name.
So, if there is a space in the name, then break on that for the first name. If not, take the rest of the field.
DECLARE #NAME VARCHAR(50)
SET #NAME = 'Smith,Jane' -- 'Smith,Jane Ann'
SELECT LEFT(#NAME, CHARINDEX(',', #NAME) - 1) AS LastName,
CASE
WHEN (CHARINDEX(' ', #NAME) = 0)
THEN SUBSTRING(#NAME, CHARINDEX(',', #NAME) + 1, 100)
ELSE
SUBSTRING(#NAME, CHARINDEX(',', #NAME) + 1, CHARINDEX(' ', #NAME) - CHARINDEX(',', #NAME))
END AS FirstName,
CASE
WHEN (CHARINDEX(' ', #NAME) = 0)
THEN ''
ELSE
SUBSTRING(#NAME, CHARINDEX(' ', #NAME) + 1, 100)
END AS MiddleName

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.

SQL Dynamic Charindex

I have a field in a sql table but I need to parse it via charindex, but the lttle caveat is, I don't know how many pieces there are.
The field data would look like the following:
(Image: "filename=a.jpg"), (Image: "filename=b.jpg")
But the question I'm not sure how many filenames there will be in this string, so i need to dynamically build this out this could be 1 or this could be 100.
Any suggestions?
Thanks
Since you cannot know in advance how many values you will extract from each value, I would suggest to represent the results as records, not columns.
If you are using SQL Server 2016 or higher, you can use function STRING_SPLIT() to turn CSV parts to records. Then, SUBSTRING() and CHARINDEX() can be used to extract the relevant information:
declare #t table ([txt] varchar(200))
insert into #t VALUES ('(Image: "filename=a.jpg"),(Image: "filename=b.jpg")')
SELECT value, SUBSTRING(
value,
CHARINDEX('=', value) + 1,
LEN(value) - CHARINDEX('=', value) - 2
)
FROM #t t
CROSS APPLY STRING_SPLIT(t.txt , ',')
Demo on DB Fiddle:
DECLARE #t table ([txt] varchar(200))
INSERT INTO #t VALUES ('(Image: "filename=a.jpg"),(Image: "filename=b.jpg")')
SELECT value, SUBSTRING(
value,
CHARINDEX('=', value) + 1,
LEN(value) - CHARINDEX('=', value) - 2
)
FROM #t t
CROSS APPLY STRING_SPLIT(t.txt , ',')
GO
value | (No column name)
:------------------------ | :---------------
(Image: "filename=a.jpg") | a.jpg
(Image: "filename=b.jpg") | b.jpg
NB : this assumes that the value to extract is always located after the first equal sign and until 2 characters before the end of string. If the pattern is different, you may need to adapt the SUBSTRING()/CHARINDEX() calls.
The real issue is: This is breaking 1.NF. You should never ever store more than one piece of data in one cell. Such CSV-formats are a pain in the neck and you really should use a related side table to store your image hints one by one.
Nevertheless, this can be handled:
--A mockup table
DECLARE #mockup TABLE(ID INT IDENTITY,YourString VARCHAR(1000));
INSERT INTO #mockup VALUES
('(Image: "filename=a.jpg"), (Image: "filename=b.jpg") ')
,('(Image: "filename=aa.jpg"), (Image: "filename=bb.jpg"), (Image: "filename=cc.jpg"), (Image: "filename=dd.jpg"), (Image: "filename=ee.jpg")');
--Pick one element by its position:
DECLARE #position INT=2;
SELECT CAST('<x>' + REPLACE(t.YourString,',','</x><x>') + '</x>' AS XML)
.value('/x[position()=sql:variable("#position")][1]','nvarchar(max)')
FROM #mockup t;
The trick is, to transform the string to XML and use XQuery to fetch the needed element by its position. The intermediate XML looks like this:
<x>(Image: "filename=a.jpg")</x>
<x> (Image: "filename=b.jpg") </x>
You can use some more replacements and L/RTRIM() to get it cleaner.
Read table data
And if you want to create a clean side table and you need all data neatly separated, you can use a bit more of the same:
SELECT CAST('<x><y><z>'
+ REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
t.YourString,'(','') --no opening paranthesis
,')','') --no closing paranthesis
,'"','') --no quotes
,' ','') --no blanks
,'=','</z><z>') --Split at "="
,':','</z></y><y><z>') --Split at ":"
,',','</z></y></x><x><y><z>') --Split at ","
+ '</z></y></x>' AS XML)
FROM #mockup t;
This returns
<x>
<y>
<z>Image</z>
</y>
<y>
<z>filename</z>
<z>a.jpg</z>
</y>
</x>
<x>
<y>
<z>Image</z>
</y>
<y>
<z>filename</z>
<z>b.jpg</z>
</y>
</x>
And with this you would get a clean EAV-table (
WITH Casted AS
(
SELECT ID
,CAST('<x><y><z>'
+ REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
t.YourString,'(','')
,')','')
,'"','')
,' ','')
,'=','</z><z>')
,':','</z></y><y><z>')
,',','</z></y></x><x><y><z>')
+ '</z></y></x>' AS XML) AS CastedToXml
FROM #mockup t
)
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS ID
,ID AS oldId
,eachElement.value('y[1]/z[1]','varchar(max)') AS DataType
,eachElement.value('y[2]/z[1]','varchar(max)') AS ContentType
,eachElement.value('y[2]/z[2]','varchar(max)') AS Content
FROM Casted
CROSS APPLY CastedToXml.nodes('/x') A(eachElement)
The result
+----+-------+----------+-------------+---------+
| ID | oldId | DataType | ContentType | Content |
+----+-------+----------+-------------+---------+
| 1 | 1 | Image | filename | a.jpg |
+----+-------+----------+-------------+---------+
| 2 | 1 | Image | filename | b.jpg |
+----+-------+----------+-------------+---------+
| 3 | 2 | Image | filename | aa.jpg |
+----+-------+----------+-------------+---------+
| 4 | 2 | Image | filename | bb.jpg |
+----+-------+----------+-------------+---------+
| 5 | 2 | Image | filename | cc.jpg |
+----+-------+----------+-------------+---------+
| 6 | 2 | Image | filename | dd.jpg |
+----+-------+----------+-------------+---------+
| 7 | 2 | Image | filename | ee.jpg |
+----+-------+----------+-------------+---------+
I used a table value function
ALTER FUNCTION [dbo].[Fn_sqllist_to_table](#list AS VARCHAR(8000),
#delim AS VARCHAR(10))
RETURNS #listTable TABLE(
Position INT,
Value VARCHAR(8000))
AS
BEGIN
DECLARE #myPos INT
SET #myPos = 1
WHILE Charindex(#delim, #list) > 0
BEGIN
INSERT INTO #listTable
(Position,Value)
VALUES (#myPos,LEFT(#list, Charindex(#delim, #list) - 1))
SET #myPos = #myPos + 1
IF Charindex(#delim, #list) = Len(#list)
INSERT INTO #listTable
(Position,Value)
VALUES (#myPos,'')
SET #list = RIGHT(#list, Len(#list) - Charindex(#delim, #list))
END
IF Len(#list) > 0
INSERT INTO #listTable
(Position,Value)
VALUES (#myPos,#list)
RETURN
END
By calling it via
select * into #test from tableX as T
cross apply [Fn_sqllist_to_table](fieldname,'(')
and then just substringed the value into the final table

How to not return null value in sql server?

I have this data set like shown below;
Company | Address | Business | Telephone Number | Contact Person
A&B | Perak | Khmer Restaurants | 012541 | Mr. Yu Lee
A&B | Perak | F&B | 012541 | Mr. Yu Lee
King Co.| Ipoh | Paper Distributors | 021453 | Mrs. Cheng
King Co.| Ipoh | Paper Distributors | Null | Mrs. Cheng
DinoX | Sunway | Guesthouses | 0124587 | Mr. Hong
Dinox | Sunway | Guesthouses | 0124587 | Mr. Q
After making some query like shown below, i get a new dataset :
IF OBJECT_ID('tempdb..#tCat') IS NOT NULL DROP TABLE #tcat
GO
DECLARE #portal varchar(100) = 'A4E7890F-A188-4663-89EB-176D94DF6774'
SELECT * INTO #tcat
FROM (
SELECT DISTINCT list.[name]
,lc.listing_uuid
,dCat.[name] as Category
,catg.[name] as Sub_Category
,comm.[value] as Telephone_Number
,pp.title + ' ' + pp.first_name + ' ' + pp.last_name as Contact_Person
FROM panpages.listings as list
LEFT JOIN panpages.listing_categories as lc on lc.listing_uuid=list.uuid AND lc.portal_uuid=#portal
LEFT JOIN panpages.categories as catg on catg.uuid=lc.category_uuid AND catg.portal_uuid=#portal
left join panpages.listing_people as lp on lp.listing_uuid = list.uuid
left join panpages.people as pp on pp.id = lp.person_id
left join panpages.person_communications as comm on comm.person_id = lp.person_id and (comm.communication_type = 'Mobile Phone' or comm.communication_type = 'Tel')
LEFT JOIN ( SELECT DISTINCT uuid,[name] FROM panpages.categories WHERE parent_uuid IS NULL ) as dCat on dCat.uuid=catg.parent_uuid
WHERE list.portal_uuid=#portal and list.is_active=1
)as tCat
select
list.[name] as [Company]
,list.[address] as [Address]
,replace(cats.Sub_Category,'&','&') as [Nature of Business]
,replace(cats.Telephone_Number,'&','&') as [Telephone Number]
,replace(cats.Contact_Person,'&','&') as [Contact Person]
from [panpages].[listings] as list
left join (
SELECT DISTINCT tc1.listing_uuid,tc1.[name],
Sub_Category = STUFF(( SELECT ', ' + tc2.Sub_Category
FROM
(
SELECT Sub_Category, MIN(listing_uuid) AS listing_uuid
FROM #tCat
GROUP BY Sub_Category
) AS tc2
WHERE tc1.listing_uuid = tc2.listing_uuid
ORDER BY tc2.Sub_Category
FOR XML PATH('')), 1, 1, ''),
Telephone_Number = STUFF(( SELECT ', ' + tc2.Telephone_Number
FROM
(
SELECT Telephone_Number, MAX(listing_uuid) AS listing_uuid
FROM #tCat
GROUP BY Telephone_Number
) AS tc2
WHERE tc1.listing_uuid = tc2.listing_uuid
ORDER BY tc2.Telephone_Number
FOR XML PATH('')), 1, 1, ''),
Contact_Person = STUFF(( SELECT ', ' + tc2.Contact_Person
FROM
(
SELECT Contact_Person, MAX(listing_uuid) AS listing_uuid
FROM #tCat
GROUP BY Contact_Person
) AS tc2
WHERE tc1.listing_uuid = tc2.listing_uuid
ORDER BY tc2.Contact_Person
FOR XML PATH('')), 1, 1, '')
FROM #tCat as tc1 where tc1.listing_uuid is not null
) cats on cats.listing_uuid=list.uuid
where
list.[portal_uuid]=#portal and
list.[is_active]=1
And below is the new dataset :
Company |Address| Business | Telephone Number | Contact Person
A&B | Perak | Khmer Restaurants, F&B| 012541 | Mr. Yu Lee
King Co.| Ipoh | Paper Distributors | 021453, Null | Mrs. Cheng
DinoX | Sunway| Guesthouses | 0124587 | Mr. Hong, Mr Q
How to not return the null value? I dont want to return the "Null" value.
You can either use ISNULL function prior to check or you can use COALESCE function as below
SELECT COALESCE(Telephone_Number,''), MAX(listing_uuid) AS listing_uuid
Replace whatever you want to return within ' '. If you just want an empty string, leave it at ''
Use STUFF inside a replace to replace the null values.
Telephone_Number = Replace(STUFF( SELECT ', ' + tc2.Telephone_Number
FROM
(
SELECT Telephone_Number, MAX(listing_uuid) AS listing_uuid
FROM #tCat
GROUP BY Telephone_Number
) AS tc2
WHERE tc1.listing_uuid = tc2.listing_uuid
ORDER BY tc2.Telephone_Number
FOR XML PATH('')), 1, 1, ''), ' null', ''),

Insert random Data content in SQL Server 2008

I know there are several topics on this, but none of them was suitable for me, that's why I took the chance to ask you again.
I have a table which has columns UserID, FirstName, Lastname.
I need to insert 300 000 records for each column and they have to be unique, for example:
UserID0001, John00001, Doe00001
UserID0002, John00002, Doe00002
UserID0003, John00003, Doe00003
I hope there is an easy way :)
Thank you in advance.
Best,
Lyubo
;with sequence as (
select N = row_number() over (order by ##spid)
from sys.all_columns c1, sys.all_columns c2
)
insert into [Table] (UserID, FirstName, Lastname)
select
'UserID' + right('000000' + cast(N as varchar(10)), 6),
'John' + right('000000' + cast(N as varchar(10)), 6),
'Doe' + right('000000' + cast(N as varchar(10)), 6)
from sequence where N <= 300000
You could use the ROW_NUMBER function to generate different numbers like this:
SQL Fiddle
MS SQL Server 2008 Schema Setup:
CREATE TABLE dbo.users(
Id INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
user_id VARCHAR(20),
first_name VARCHAR(20),
last_name VARCHAR(20)
);
GO
DECLARE #NoOfRows INT = 7;
INSERT INTO dbo.users(user_id, first_name, last_name)
SELECT 'User_'+n, 'John_'+n, 'Doe_'+n
FROM(
SELECT REPLACE(STR(ROW_NUMBER()OVER(ORDER BY (SELECT NULL))),' ','0') n FROM(
select TOP(#NoOfRows) 1 x from sys.objects A,sys.objects B,sys.objects C,sys.objects D,sys.objects E,sys.objects F,sys.objects G
)X
)N
Query 1:
SELECT * FROM dbo.users
Results:
| ID | USER_ID | FIRST_NAME | LAST_NAME |
-----------------------------------------------------------
| 1 | User_0000000001 | John_0000000001 | Doe_0000000001 |
| 2 | User_0000000002 | John_0000000002 | Doe_0000000002 |
| 3 | User_0000000003 | John_0000000003 | Doe_0000000003 |
| 4 | User_0000000004 | John_0000000004 | Doe_0000000004 |
| 5 | User_0000000005 | John_0000000005 | Doe_0000000005 |
| 6 | User_0000000006 | John_0000000006 | Doe_0000000006 |
| 7 | User_0000000007 | John_0000000007 | Doe_0000000007 |
Just change the #NoOfRows to 300000 to get the number of rows you are looking for.
I've adapted a script found in this article:
DECLARE #RowCount INT
DECLARE #RowString VARCHAR(14)
DECLARE #First VARCHAR(14)
DECLARE #LAST VARCHAR(14)
DECLARE #ID VARCHAR(14)
SET #ID = 'UserID'
SET #First = 'John'
SET #Last = 'Doe'
SET #RowCount = 1
WHILE #RowCount < 300001
BEGIN
SET #RowString = CAST(#RowCount AS VARCHAR(10))
SET #RowString = REPLICATE('0', 6 - DATALENGTH(#RowString)) + #RowString
INSERT INTO TestTableSize (
UserID
,FirstName
,LastName
)
VALUES
(#ID + #RowString
, #First + #RowString
, #Last + #RowString)
SET #RowCount = #RowCount + 1
END

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