Replace “<” and “>”and "<\" with “<” ,“>” and </ in sql server - 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>

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>

FOR XML PATH : DISTINCT sort cost increased

I'd like to put together only unique values in the concatenated string. My code is currently:
SELECT PITEM2.orderid,
(SELECT ISNULL(E.FIRSTNAME + ' ' + E.LASTNAME,' ') + ', ' AS [text()]
FROM F_PURCHASEITEM PITEM1
LEFT JOIN E__EMPLOYEE E ON e.EMPLOYEEID=PITEM1.APPROVED_BY
WHERE PITEM1.ORDERID = PITEM2.ORDERID
AND PITEM1.PISTATUS =
(SELECT POSTATUSID
FROM F_POSTATUS
WHERE POSTATUSNAME = 'Invoice Received') GROUP By ISNULL(E.FIRSTNAME + ' ' + E.LASTNAME,' ') + ', '
FOR XML PATH ('') ) [EmployeeNames]
FROM F_PURCHASEITEM PITEM2
WHERE ORDERID=305089 Group By PITEM2.orderid
This gives me the output I'd expect, but the cost of the query increased and execution plan shows the Distinct sort as 46.3%.
How can I decrease the cost for this distinct?

Generate XML from SQL issue

I need to generate XML in the following format :
I haven't gone too far with the xml part of the task as I encountered following situation, you can tell that this obviously was not my intention.
How can I handle this properly considering that BBAN and IBAN need to be inside AccountNoas well as that I want it formatted according to the first picture.
The complete query along with my fair attempt of generating xml looks like this:
DECLARE #AccountType NVARCHAR(3);
DECLARE #kodBanke NVARCHAR(3);
SET #AccountType = 'T';
SET #kodBanke = ( SELECT vrednost FROM dbini WHERE IDENT = 'KOD' AND SECTION = 'PP' );
WITH Ent_Posta
AS
(
SELECT e.naziv,p.posta,e.sifra
FROM entitet AS e
INNER JOIN poste AS p ON e.sifra = p.entitet
)
SELECT (
SELECT
[dbo].[brojracuna](#kodBanke,i.partija) AS 'BBAN',
[dbo].[GENERATEIBAN](i.partija) AS 'IBAN'
FOR XML PATH('AccountNo'), ELEMENTS, ROOT('Account')
),
#accountType AS 'AccountType',
(a.ime + ' ( ' + a.roditel + ' ) ' + a.prezime) AS 'Name',
a.embg AS 'UID',
CASE status
WHEN 2 THEN 'A'
WHEN 4 THEN 'B'
WHEN 8 THEN 'U'
END AS 'Status',
c.sifra AS 'Territory',
#kodBanke as 'ID_Bank',
REPLACE(CONVERT(VARCHAR(10), i.DOTVaRANJE, 120), '.', '') + '-' + RIGHT( '0' + CONVERT(VARCHAR(2), DATEPART(hh, i.DOTVaRANJE)), 2) + '' + RIGHT('0' + CONVERT(VARCHAR(2), DATEPART(mi, i.DOTVaRANJE)), 2) + '' + RIGHT('0' + CONVERT(VARCHAR(2), DATEPART(s, i.DOTVaRANJE)),2) AS OpeningDate,
REPLACE(CONVERT(VARCHAR(10),'2006.09.28 ', 120), '.', '') + '-' + RIGHT( '0' + CONVERT(VARCHAR(2), DATEPART(hh, '2006.09.28' )), 2) + '' + RIGHT('0' + CONVERT(VARCHAR(2), DATEPART(mi, '2006.09.28 ')), 2) + '' + RIGHT('0' + CONVERT(VARCHAR(2),DATEPART(s,'2006.09.28 ')),2) AS ClosingDate
FROM adresar AS a
INNER JOIN istdden AS i
ON a.embg = i.embg
INNER JOIN Ent_Posta as c
ON a.postbroj = c.posta
FOR XML PATH ('Account'), ROOT('Accounts');
Upon removal of this part I get...
<Accounts>
<Account>
<BBAN>5710543102313248</BBAN>
<IBAN>BA39531231634039248</IBAN>
<AccountType>T</AccountType>
<Name>DARKO ( DRAGAN ) TESIC</Name>
<UID>0000005467234</UID>
<Status>A</Status>
<Territory>1</Territory>
<ID_Bank>571</ID_Bank>
<OpeningDate>20081205-000000</OpeningDate>
<ClosingDate>20060928-000000</ClosingDate>
</Account>
... but now AccountNO is missing.
Your question is not all clear, but - if I get this correctly - you are fighting with 1:1 values, but within some deeper nesting.
You can use an XPath-like expression within [] in connection with FOR XML PATH. Check this out:
SELECT 'blah' AS FirstNode
,'blub' AS [SecondNode/OneDeeper]
,'blib' AS [SecondNode/OneMore]
,'ballaballa' AS [ThirdNode]
FOR XML PATH('row'),ROOT('root');
the resutl (look especially at <SecondNode>:
<root>
<row>
<FirstNode>blah</FirstNode>
<SecondNode>
<OneDeeper>blub</OneDeeper>
<OneMore>blib</OneMore>
</SecondNode>
<ThirdNode>ballaballa</ThirdNode>
</row>
</root>
If this is not what you need, please tag with the actual RDBMS (product and version) and please read How to ask a good SQL question and How to create a MCVE
For your issue it might be enough to use AS [AccountNo/IBAN] in your query.

SQL Server build dynamic sql

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,'')

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