SQL Server build dynamic sql - sql-server

I have a temp table called #temp, and I need to get all the CDate column from that table, to build a string.
The CDate list in that table is (20171209, 20171210....20171223)
I expected to see
'A.[20171209] as [20171209], A.[20171210] as [20171210],
A.[20171211] as [20171211], A.[20171212] as [20171212],
A.[20171213] as [20171213], A.[20171214] as [20171214],
A.[20171215] as [20171215], A.[20171216] as [20171216],
A.[20171217] as [20171217], A.[20171218] as [20171218],
A.[20171219] as [20171219], A.[20171220] as [20171220],
A.[20171221] as [20171221], A.[20171222] as [20171222],
A.[20171223] as [20171223], '
however the result I got is missing the first date , ie 'A.[20171209] as [20171209]'
Here is my code:
SELECT
#col2 = ISNULL(#col2 + 'A.' + QUOTENAME(CDate) + ' as ' + QUOTENAME(CDate) + ', ' , '')
FROM
(SELECT DISTINCT CDate FROM #temp) AS tmp;

Your current approach will not work in some cases, it is an undocumented feature, always use For Xml path to concatenating the rows into csv.
SET #col2 = stuff((SELECT ', A.' + Quotename(CDate) + ' as '
+ Quotename(CDate)
FROM (SELECT DISTINCT CDate
FROM #temp) a
FOR xml path('')),1,1,'')

Related

Encoding a SQL Server SELECT statement for HTML output

I have this SELECT statement that I will be using in a SQL Server 2016 stored procedure:
IF OBJECT_ID('tempdb..#TempTable') IS NOT NULL
DROP Table #TempTable
SELECT DISTINCT
STUFF((SELECT ', '+ CASE WHEN AU1.Color IS NOT NULL THEN +'<b><font color="' + AU1.Color + '">' + AU1.LastName+ ' ' + AU1.Initials + '</font></b>' + CHAR(10) ELSE
AU1.LastName + ' ' + AU1.Initials END AS [text()]
FROM
dbo.[Publication.PubMed.Author] AU1
WHERE
AU1.PMID = 30579772
ORDER BY
AU1.PMID
FOR XML PATH('')), 1, 1, '') AS authorList
INTO
#TempTable
SELECT * FROM #TempTable
And I want to save it with the < and > and when I have this as part of a larger SELECT statement it does but when I pull it out to run on it's own it does not. I have what I through was the answer with the [text()] but that does not help. The code gets put into an Word document as an HTML string and I it to run correctly. Should I store it encoded and worry about decoding on the endusers side? or can I store the html formatted string?
I get
Rodenbach RA, Norton SA, Wittink MN, <b><font color="Blue">Mohile S</font></b>
and I want
Rodenbach RA, Norton SA, Wittink MN, <b><font color="Blue">Mohile S</font></b>
What am I doing wrong? Thanks
Cast the the whole value with markup to xml, don't apply AS [text()].
Demo
select convert(xml, 'my text' + ' <p> my para </p>')
for xml path ('')
result
my text <p> my para </p>

Replace “<” and “>”and "<\" with “<” ,“>” and </ in sql server

I know that Replace < and > with < and > in sql server has been asked at
Replace “<” and “>” with “<” and “>” in sql server
but I need to expand upon it. I am trying to create formatted HTML code from a MS 2016 SQL server.
What I have is:
DECLARE #json nvarchar(max) = (SELECT DISTINCT AU2.PMID,
SUBSTRING(
(
SELECT ', '+ CASE WHEN AU1.Format IS Not Null Then +'<b>' +
AU1.LastName+ ' ' + AU1.Initials + '</' + AU1.Format + '>' ELSE
AU1.LastName + ' ' + AU1.Initials END AS [text()]
FROM dbo.[Publication.PubMed.Author] AU1
WHERE AU1.PMID = AU2.PMID
ORDER BY AU1.PmPubsAuthorID
FOR XML PATH ('')
), 3, 1000) + '. Journal Name ' [Authors]
FROM dbo.[Publication.PubMed.Author] AU2
WHERE AU2.[PMID] =27702896 FOR JSON AUTO)
SELECT #json
And what I get back is:
Name DG, Name K, Name A, Chen FK, Song X, Pirun M, Santiago PM, Kim-Kiselak C, Platt JT, Lee E, Hodges E, <b>Rosebrock AP</b>, Bronson RT, Socci ND, Hannon GJ, Jacks T, Varmus H Journal Name
If I try to put TYPE into the
FOR XML PATH(''), TYPE
I get an error saying:
Argument data type xml is invalid for argument 1 of substring function.
I've tried to add REPLACE
replace(CASE WHEN AU1.Format IS Not Null Then +'<b>' +
AU1.LastName+ ' ' + AU1.Initials + '</b>' ELSE
AU1.LastName + ' ' + AU1.Initials END, '<', '<')
But then I get an error
The xml data type cannot be selected as DISTINCT because it is not comparable.
The best that I can come up with is:
SET #json = replace(#json, '<\', '<')
SET #json = replace(#json, '<', '<')
SET #json = replace(#json, '>', '>')
Just before the final SELECT #json.
I will have over a 1000 records that I need to pull. Do I need to do this is steps?
Based upon TT code I changed mine to
DECLARE #json nvarchar(max) = (SELECT DISTINCT AU2.PMID,
SUBSTRING(
(
SELECT ', '+ CASE WHEN AU1.Format IS Not Null Then +'<b>' +
AU1.LastName+ ' ' + AU1.Initials + '</b>' ELSE
AU1.LastName + ' ' + AU1.Initials END AS [text()]
FROM dbo.[Publication.PubMed.Author] AU1
WHERE AU1.PMID = AU2.PMID
ORDER BY AU1.PmPubsAuthorID
FOR XML PATH (''),TYPE).value('.[1]','NVARCHAR(MAX)'
), 1, 1000) + '. Journal Name ' [Authors]
FROM dbo.[Publication.PubMed.Author] AU2
WHERE AU2.[PMID] =27702896 FOR JSON AUTO)
And that woks fine. but see comment below
As far as I can tell you are on the right track with FOR XML PATH(''), TYPE. It's just that you then have an XML text value which you need to convert to a string (i.e. of type [N]VARCHAR(X)). This can be done with the XML value() method.
An example (fiddle):
CREATE TABLE t(s NVARCHAR(16));
INSERT INTO t(s)VALUES(N'1'),(N'2'),(N'3'),(N'4'),(N'5'),(N'6');
SELECT
(
SELECT N'<b>'+s+N'</b>'
FROM t
FOR XML PATH(''),TYPE
).value('.[1]','NVARCHAR(MAX)');
results in
<b>1</b><b>2</b><b>3</b><b>4</b><b>5</b><b>6</b>

Paginating a parent in SQL Server on a parent/child query

(SQL Server 2012 - Web Edition)
I have a parent/child (one to many) relationship in a query like so:
SELECT a.a, a.b, b.c
FROM tablea INNER JOIN
tableb ON b.pk = a.fk
I have a huge pagination query that encompasses this using the standard (psuedo-code):
WITH C as (SELECT top(#perpage*#pagenum) rowID = row_number() OVER (somefield)),
SELECT c.* FROM C (query) WHERE DT_RowId > (#pagenum-1)*#perpage
The question I have is in this scenario is it possible to paginate off the parent table (a), instead of the entire query? Can I modify my pagination query (not the sql that pulls the query itself) so that when I ask for 10 rows, it gives me 10 rows from the parent, with 'x' number of children attached?
I know I'm not giving the bigger picture here, but the bigger picture is ugly. If need be, we can go there, but it's out there. Here's a small taste of where we're going with this:
IF UPPER(LEFT(#rSQL, 6)) = 'SELECT'
BEGIN
SET #rSQL = 'SELECT * FROM (' + #rSQL + ')' + ' as rTBL';
SET #rSQL = RIGHT(#rSQL, LEN(#rSQL)-7);
IF (LEN(LTRIM(#search)) > 0)
BEGIN
SET #rPaging =
'IF (#schemaonly=1) SET FMTONLY ON;
SELECT #ttlrows = COUNT(*) FROM (SELECT ' + #rSQL + #rWhere + ') AS TBL;
WITH C as (select top(#perpage*#pagenum) DT_RowId = ROW_NUMBER() OVER (' + #rOrder + '), ';
SET #rPaging = #rPaging + #rSQL + #rWhere + ')
SELECT C.*' + #rcols + ', (#perpage-1) * #pagenum as pagenum, #ttlrows as ct, CEILING(#ttlrows / CAST(#perpage AS FLOAT)) as pages
FROM C '+ #query + ' WHERE DT_RowId > (#pagenum-1) * #perpage ';
END
ELSE
BEGIN
SET #rPaging =
'IF (#schemaonly=1) SET FMTONLY ON;
SELECT #ttlrows = COUNT(*) FROM (' + #oSQL + ') AS SUBQUERY;
WITH C as (select top(#perpage*#pagenum) DT_RowId = ROW_NUMBER() OVER (' + #rOrder + '), ';
SET #rPaging = #rPaging + #rSQL + ')
SELECT C.*' + #rcols + ',(#perpage-1) * #pagenum as pagenum, #ttlrows as ct, CEILING(#ttlrows / CAST(#perpage AS FLOAT)) as pages
FROM C '+ #query + ' WHERE DT_RowId > (#pagenum-1) * #perpage ';
END
PRINT #rPaging;
EXECUTE SP_EXECUTESQL #rPaging, #parms, #ttlrows out, #schemaonly, #perpage, #pagenum, #fksiteID, #filter1, #filter2, #filter3, #filter4, #intfilter1, #intfilter2, #intfilter3, #intfilter4, #datefilter1, #datefilter2, #search;
SET FMTONLY OFF;
END
ELSE
BEGIN
SET #rSQL = LTRIM(REPLACE(UPPER(#rSQL), 'EXEC',''));
EXECUTE SP_EXECUTESQL #rSQL, #parms, #ttlrows out, #schemaonly, #perpage, #pagenum, #fksiteID, #filter1, #filter2, #filter3, #filter4, #intfilter1, #intfilter2, #intfilter3, #intfilter4, #datefilter1, #datefilter2;
END
You could do the pagination in a CTE that only gets the parent rows, and then join the child rows in a subsequent CTE or in the main query.
Due to the dynamic way you are using this, this might have to involve building your pagination query from the same building blocks you use to build #query. Without seeing the code that builds #query I can't be much more specific than that.
You could add
,DENSE_RANK() OVER (ORDER BY table_a.primary_key)
This would indirectly provide the same result as
,ROW_NUMBER() OVER(ORDER BY table_a.primary_key)
but the former would be on the final result set instead going back to table a for the latter code snippet.
But please be aware of the disadvantage: any additional ranking function will force an additional sort operation on the result set! This might significantly influence the query performance. If this is the case in your scenario, I'd recommend to follow Tab Allemans solution and use a cte.

Microsoft SQL Server Rows to Column Transpose using PiVOT

I'm using MS-SQLServer-2016 and got a requirement to transpose rows to columns.
I'm using Pivot and dynamic SQL option to do it because the number of rows is dynamic.
Figure1 is the output I'm currently getting. However the client doesn't want those NULLs displayed. He only wants the Not-Null dates to be displayed.
Is there way to get rid of those Null Values and display only distinct dates?
Figure1-Transpose_Output
With Regards,
Tanuja
DECLARE #columns AS NVARCHAR(MAX), #sql AS NVARCHAR(MAX), #var1 AS
VARCHAR(MAX);
SELECT #columns = stuff((select DISTINCT ',' + quotename(replace(replace(replace(n.action_note,' ','<>'),'><',''),'<>',' ') )
from engagement_action n, action_party m, personal p
where n.action_id = m.action_id
and p.party_id = m.party_id
and n.action_note like 'XXX'
and m.system_name = 'XXXXXXXXXXXX'
and p.customer_number = 'XXXXXXX' FOR XML PATH(''),TYPE).value('.','NVARCHAR(MAX)'),1,1,'')
SELECT #sql =
'select "RANK_IN_PROP" ,
customer_number,
customer_shortname,
system_name,
'+ #columns + '
from
(SELECT RANK() OVER (PARTITION BY convert(date,m.created_when) ORDER BY convert(date,m.created_when))"RANK_IN_PROP" ,
p.customer_number,
p.customer_shortname,
m.system_name,
m.created_when ,
convert(date,m.created_when) as created_when,
replace(replace(replace(n.action_note,'' '',''<>''),''><'',''''),''<>'','' '') as action_note1
FROM engagement_action n, action_party m, personal p
WHERE n.action_id = m.action_id
AND p.party_id = m.party_id
AND n.action_note like ''%XXX%''
AND m.system_name = ''XXXXXXXXXXX''
AND p.customer_number = ''XXXXXXXX'' ) d
PIVOT
(max(created_when) for action_note1 in ( ' + #columns + ' ))p order by created_when desc'
execute(#sql);`
Can you try this , just added (select distinct action_note engagement_action where action_note is not null) in where clause. As i can't create test data so could not really execute the query
SELECT #columns = stuff((select DISTINCT ',' +
quotename(replace(replace(replace(n.action_note,' ','<>'),'><',''),'<>',' ')
)
from
(select distinct action_note engagement_action where action_note is not null)
n, action_party m, personal p
where n.action_id = m.action_id
and p.party_id = m.party_id
and n.action_note like 'XXX'
and m.system_name = 'XXXXXXXXXXXX'
and p.customer_number = 'XXXXXXX' FOR XML PATH(''),TYPE).value('.','NVARCHAR(MAX)'),1,1,'')

Not able to remove first comma in string SQL Server

The code works fine except for
SELECT DISTINCT isnull(#FEATURE + ', ', ',') + Feature
FROM [128.100.194.219, 1435].[EMSData].[dbo].[vOSLRoomFeatures] as rf2 where (rf2.roomid = rf.roomid)
for xml path('')),
which is giving me problems. I do not know how to get rid of the first comma. I have tried substring but it removes all the commas(I guess since it's in a select statement). I even tried
COALESCE(#FEATURE + ', ', '') + FEATURE but I end up with the same result, either no commas or one extra comma at the end or at the very beginning.
DECLARE #FEATURE VARCHAR(500)
-- INSERT INTO BookableRooms IF NOT EXISTS ROOM NUMBER
INSERT INTO dbo.BookableRooms_test (FK_Building_code,
Room_num,Other_room_name,
Capacity_from,
Capacity_to,
Accessiblity,AV_book_separate,Flooring_type,Features,
Food_drink_allowed, Alcohol_allowed,Internet,
[Owner],FK_BookingContact_ID,
LCD_projector,Computer,FK_SpaceManager_code,Last_updated_date,Last_updated_by,SpecialFlag)
SELECT DISTINCT CASE
WHEN rf.[Building Reference] is null or rf.[Building Reference] = '' THEN 'HH'
ELSE rf.[Building Reference]
END,
[ROOMID],[Description],
(SELECT MIN(rf2.CAPACITY) FROM [128.100.194.219, 1435].[EMSData].[dbo].[vOSLRoomFeatures] AS rf2 WHERE rf2.ROOMID = rf.ROOMID),
(SELECT MAX(rf2.CAPACITY) FROM [128.100.194.219, 1435].[EMSData].[dbo].[vOSLRoomFeatures] AS rf2 WHERE rf2.ROOMID = rf.ROOMID),
dbo.iszero([Wheelchair Accessible]), dbo.iszero(rf.[Separate AV]),dbo.isflat(rf.[Flat Floor]),
(
SELECT DISTINCT isnull(#FEATURE + ', ', ',') + Feature
FROM [128.100.194.219, 1435].[EMSData].[dbo].[vOSLRoomFeatures] as rf2 where (rf2.roomid = rf.roomid)
for xml path('')),
dbo.iszero(rf.[Food and Drink]),dbo.iszero(rf.[Alcohol]),dbo.iszero(rf.[Room Internet]),
'HH',5,
dbo.iszero(rf.[Digital Projector]),dbo.iszero(rf.[Computer]),'HH',GetDate(),'System',dbo.iszero(rf.[Restricted])
FROM [128.100.194.219, 1435].[EMSData].[dbo].[vOSLRoomFeatures] as rf where NOT EXISTS(
SELECT 1 FROM dbo.BookableRooms_test b WHERE
b.Room_num = rf.ROOMID);
Use Stuff but on the outer side of subquery:
stuff ((SELECT DISTINCT ',' + Feature
FROM [128.100.194.219, 1435].[EMSData].[dbo].[vOSLRoomFeatures] as rf2
WHERE (rf2.roomid = rf.roomid)
for xml path('')), 1, 1, '')
Use the STUFF function to remove the leading comma.
SELECT DISTINCT STUFF(',' + Feature
FROM [128.100.194.219, 1435].[EMSData].[dbo].[vOSLRoomFeatures] as rf2 where (rf2.roomid = rf.roomid)
for xml path('')),1,1,''),
I am not sure what you are trying to achieve. If my guess was wrong, it would good if you told us what results you expect in which situation.
Try this
CASE WHEN #FEATURE IS NULL THEN NULL ELSE #FEATURE + ', ' END

Resources