Transact sql (2012) Using #xml.modify to insert 'elements using a variable - sql-server

I need to add an element using a variable
This works --
declare #XML xml = '
<DWDocument>
<FileInfos>
<ImageInfos>
<ImageInfo id="0,0,0" nPages="0">
<FileInfo fileName="9b7b36ac-c705-49ba-bf91-a952bdb44576.eml" dwFileName="f0.eml" type="normal" length="0" />
</ImageInfo>
<ImageInfo id="1,0,0" nPages="0">
<FileInfo fileName="Response to Deficiency Letter.docx" dwFileName="f1.docx" type="normal" length="0" />
</ImageInfo>
</ImageInfos>
</FileInfos>
</DWDocument>
'
SET #xml.modify ('insert <ImageInfo id="2,0,0" nPages="0"></ImageInfo>
as last into (DWDocument/FileInfos/ImageInfos)[1]')
Gives me:
<ImageInfo id="2,0,0" nPages="0" /><ImageInfo>
BUT...
I need the '2' to be a variable
I tried:
declare #XML xml = '
<DWDocument>
<FileInfos>
<ImageInfos>
<ImageInfo id="0,0,0" nPages="0">
<FileInfo fileName="9b7b36ac-c705-49ba-bf91-a952bdb44576.eml" dwFileName="f0.eml" type="normal" length="0" />
</ImageInfo>
<ImageInfo id="1,0,0" nPages="0">
<FileInfo fileName="Response to Deficiency Letter.docx" dwFileName="f1.docx" type="normal" length="0" />
</ImageInfo>
</ImageInfos>
</FileInfos>
</DWDocument>
'
declare #ImageInfo_ID nvarchar(50) = '"2,0,0"'
declare #ImageInfo_nPages nvarchar(50) = '"0"'
SET #xml.modify ('insert <ImageInfo id={sql:variable("#ImageInfo_ID")}></ImageInfo>
as last into (DWDocument/FileInfos/ImageInfos)[1]')
gives me the error:
Msg 2225, Level 16, State 1, Line 46
XQuery [modify()]: A string literal was expected
SET #xml.modify ('insert <ImageInfo id{sql:variable("#ImageInfo_ID")}></ImageInfo>
as last into (DWDocument/FileInfos/ImageInfos)[1]')
gives me the error
Msg 2205, Level 16, State 1, Line 48
XQuery [modify()]: "=" was expected.
SET #xml.modify ('insert <ImageInfo>{sql:variable("#ImageInfo_ID")}</ImageInfo>
as last into (DWDocument/FileInfos/ImageInfos)[1]')
has no error but the data is wrong, gives me
<ImageInfo>"2,0,0" nPages="0"</ImageInfo>
the 'id=' is missing
How do I specify the attribute name? id=#ImageInfo_ID?
What I REALLY NEED is
<ImageInfo id=#ImageInfo_ID nPages=#ImageInfo_nPages></ImageInfo>
to get to
<ImageInfo id="2,0,0" nPages="0"></ImageInfo>
What am I missing?

To specify the attribute name and values using variables in the XQuery expression of the modify method, you can use the sql:variable function to concatenate the attribute name and value as a string. Here's an example that should work for you:
DECLARE #ImageInfo_ID NVARCHAR(50) = '2,0,0'
DECLARE #ImageInfo_nPages NVARCHAR(50) = '0'
SET #xml.modify('
insert <ImageInfo id={sql:variable("#ImageInfo_ID")} nPages={sql:variable("#ImageInfo_nPages")}></ImageInfo>
as last into (DWDocument/FileInfos/ImageInfos)[1]'
)

Please try the following solution.
It is using XQuery FLWOR expression to compose needed XML.
SQL
DECLARE #xml XML =
N'<DWDocument>
<FileInfos>
<ImageInfos>
<ImageInfo id="0,0,0" nPages="0">
<FileInfo fileName="9b7b36ac-c705-49ba-bf91-a952bdb44576.eml" dwFileName="f0.eml" type="normal" length="0"/>
</ImageInfo>
<ImageInfo id="1,0,0" nPages="0">
<FileInfo fileName="Response to Deficiency Letter.docx" dwFileName="f1.docx" type="normal" length="0"/>
</ImageInfo>
</ImageInfos>
</FileInfos>
</DWDocument>';
DECLARE #ImageInfo_ID NVARCHAR(50) = '2,0,0';
DECLARE #ImageInfo_nPages NVARCHAR(50) = '0';
SET #xml = #xml.query('<DWDocument><FileInfos><ImageInfos>
{
for $x in //DWDocument/FileInfos/ImageInfos
return if ($x[position() lt last()]) then $x
else $x, <ImageInfo id="{sql:variable("#ImageInfo_ID")}" nPages="{sql:variable("#ImageInfo_nPages")}"></ImageInfo>
}
</ImageInfos></FileInfos></DWDocument>');
-- test
SELECT #xml;
Output
<DWDocument>
<FileInfos>
<ImageInfos>
<ImageInfos>
<ImageInfo id="0,0,0" nPages="0">
<FileInfo fileName="9b7b36ac-c705-49ba-bf91-a952bdb44576.eml" dwFileName="f0.eml" type="normal" length="0" />
</ImageInfo>
<ImageInfo id="1,0,0" nPages="0">
<FileInfo fileName="Response to Deficiency Letter.docx" dwFileName="f1.docx" type="normal" length="0" />
</ImageInfo>
</ImageInfos>
<ImageInfo id="2,0,0" nPages="0" />
</ImageInfos>
</FileInfos>
</DWDocument>

Related

Update multiple substrings within a string

I have a single text string stored in a SQL table which contains all of the text below. The format is XML but the field definition is varchar.
I am using SQL Server 2012 to query this data:
<?xml version="1.0" encoding="utf-16"?>
<SaveFileContext xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Mappings>
<SaveFileModel Header="Model1" FullPath="Model1" ViewType="ModelView" />
<SaveFileModel Header="xyz" FullPath="\\server\directory\" ViewType="TradeView" />
<SaveFileModel Header="Model2" FullPath="Model2" ViewType="ModelView" />
<SaveFileModel Header="Model3" FullPath="Model3" ViewType="ModelView" />
<SaveFileModel Header="abc" FullPath="\\server\directory\" ViewType="TradeView" />
<SaveFileModel Header="def" FullPath="\\server\directory\" ViewType="TradeView" />
<SaveFileModel Header="ghi" FullPath="\\server\directory\" ViewType="TradeView"/>
</Mappings>
</SaveFileContext>
How can I update or remove the entire lines of text where viewtype="ModelView"?
I want to remove any lines where viewtype="ModelView" within this single string and replace it with a blank space. In the example above I want to remove 3 lines total and leave the rest.
In the end I want the string to look like below (keep in mind all lines are contained in 1 single string. I just separated them to make viewing them easier.
<?xml version="1.0" encoding="utf-16"?>
<SaveFileContext xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Mappings>
<SaveFileModel Header="xyz" FullPath="\\server\directory\" ViewType="TradeView" />
<SaveFileModel Header="abc" FullPath="\\server\directory\" ViewType="TradeView" />
<SaveFileModel Header="def" FullPath="\\server\directory\" ViewType="TradeView" />
<SaveFileModel Header="ghi" FullPath="\\server\directory\" ViewType="TradeView"/>
</Mappings>
</SaveFileContext>
This is my current query that I am using to replace the lines but the values to replace are very specific. I'm basically entering the string to look for to replace.
IF OBJECT_ID('tempdb..#replacement') IS NOT NULL
DROP TABLE #replacement
CREATE TABLE #replacement (
string_pattern VARCHAR(100),
string_replacement VARCHAR(5)
);
INSERT INTO #replacement (
string_pattern,
string_replacement
)
VALUES
('<SaveFileModel Header="Model1" FullPath="Model1" ViewType="ModelView" />', ''),
('<SaveFileModel Header="Model2" FullPath="Model2" ViewType="ModelView" />', ''),
('<SaveFileModel Header="Model3" FullPath="Model3" ViewType="ModelView" />', ''),
('<SaveFileModel Header="Model4" FullPath="Model4" ViewType="ModelView" />', ''),
('<SaveFileModel Header="Model5" FullPath="Model5" ViewType="ModelView" />', ''),
('<SaveFileModel Header="Model6" FullPath="Model6" ViewType="ModelView" />', ''),
('<SaveFileModel Header="Model7" FullPath="Model7" ViewType="ModelView" />', ''),
('<SaveFileModel Header="Model8" FullPath="Model8" ViewType="ModelView" />', ''),
('<SaveFileModel Header="Model9" FullPath="Model9" ViewType="ModelView" />', ''),
('<SaveFileModel Header="Model10" FullPath="Model10" ViewType="ModelView" />', ''),
('<SaveFileModel Header="Model11" FullPath="Model11" ViewType="ModelView" />', ''),
('<SaveFileModel Header="Model12" FullPath="Model12" ViewType="ModelView" />', ''),
('<SaveFileModel Header="Model13" FullPath="Model13" ViewType="ModelView" />', ''),
('<SaveFileModel Header="Model14" FullPath="Model14" ViewType="ModelView" />', ''),
('<SaveFileModel Header="Model15" FullPath="Model15" ViewType="ModelView" />', ''),
('<SaveFileModel Header="Model16" FullPath="Model16" ViewType="ModelView" />', ''),
('<SaveFileModel Header="Model17" FullPath="Model17" ViewType="ModelView" />', ''),
('<SaveFileModel Header="Model18" FullPath="Model18" ViewType="ModelView" />', ''),
('<SaveFileModel Header="Model19" FullPath="Model19" ViewType="ModelView" />', ''),
('<SaveFileModel Header="Model20" FullPath="Model20" ViewType="ModelView" />', '');
DECLARE #string AS VARCHAR(MAX),
#userident varchar(20);
DECLARE userviewdef CURSOR FOR
SELECT
UserID
FROM
TableSettings where section = 'user view session'
OPEN userviewdef;
FETCH NEXT FROM userviewdef INTO
#userident;
WHILE ##FETCH_STATUS = 0
BEGIN
select #string = varcharvalue from tablesettings where section = 'user view session' and userid = #userident
-- Perform all replacements
SELECT #string = REPLACE(#string, string_pattern, string_replacement) FROM #replacement;
-- Return new string
--PRINT #string;
update tablesettings
set varcharvalue = #string
where section = 'user view session' and userid = #userident
FETCH NEXT FROM userviewdef INTO
#userident;
END;
CLOSE userviewdef;
DEALLOCATE userviewdef;
There are instances where a string could be what is seen below and it would not get removed since it doesn't fit any of the strings I coded to be removed. I want to find an easy way to remove any lines where ViewType="ModelView" since this is my criteria.
<SaveFileModel Header="ThisIsSomethingElse" FullPath="Model1" ViewType="ModelView" />
4/21/21:
After following the advice of #FrankPl to use XML here is what I came up with. The result returns a blank space. I might be coding the XML query piece incorrectly and need a bit of help:
DECLARE #stringXML XML,
#finalString varchar(max),
#userident varchar(20);
DECLARE userviewdef CURSOR FOR
SELECT
UserID
FROM
TableSettings where section = 'user view session';
OPEN userviewdef;
FETCH NEXT FROM userviewdef INTO
#userident;
WHILE ##FETCH_STATUS = 0
BEGIN
select #stringXML = varcharvalue from tablesettings where section = 'user view session' and userid = #userident
select #stringXML.query('
for $item in (/SaveFileContext/Mappings/SaveFileModel)
return if ($item[#ViewType = "ModelView"]) then string($item) else ""
')
select #finalString = convert(varchar(max), #stringXML)
-- Return new string
PRINT #finalstring;
FETCH NEXT FROM userviewdef INTO
#userident;
END;
CLOSE userviewdef;
DEALLOCATE userviewdef;
If you declare your #step variable as data type XML instead of varchar, you can use XQuery to process the data, in this case a FLOWR expression in curly braces within literal XML elements, the curly braces switch from literal mode to XPath mode:
SELECT #string.query('
<SaveFileContext>
<Mappings> {
for $item in (/SaveFileContext/Mappings/SaveFileModel)
return if ($item[#ViewType = "ModelView"]) then $item else ()
} </Mappings>
</SaveFileContext>
'
The XML declaration and the namespaces are swallowed by the SQLServer XML processor.
This solution assumes the data are valid XML fragments.
Please note that - as the whole query needs to be a SQL string (i. e. in single quotes), and XQuery accepts strings in double as well as in single quotes, for simplicity, I used double quotes here. Alternatively, I could have used doubled single quotes to escape them within the SQL string.

SQL XML - Create a XML file from SQL Server for an invoice including invoice positions in one XML file

I create my xml file in this way (I do not show all output fields because there are very many fields):
DECLARE #ID_Rechnung int = 8;
WITH XMLNAMESPACES (
'urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2' as ext,
'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2' as cbc,
'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2' as cac,
'http://uri.etsi.org/01903/v1.3.2#' as xades,
'http://www.w3.org/2001/XMLSchema-instance' as xsi,
'http://www.w3.org/2000/09/xmldsig#' as ds
)
SELECT
#XMLData = xmldat.xmldataCol
FROM
(
SELECT
(
SELECT
-- HIER XML Daten generieren
'' AS 'ext:UBLExtensions',
'' AS 'ext:UBLExtensions/ext:UBLExtension',
'' AS 'ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent',
'2.1' AS 'cbc:UBLVersionID',
'TR1.2' AS 'cbc:CustomizationID',
'' AS 'cbc:ProfileID',
Rechnungen.Nummer AS 'cbc:ID',
'false' AS 'cbc:CopyIndicator',
'' AS 'cbc:UUID',
CAST(Rechnungen.Datum AS Date) AS 'cbc:IssueDate'
FROM
rechnungen
WHERE
rechnungen.id = #ID_Rechnung
FOR XML PATH(''), ROOT('Invoice')
) AS xmldataCol
This works fine - i get the following XML:
<Invoice xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2">
<ext:UBLExtensions>
<ext:UBLExtension>
<ext:ExtensionContent />
</ext:UBLExtension>
</ext:UBLExtensions>
<cbc:UBLVersionID>2.1</cbc:UBLVersionID>
<cbc:CustomizationID>TR1.2</cbc:CustomizationID>
<cbc:ProfileID />
<cbc:ID>R200001</cbc:ID>
<cbc:CopyIndicator>false</cbc:CopyIndicator>
<cbc:UUID />
<cbc:IssueDate>2020-06-29</cbc:IssueDate>
</Invoice>
But now i need the invoice positions in the same file.
This SQL should be included in the first one and the date should be as invoice line in the xml file:
SELECT
Rechnungpos.ID AS 'cac:InvoiceLine/cbc:ID',
Rechnungpos.Anzahl AS 'cac:InvoiceLine/cbc:InvoicedQuantity'
FROM
RechnungPos
WHERE
RechnungPos.id_Rechnung = #ID_Rechnung
The output should be this:
<Invoice xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2">
<ext:UBLExtensions>
<ext:UBLExtension>
<ext:ExtensionContent />
</ext:UBLExtension>
</ext:UBLExtensions>
<cbc:UBLVersionID>2.1</cbc:UBLVersionID>
<cbc:CustomizationID>TR1.2</cbc:CustomizationID>
<cbc:ProfileID />
<cbc:ID>R200001</cbc:ID>
<cbc:CopyIndicator>false</cbc:CopyIndicator>
<cbc:UUID />
<cbc:IssueDate>2020-06-29</cbc:IssueDate>
<cac:InvoiceLine>
<cbc:ID>1<(cbc:>
<cbc:InvoicedQuantity>3</cbc:InvoicedQuantity>
</cac:InvoiceLine>
<cac:InvoiceLine>
<cbc:ID>5<(cbc:>
<cbc:InvoicedQuantity>1</cbc:InvoicedQuantity>
</cac:InvoiceLine>
<cac:InvoiceLine>
<cbc:ID>9<(cbc:>
<cbc:InvoicedQuantity>2</cbc:InvoicedQuantity>
</cac:InvoiceLine>
</Invoice>
Here is the Code to generate Test Data:
CREATE TABLE [dbo].[Rechnungen](
[id] [int] NOT NULL,
[Nummer] [nvarchar](20) NOT NULL,
[Datum] [datetime] NOT NULL
)
INSERT INTO Rechnungen (id, Nummer, Datum) VALUES (8, 'R200001', '29.06.2020')
CREATE TABLE [dbo].Rechnungpos(
[id] [int] NOT NULL,
[id_Rechnung] [int] NOT NULL,
[Anzahl] [float] NOT NULL
)
INSERT INTO RechnungPos (id, id_Rechnung, Anzahl) VALUES (1, 8, 3)
INSERT INTO RechnungPos (id, id_Rechnung, Anzahl) VALUES (5, 8, 1)
INSERT INTO RechnungPos (id, id_Rechnung, Anzahl) VALUES (9, 8, 2)
it has to run on different versions - my version is SQL Server 2019
How can i do that?
Thanks for help, Thomas.
Here is how to do it.
The only complexity is how to handle a child table and specially namespaces in the output XML. That's why XQuery and its FLWOR expression are in use.
SQL
-- DDL and sample data population, start
DECLARE #Rechnungen TABLE (id int , Nummer nvarchar(20), Datum datetime);
INSERT INTO #Rechnungen (id, Nummer, Datum) VALUES
(8, 'R200001', '2020-06-29');
DECLARE #Rechnungpos TABLE (id int, id_Rechnung int, Anzahl float);
INSERT INTO #RechnungPos (id, id_Rechnung, Anzahl) VALUES
(1, 8, 3),
(5, 8, 1),
(9, 8, 2);
-- DDL and sample data population, end
DECLARE #ID_Rechnung int = 8;
;WITH XMLNAMESPACES ('urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2' as ext
, 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2' as cbc
, 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2' as cac
, 'http://uri.etsi.org/01903/v1.3.2#' as xades
, 'http://www.w3.org/2001/XMLSchema-instance' as xsi
, 'http://www.w3.org/2000/09/xmldsig#' as ds)
SELECT (
SELECT '2.1' AS [cbc:UBLVersionID],
'TR1.2' AS [cbc:CustomizationID],
'' AS [cbc:ProfileID],
p.Nummer AS [cbc:ID],
'false' AS [cbc:CopyIndicator],
'' AS [cbc:UUID],
CAST(p.Datum AS Date) AS [cbc:IssueDate],
(
SELECT c.id AS [cbc:ID]
, CAST(c.Anzahl AS INT) AS [cbc:InvoicedQuantity]
FROM #Rechnungpos AS c INNER JOIN
#Rechnungen AS p ON p.id = c.id_Rechnung
FOR XML PATH('r'), TYPE, ROOT('root')
)
FROM #Rechnungen AS p
WHERE p.id = #ID_Rechnung
FOR XML PATH(''), TYPE, ROOT('Invoice')
).query('<Invoice xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xades="http://uri.etsi.org/01903/v1.3.2#"
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2">
<ext:UBLExtensions>
<ext:UBLExtension>
<ext:ExtensionContent/>
</ext:UBLExtension>
</ext:UBLExtensions>
{
for $x in /Invoice/*[local-name()!="root"]
return $x,
for $x in /Invoice/root/r
return <cac:InvoiceLine>{$x/*}</cac:InvoiceLine>
}
</Invoice>');
Output
<Invoice xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2">
<ext:UBLExtensions>
<ext:UBLExtension>
<ext:ExtensionContent />
</ext:UBLExtension>
</ext:UBLExtensions>
<cbc:UBLVersionID>2.1</cbc:UBLVersionID>
<cbc:CustomizationID>TR1.2</cbc:CustomizationID>
<cbc:ProfileID />
<cbc:ID>R200001</cbc:ID>
<cbc:CopyIndicator>false</cbc:CopyIndicator>
<cbc:UUID />
<cbc:IssueDate>2020-06-29</cbc:IssueDate>
<cac:InvoiceLine>
<cbc:ID>1</cbc:ID>
<cbc:InvoicedQuantity>3</cbc:InvoicedQuantity>
</cac:InvoiceLine>
<cac:InvoiceLine>
<cbc:ID>5</cbc:ID>
<cbc:InvoicedQuantity>1</cbc:InvoicedQuantity>
</cac:InvoiceLine>
<cac:InvoiceLine>
<cbc:ID>9</cbc:ID>
<cbc:InvoicedQuantity>2</cbc:InvoicedQuantity>
</cac:InvoiceLine>
</Invoice>
Thanks, Yitzhak Khabinsky for help - heres the complete solution:
DECLARE #ID_Rechnung int = 8,
#XMLData xml;
WITH XMLNAMESPACES ('urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2' as ext
, 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2' as cbc
, 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2' as cac
, 'http://uri.etsi.org/01903/v1.3.2#' as xades
, 'http://www.w3.org/2001/XMLSchema-instance' as xsi
, 'http://www.w3.org/2000/09/xmldsig#' as ds)
SELECT
#XMLData = xmldat.xmldataCol
FROM
(
SELECT (
SELECT
-- HIER XML Daten generieren
'' AS 'ext:UBLExtensions',
'' AS 'ext:UBLExtensions/ext:UBLExtension',
'' AS 'ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent',
'2.1' AS 'cbc:UBLVersionID',
'TR1.2' AS 'cbc:CustomizationID',
'' AS 'cbc:ProfileID',
Rechnungen.Nummer AS 'cbc:ID',
'false' AS 'cbc:CopyIndicator',
'' AS 'cbc:UUID',
CAST(Rechnungen.Datum AS Date) AS 'cbc:IssueDate',
'' AS 'cbc:InvoiceTypeCode',
Rechnungen.Bemerkung1 AS 'cbc:Note',
#Waehrung AS 'cbc:DocumentCurrencyCode',
#Waehrung AS 'cbc:TaxCurrencyCode',
Rechnungen.Auftrag AS 'cac:OrderReference/cbc:ID',
-- Verkaüfer
'' AS 'cac:AccountingSupplierParty/cac:Party/cbc:EndpointID',
'' AS 'cac:AccountingSupplierParty/cac:Party/cac:PartyIdentification/cbc:ID',
'' AS 'cac:AccountingSupplierParty/cac:Party/cac:PartyName/cbc:Name',
'' AS 'cac:AccountingSupplierParty/cac:Party/cac:PostalAddress/cbc:StreetName',
'' AS 'cac:AccountingSupplierParty/cac:Party/cac:PostalAddress/cbc:CityName',
'' AS 'cac:AccountingSupplierParty/cac:Party/cac:PostalAddress/cbc:PostalZone',
'' AS 'cac:AccountingSupplierParty/cac:Party/cac:PostalAddress/cac:Country/cbc:IdentificationCode',
'' AS 'cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cbc:CompanyId',
'VAT' AS 'cac:AccountingSupplierParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:ID',
'' AS 'cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity/cbc:RegistrationName',
'' AS 'cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity/cbc:CompanyID',
'' AS 'cac:AccountingSupplierParty/cac:Party/cac:PartyLegalEntity/cbc:CompanyLegalForm',
'' AS 'cac:AccountingSupplierParty/cac:Party/cac:Contact/cbc:Name',
'' AS 'cac:AccountingSupplierParty/cac:Party/cac:Contact/cbc:Telephone',
'' AS 'cac:AccountingSupplierParty/cac:Party/cac:Contact/cbc:ElectronicMail',
-- Käufer
'' AS 'cac:AccountingCustomerParty/cac:Party/cbc:EndpointID',
Rechnungen.DebKreNr AS 'cac:AccountingCustomerParty/cac:Party/cac:PartyIdentification/cbc:ID',
Rechnungen.DebBez01 + ' ' + DebBez02 AS 'cac:AccountingCustomerParty/cac:Party/cac:PartyName/cbc:Name',
Rechnungen.DebStrasse AS 'cac:AccountingCustomerParty/cac:Party/cac:PostalAddress/cbc:StreetName',
Rechnungen.DebOrt AS 'cac:AccountingCustomerParty/cac:Party/cac:PostalAddress/cbc:CityName',
Rechnungen.DebPLZ AS 'cac:AccountingCustomerParty/cac:Party/cac:PostalAddress/cbc:PostalZone',
Rechnungen.DebLandKFZ AS 'cac:AccountingCustomerParty/cac:Party/cac:PostalAddress/cac:Country/cbc:IdentificationCode',
Rechnungen.DebUMSTID AS 'cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cbc:CompanyID',
'VAT' AS 'cac:AccountingCustomerParty/cac:Party/cac:PartyTaxScheme/cac:TaxScheme/cbc:ID',
Rechnungen.DebBez01 + ' ' + DebBez02 AS 'cac:AccountingCustomerParty/cac:Party/cac:PartyLegalEntity/cbc:RegistrationName',
'' AS 'cac:AccountingCustomerParty/cac:Party/cac:Contact/cbc:Name',
'' AS 'cac:AccountingCustomerParty/cac:Party/cac:Contact/cbc:Telephone',
'' AS 'cac:AccountingCustomerParty/cac:Party/cac:Contact/cbc:ElectronicMail',
-- Kontoverbindung Verkäufer
'' AS 'cac:PaymentMeans/cbc:PaymentMeansCode',
'' AS 'cac:PaymentMeans/cac:PayeeFinancialAccount/cbc:ID',
'' AS 'cac:PaymentMeans/cac:PayeeFinancialAccount/cbc:Name',
'' AS 'cac:PaymentMeans/cac:PayeeFinancialAccount/cac:FinancialInstitutionBranch/cbc:ID',
--'' AS 'cac:PaymentTerms/cbc:Note',
-- Steuern
#Waehrung AS 'cac:TaxTotal/cbc_TaxAmount/#currencyID',
CAST(Rechnungen.BetragMWST AS nvarchar(15)) AS 'cac:TaxTotal/cbc_TaxAmount',
#Waehrung AS 'cac:TaxTotal/cac:Taxubtotal/cbc:TaxableAmount/#currencyID',
CAST(Rechnungen.BetragNetto AS nvarchar(15))AS 'cac:TaxTotal/cac:Taxubtotal/cbc:TaxableAmount',
#Waehrung AS 'cac:TaxTotal/cac:Taxubtotal/cbc:TaxAmount/#currencyID',
CAST(Rechnungen.BetragMWST AS nvarchar(15))AS 'cac:TaxTotal/cac:Taxubtotal/cbc:TaxAmount',
'' AS 'cac:TaxTotal/cac:Taxubtotal/cac:TaxCategory/cbc:ID',
CAST(Rechnungen.MWST AS nvarchar(2)) AS 'cac:TaxTotal/cac:Taxubtotal/cac:TaxCategory/cbc:Percent',
'VAT' AS 'cac:TaxTotal/cac:Taxubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID',
#Waehrung AS 'cac:LegalMonetaryTotal/cbc:LineExtensionAmount/#currencyID',
CAST(Rechnungen.BetragNetto AS nvarchar(15))AS 'cac:LegalMonetaryTotal/cbc:LineExtensionAmount',
#Waehrung AS 'cac:LegalMonetaryTotal/cbc:TaxExclusiveAmount/#currencyID',
CAST(Rechnungen.BetragNetto AS nvarchar(15))AS 'cac:LegalMonetaryTotal/cbc:TaxExclusiveAmount',
#Waehrung AS 'cac:LegalMonetaryTotal/cbc:TaxInclusiveAmount/#currencyID',
CAST(Rechnungen.BetragBrutto AS nvarchar(15))AS 'cac:LegalMonetaryTotal/cbc:TaxInclusiveAmount',
#Waehrung AS 'cac:LegalMonetaryTotal/cbc:PayableAmount/#currencyID',
CAST(Rechnungen.BetragBrutto AS nvarchar(15))AS 'cac:LegalMonetaryTotal/cbc:PayableAmount',
(
SELECT Rechnungpos.id AS [cbc:ID]
, CAST(Rechnungpos.Anzahl AS INT) AS [cbc:InvoicedQuantity]
FROM Rechnungpos WHERE RechnungPos.id_Rechnung = #id_Rechnung
FOR XML PATH('r'), TYPE, ROOT('root')
)
FROM Rechnungen
WHERE Rechnungen.id = #ID_Rechnung
FOR XML PATH(''), TYPE, ROOT('Invoice')
) AS xmldataCol
) AS xmldat;
SELECT #XMLData
.query('<Invoice xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xades="http://uri.etsi.org/01903/v1.3.2#"
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2">
{
for $x in /Invoice/*[local-name()!="root"]
return $x,
for $x in /Invoice/root/r
return <cac:InvoiceLine>{$x/*}</cac:InvoiceLine>
}
</Invoice>');

SQL Server: Facing problem to parse nested xml element by XQuery

My xml has 4 elements called Sheet, Group, Lineitem and BM
1) there could be multiple Sheet elements but sheet elements will not be nested.
2) Group will be child element of sheet element and Group can be nested means a group can have another child group or many nested child group.
3) Lineitem will be child element of Group element and Lineitem will not be nested.
2) BM will be child element of Lineitem element but BM element will not be nested.
i have a nested xml which i try to parse by xquery to insert data into table one by one. i store the nested element as Parent Child relationship in xml.
here is table structure
CREATE TABLE [dbo].[tblCSM_Details](
[CSM_ID] [int] NOT NULL,
[ID] [int] IDENTITY(1,1) NOT NULL,
[ParentID] [int] NULL,
[Type] [varchar](30) NULL,
[DisplayInCSM] [varchar](200) NULL,
[FontName] [varchar](max) NULL,
[FontStyle] [varchar](max) NULL,
[FontSize] [varchar](max) NULL,
[UnderLine] [varchar](max) NULL,
[BGColor] [varchar](max) NULL,
[LineItemID] [int] NULL,
[BMID] [int] NULL,
[ColOrder] [int] NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
Parent-child relation is maintained in table by the fields called ID and ParentID
My full code to parse nested element in xml.
DECLARE #XMLData XML=N'<Nodes>
<Sheet FontName="" FontStyle="" FontSize="" UnderLine="false" BGColor="" NodeText="Model1">
<Group FontName="" FontStyle="" FontSize="" UnderLine="false" BGColor="" NodeText="Consensus Model">
<LineItem FontName="" FontStyle="" FontSize="" UnderLine="false" BGColor="" LineItemID="1225" NodeText="Net Revenue" />
<LineItem FontName="" FontStyle="" FontSize="" UnderLine="false" BGColor="" LineItemID="1226" NodeText="Cost of Revenue">
<BM FontName="" FontStyle="" FontSize="" UnderLine="false" BGColor="" BMID="01" NodeText="As % of Net Revenue" />
<BM FontName="" FontStyle="" FontSize="" UnderLine="false" BGColor="" BMID="02" NodeText="Year over Year Growth" />
</LineItem>
</Group>
<Group FontName="" FontStyle="" FontSize="" UnderLine="false" BGColor="" NodeText="Segment Details">
<LineItem FontName="" FontStyle="" FontSize="" UnderLine="false" BGColor="" LineItemID="1227" NodeText="Cost of Revenue-GAAP" />
<LineItem FontName="" FontStyle="" FontSize="" UnderLine="false" BGColor="" LineItemID="1228" NodeText="Gross Profit" />
</Group>
</Sheet>
<Sheet FontName="" FontStyle="" FontSize="" UnderLine="false" BGColor="" NodeText="Model2">
<Group FontName="" FontStyle="" FontSize="" UnderLine="false" BGColor="" NodeText="Key Financials">
<LineItem FontName="" FontStyle="" FontSize="" UnderLine="false" BGColor="" LineItemID="1235" NodeText="Total Operating Expenses-GAAP" />
<LineItem FontName="" FontStyle="" FontSize="" UnderLine="false" BGColor="" LineItemID="1236" NodeText="EBITDA" />
</Group>
</Sheet>
</Nodes>'
DECLARE #BMID INT,#ColLineItemID INT
DECLARE #SheetID INT,#GroupID INT,#LineItemID INT
DECLARE #SheetOrderID INT,#GroupOrderID INT,#LineItemOrderID INT,#BMOrderID INT
DECLARE #SheetStartIndex INT ,#SheetCount INT = #XMLData.value('count(/Nodes/Sheet)', 'INT');
DECLARE #GroupStartIndex INT ,#GroupCount INT = #XMLData.value('count(/Nodes/Sheet/Group)', 'INT');
DECLARE #LineitemStartIndex INT ,#LineitemCount INT = #XMLData.value('count(/Nodes/Sheet/Group/LineItem)', 'INT');
DECLARE #BMStartIndex INT ,#BMCount INT = #XMLData.value('count(/Nodes/Sheet/Group/LineItem/BM)', 'INT');
SET #SheetStartIndex = 1
SET #GroupStartIndex = 1
SET #LineitemStartIndex = 1
SET #BMStartIndex = 1
SET #SheetOrderID = 1
SET #GroupOrderID = 1
SET #LineItemOrderID = 1
SET #BMOrderID = 1
DECLARE #DisplayInCSM VARCHAR(MAX),
#FontName VARCHAR(MAX),
#FontStyle VARCHAR(MAX),
#FontSize VARCHAR(MAX),
#UnderLine VARCHAR(MAX),
#BGColor VARCHAR(MAX)
SET #DisplayInCSM = ''
SET #FontName = ''
SET #FontStyle = ''
SET #FontSize = ''
SET #UnderLine = ''
SET #BGColor = ''
WHILE #SheetStartIndex <= #SheetCount
BEGIN --Inserting sheet data
--PRINT 'Sheet'
SELECT #DisplayInCSM = tab.col.value('#NodeText[1]', 'VARCHAR(MAX)'),
#FontName = tab.col.value('#FontName[1]', 'VARCHAR(MAX)'),
#FontStyle = tab.col.value('#FontStyle[1]', 'VARCHAR(MAX)'),
#FontSize = tab.col.value('#FontSize[1]', 'VARCHAR(MAX)'),
#UnderLine = tab.col.value('#UnderLine[1]', 'VARCHAR(MAX)'),
#BGColor = tab.col.value('#BGColor[1]', 'VARCHAR(MAX)')
FROM #XMLData.nodes('/Nodes/Sheet[position() = sql:variable("#SheetStartIndex")]') AS tab(col)
INSERT INTO tblCSM_Details(CSM_ID,[ParentID],[Type],[DisplayInCSM],[FontName],[FontStyle],[FontSize],[UnderLine],[BGColor],[LineItemID],[BMID],[ColOrder])
VALUES(1,0,'SHEET',#DisplayInCSM,#FontName,#FontStyle,#FontSize,#UnderLine,#BGColor,0,0,#SheetOrderID)
SELECT #SheetID = SCOPE_IDENTITY()
BEGIN --Inserting Group data
SET #GroupOrderID = 1
SET #GroupStartIndex = 1
WHILE #GroupStartIndex <= #GroupCount
BEGIN --Inserting Group data
SELECT #DisplayInCSM = tab.col.value('#NodeText[1]', 'VARCHAR(MAX)'),
#FontName = tab.col.value('#FontName[1]', 'VARCHAR(MAX)'),
#FontStyle = tab.col.value('#FontStyle[1]', 'VARCHAR(MAX)'),
#FontSize = tab.col.value('#FontSize[1]', 'VARCHAR(MAX)'),
#UnderLine = tab.col.value('#UnderLine[1]', 'VARCHAR(MAX)'),
#BGColor = tab.col.value('#BGColor[1]', 'VARCHAR(MAX)')
FROM #XMLData.nodes('/Nodes/Sheet/Group[position() = sql:variable("#GroupStartIndex")]') AS tab(col)
INSERT INTO tblCSM_Details(CSM_ID,[ParentID],[Type],[DisplayInCSM],[FontName],[FontStyle],[FontSize],[UnderLine],[BGColor],[LineItemID],[BMID],[ColOrder])
VALUES(1,#SheetID,'GROUP',#DisplayInCSM,#FontName,#FontStyle,#FontSize,#UnderLine,#BGColor,0,0,#GroupOrderID)
SELECT #GroupID = SCOPE_IDENTITY()
BEGIN --Inserting LineItem data
SET #LineItemOrderID = 1
SET #LineitemStartIndex = 1
WHILE #LineitemStartIndex <= #LineitemCount
BEGIN
SELECT #DisplayInCSM = tab.col.value('#NodeText[1]', 'VARCHAR(MAX)'),
#FontName = tab.col.value('#FontName[1]', 'VARCHAR(MAX)'),
#FontStyle = tab.col.value('#FontStyle[1]', 'VARCHAR(MAX)'),
#FontSize = tab.col.value('#FontSize[1]', 'VARCHAR(MAX)'),
#UnderLine = tab.col.value('#UnderLine[1]', 'VARCHAR(MAX)'),
#BGColor = tab.col.value('#BGColor[1]', 'VARCHAR(MAX)'),
#ColLineItemID = CAST(tab.col.value('#LineItemID[1]', 'VARCHAR(MAX)') AS INT)
FROM #XMLData.nodes('/Nodes/Sheet/Group/LineItem[position() = sql:variable("#LineitemStartIndex")]') AS tab(col)
INSERT INTO tblCSM_Details(CSM_ID,[ParentID],[Type],[DisplayInCSM],[FontName],[FontStyle],[FontSize],[UnderLine],[BGColor],[LineItemID],[BMID],[ColOrder])
VALUES(1,#GroupID,'LINEITEM',#DisplayInCSM,#FontName,#FontStyle,#FontSize,#UnderLine,#BGColor,#ColLineItemID,0,#LineItemOrderID)
SELECT #LineItemID = SCOPE_IDENTITY()
BEGIN --Inserting BM data
SET #BMOrderID = 1
SET #BMStartIndex = 1
WHILE #BMStartIndex <= #BMCount
BEGIN --Inserting sheet data
SELECT #DisplayInCSM = tab.col.value('#NodeText[1]', 'VARCHAR(MAX)'),
#FontName = tab.col.value('#FontName[1]', 'VARCHAR(MAX)'),
#FontStyle = tab.col.value('#FontStyle[1]', 'VARCHAR(MAX)'),
#FontSize = tab.col.value('#FontSize[1]', 'VARCHAR(MAX)'),
#UnderLine = tab.col.value('#UnderLine[1]', 'VARCHAR(MAX)'),
#BGColor = tab.col.value('#BGColor[1]', 'VARCHAR(MAX)'),
#BMID = CAST(tab.col.value('#BMID[1]', 'VARCHAR(MAX)') AS INT)
FROM #XMLData.nodes('/Nodes/Sheet/Group/LineItem/BM[position() = sql:variable("#BMStartIndex")]') AS tab(col)
INSERT INTO tblCSM_Details(CSM_ID,[ParentID],[Type],[DisplayInCSM],[FontName],[FontStyle],[FontSize],[UnderLine],[BGColor],[LineItemID],[BMID],[ColOrder])
VALUES(1,#LineItemID,'BM',#DisplayInCSM,#FontName,#FontStyle,#FontSize,#UnderLine,#BGColor,0,#BMID,#BMOrderID)
SET #BMOrderID = #BMOrderID + 1
SET #BMStartIndex = #BMStartIndex + 1
END
END
SET #LineItemOrderID = #LineItemOrderID + 1
SET #LineitemStartIndex = #LineitemStartIndex + 1
END
END
SET #GroupOrderID = #GroupOrderID + 1
SET #GroupStartIndex = #GroupStartIndex + 1;
END
END
SET #SheetOrderID = #SheetOrderID + 1
SET #SheetStartIndex = #SheetStartIndex + 1;
END
1) When run the above code then i saw 6 Group has been inserted into table. whereas i have 3 group in xml
2) BM element has been added under wrong lineitem.
i insert data into loop because i have parent child relation in table. so when i insert parent data then i store parent's inserted id into variable which i also insert during child data insertion.
i am not being able to understand where i made the mistake in code. anyone can help me. thanks

Prepare WHERE Clause string for given values

I have the following details to prepare string as shown below in the expected result.
Given:
DECLARE #VValue VARCHAR(MAX) = 'John Dee|Mak Don'
DECLARE #VColumns VARCHAR(MAX) = 'FName|LName'
DECLARE #VCondition VARCHAR(500) = 'OR'
DECLARE #VPattern VARCHAR(MAX) = 'Start|Exact'
DECLARE #VCheck VARCHAR(MAX) = '1|0'
DECLARE #String VARCHAR(MAX) = ''
Expected result:
(
ISNULL(PATINDEX(''John%'', FName), ''0'') > 0 AND
ISNULL(PATINDEX(''Dee%'', FName), ''0'') > 0
)
OR
(
ISNULL(PATINDEX(''Mak'', LName), ''0'') +
ISNULL(PATINDEX(''Don'', LName), ''0'') > 0
)
My attempt:
SET #VCondition = '|'+#VCondition;
SET #String = REPLACE('('+REPLACE(STUFF((SELECT N') '+DS3.Item+' (' + NCHAR(10) +
STUFF((SELECT
CASE WHEN DS4.Item = 'Start' AND DS5.Item = 0
THEN
N' + ' +NCHAR(10)+
N'ISNULL(PATINDEX('''''+DSn.Item +'%'''''+ N',' + DSc.Item + N'),''''0'''')'
WHEN DS4.Item = 'Start' AND DS5.Item = 1
THEN
N' > 0 AND ' +NCHAR(10)+
N'ISNULL(PATINDEX('''''+DSn.Item +'%'''''+ N',' + DSc.Item + N'),''''0'''')'
ELSE
''
END
+
CASE WHEN DS4.Item = 'Exact' AND DS5.Item = 0
THEN
N' + ' +NCHAR(10)+
N'ISNULL(PATINDEX('''''+DSn.Item +''''''+ N',' + DSc.Item + N'),''''0'''')'
WHEN DS4.Item = 'Exact' AND DS5.Item = 1
THEN
N' > 0 AND ' +NCHAR(10)+
N'ISNULL(PATINDEX('''''+DSn.Item +''''''+ N',' + DSc.Item + N'),''''0'''')'
ELSE ''
END
FROM dbo.f_split(DS1.Item,' ') DSn
CROSS APPLY dbo.f_split(DS2.Item,',') DSc
ORDER BY DSc.id, DSn.id
FOR XML PATH(N'')),1,4,N'')
FROM dbo.udf_split (#VValue,'|') DS1
CROSS APPLY dbo.udf_split (#VColumns,'|') DS2
CROSS APPLY dbo.udf_split (#VCondition,'|') DS3
CROSS APPLY dbo.udf_split (#VPattern,'|') DS4
CROSS APPLY dbo.udf_split (#VCheck, '|') DS5
WHERE DS1.id = DS2.id AND DS2.ID = DS3.ID AND DS3.ID = DS4.ID AND DS4.ID = DS5.ID
ORDER BY DS1.id
FOR XML PATH(N'')),1,9,N''),'>','>') + N') )','&gt;','>');
PRINT(#String);
But I'm getting the following result:
( AND
ISNULL(PATINDEX(''John%'', FName), ''0'') > 0 AND
ISNULL(PATINDEX(''Dee%'', FName), ''0'')) OR (
ISNULL(PATINDEX(''Mak'', LName), ''0'') +
ISNULL(PATINDEX(''Don'', LName), ''0'')) )
After many attempt, following does the job done.
Query:
DECLARE #VValue VARCHAR(MAX) = 'John Dee|Mak Don'
DECLARE #VColumns VARCHAR(MAX) = 'FName|LName'
DECLARE #VCondition VARCHAR(500) = 'OR'
DECLARE #VPattern VARCHAR(MAX) = 'Start|Exact'
DECLARE #VCheck VARCHAR(MAX) = '1|0'
DECLARE #String VARCHAR(MAX) = ''
SET #VCondition = '|'+#VCondition;
SET #String = REPLACE('('+STUFF((SELECT N' > 0 ) '+DS3.Item+' (' + NCHAR(10) +
REPLACE(STUFF((SELECT
CASE WHEN DS4.Item = 'Start' AND DS5.Item = 0
THEN
N' + ' +NCHAR(10)+
N'ISNULL(PATINDEX('''''+DSn.Item +'%'''''+ N',' + DSc.Item + N'),''''0'''')'
WHEN DS4.Item = 'Start' AND DS5.Item = 1
THEN
N' > 0 AND ' +NCHAR(10)+
N'ISNULL(PATINDEX('''''+DSn.Item +'%'''''+ N',' + DSc.Item + N'),''''0'''')'
ELSE
''
END
+
CASE WHEN DS4.Item = 'Exact' AND DS5.Item = 0
THEN
N' + ' +NCHAR(10)+
N'ISNULL(PATINDEX('''''+DSn.Item +''''''+ N',' + DSc.Item + N'),''''0'''')'
WHEN DS4.Item = 'Exact' AND DS5.Item = 1
THEN
N' > 0 AND ' +NCHAR(10)+
N'ISNULL(PATINDEX('''''+DSn.Item +''''''+ N',' + DSc.Item + N'),''''0'''')'
ELSE ''
END
FROM dbo.f_split(DS1.Item,' ') DSn
CROSS APPLY dbo.f_split(DS2.Item,',') DSc
ORDER BY DSc.id, DSn.id
FOR XML PATH(N'')),1,11,N''),'>','>')
FROM dbo.udf_split (#VValue,'|') DS1
CROSS APPLY dbo.udf_split (#VColumns,'|') DS2
CROSS APPLY dbo.udf_split (#VCondition,'|') DS3
CROSS APPLY dbo.udf_split (#VPattern,'|') DS4
CROSS APPLY dbo.udf_split (#VCheck, '|') DS5
WHERE DS1.id = DS2.id AND DS2.ID = DS3.ID AND DS3.ID = DS4.ID AND DS4.ID = DS5.ID
ORDER BY DS1.id
FOR XML PATH(N'')),1,13,N''),'>','>') + N' > 0 ) ';
PRINT(#String);
Output:
(
ISNULL(PATINDEX(''John%'',FName),''0'') > 0 AND
ISNULL(PATINDEX(''Dee%'',FName),''0'') > 0
)
OR
(
ISNULL(PATINDEX(''Mak'',LName),''0'') +
ISNULL(PATINDEX(''Don'',LName),''0'') > 0
)

sql server query concat string with '-'

In my SQL query, I'm trying to concatenate two strings in my select clause. Here's the expected results:
col A col B Result
null null &
null '' &
null XYZ XYC
'' null &
'' '' &
'' XYZ XYC
ABC null ABC
ABC '' ABC
ABC XYZ ABC-XYC
My challenge is this - how do I get the 'dash' to show up for the last scenario and not the others?
Here's my attempt:
DECLARE #ColA as varchar(10)
DECLARE #ColB as varchar(10)
set #ColA = null; set #ColB = null; select '&' as 'Expected', COALESCE(NULLIF(COALESCE(#ColA, '') + COALESCE(#ColB, ''), ''), '&') as 'Actual'
set #ColA = null; set #ColB = ''; select '&' as 'Expected', COALESCE(NULLIF(COALESCE(#ColA, '') + COALESCE(#ColB, ''), ''), '&') as 'Actual'
set #ColA = null; set #ColB = 'XYC'; select 'XYC' as 'Expected', COALESCE(NULLIF(COALESCE(#ColA, '') + COALESCE(#ColB, ''), ''), '&') as 'Actual'
set #ColA = ''; set #ColB = null; select '&' as 'Expected', COALESCE(NULLIF(COALESCE(#ColA, '') + COALESCE(#ColB, ''), ''), '&') as 'Actual'
set #ColA = ''; set #ColB = ''; select '&' as 'Expected', COALESCE(NULLIF(COALESCE(#ColA, '') + COALESCE(#ColB, ''), ''), '&') as 'Actual'
set #ColA = ''; set #ColB = 'XYC'; select 'XYC' as 'Expected', COALESCE(NULLIF(COALESCE(#ColA, '') + COALESCE(#ColB, ''), ''), '&') as 'Actual'
set #ColA = 'ABC';set #ColB = null; select 'ABC' as 'Expected', COALESCE(NULLIF(COALESCE(#ColA, '') + COALESCE(#ColB, ''), ''), '&') as 'Actual'
set #ColA = 'ABC';set #ColB = ''; select 'ABC' as 'Expected', COALESCE(NULLIF(COALESCE(#ColA, '') + COALESCE(#ColB, ''), ''), '&') as 'Actual'
set #ColA = 'ABC';set #ColB = 'XYC'; select 'ABC-XYC' as 'Expected', COALESCE(NULLIF(COALESCE(#ColA, '') + COALESCE(#ColB, ''), ''), '&') as 'Actual'
Do you think I have to do one giant case when? I have many columns like this, and that would make it unbearable to read.
Thanks!
UPDATE: if I use a case when, then my select looks like this, which seems to work, but is going to be a pain.
select
case when (#ColA is not null and #ColA <> '') and
(#ColB is not null and #ColB <> '')
then #ColA + '-' + #ColB
else COALESCE(NULLIF(COALESCE(#ColA, '') + COALESCE(#ColB, ''), ''), '&')
end
really hoping someone has some suggestions for improvement!
Could you use a searched case function like this?
Select Case When isnull(ColA, '') + isnull(ColB, '') == '' Then '&'
When isnull(ColA, '') <> '' and isnull(ColB, '') <> '' Then ColA + '-' + ColB
Else isnull(ColA, '') + isnull(ColB, '')
From Table1
I think this answer isn't a whole lot different than one of the other ones, but you might try this:
SELECT
CASE
WHEN NULLIF(ColA,'') <> '' AND NULLIF(ColB,'') <> ''
THEN ColA + '-' + ColB
WHEN NULLIF(ColA,'') <> '' OR NULLIF(ColB,'') <> ''
THEN COALESCE(ColA,ColB)
ELSE '&'
END

Resources