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

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

Related

How to perform a dynamic pivot in T-SQL on a subset of columns

Software used: SQL Server 2014 Management Studio to query a standard 64-bit SQL Server.
I'm trying to create a query that generates a set of patient assessment results across multiple patients / assessments, and to put the results of each assessment on one row. This would suggest the use of pivoting of some sort.
Each assessment consists of a number of tests, each of which has a type, a name and a score. It is possible that we may want to add more tests to an assessment at some point, which would suggest the use of dynamic pivots.
At the moment, my query essentially looks like this:
SELECT TOP 20000
P.PatientId,
P.LastName,
P.FirstName,
FORMAT(P.DateOfBirth, 'dd/MM/yyyy') as 'DateOfBirth',
FORMAT(A.TreatmentDate, 'dd/MM/yyyy') as 'AssmentDate',
A.TestType,
A.TestName,
A.TestScore
FROM
Patient P
INNER JOIN
Assessment A ON (A.PatientSerialNumber = P.PatientSerialNumber)
INNER JOIN
AssessmentHeader AH ON (AH.AssessmentSerialNumber = A.AssessmentSerialNumber
AND AH.PatientSerialNumber = P.PatientSerialNumber)
WHERE
A.ValidEntryIndicator = 'Y'
AND AH.ValidEntryIndicator = 'Y'
ORDER BY
P.PatientId, T.TreatmentDate
My results essentially look like this (there are actually a lot more test types and names than shown here - these are just for illustration):
PatientId
LastName
FirstName
DateOfBirth
AssmentDate
TestType
TestName
TestScore
AB1234
PATIENT
Test
1/1/2000
1/1/2020
Renal
Urgency
0
AB1234
PATIENT
Test
1/1/2000
1/1/2020
Renal
Retention
1
AB1234
PATIENT
Test
1/1/2000
1/1/2020
GI
Proctitis
2
AB1234
PATIENT
Test
1/1/2000
1/1/2020
GI
Diarrhea
3
AB1234
PATIENT
Test
1/1/2000
6/6/2021
Renal
Urgency
1
AB1234
PATIENT
Test
1/1/2000
6/6/2021
Renal
Retention
0
AB1234
PATIENT
Test
1/1/2000
6/6/2021
GI
Proctitis
1
AB1234
PATIENT
Test
1/1/2000
6/6/2021
GI
Diarrhea
2
YZ6789
PATIENT2
Test2
1/1/1999
7/7/2020
Renal
Urgency
2
YZ6789
PATIENT2
Test2
1/1/1999
7/7/2020
Renal
Retention
5
YZ6789
PATIENT2
Test2
1/1/1999
7/7/2020
GI
Proctitis
3
YZ6789
PATIENT2
Test2
1/1/1999
7/7/2020
GI
Diarrhea
1
YZ6789
PATIENT2
Test2
1/1/1999
6/7/2021
Renal
Urgency
2
YZ6789
PATIENT2
Test2
1/1/1999
6/7/2021
Renal
Retention
9
YZ6789
PATIENT2
Test2
1/1/1999
6/7/2021
GI
Proctitis
4
YZ6789
PATIENT2
Test2
1/1/1999
6/7/2021
GI
Diarrhea
5
What I would like is this:
PatientId
LastName
FirstName
DateOfBirth
AssmentDate
Renal-Urgency
Renal-Retention
GI-Proctitis
GI-Diarrhea
AB1234
PATIENT
Test
1/1/2000
1/1/2020
0
1
2
3
AB1234
PATIENT
Test
1/1/2000
6/6/2021
1
0
1
2
YZ6789
PATIENT2
Test2
1/1/1999
7/7/2020
2
5
3
1
YZ6789
PATIENT2
Test2
1/1/1999
6/7/2021
2
9
4
5
I've tried to follow various online resources and SO question/answers (this one looked the most promising), but I just can't seem to get the methods shown in these to work with my query (frustratingly)
Can anyone help me out?
So you can use the technique shown at the linked answer, you just need to extend it to handle multiple key-columns and multiple pivot-source columns:
CREATE TABLE #Table (
-- key columns
PatientId Varchar(8),
LastName VarChar(32),
FirstName Varchar(32),
DateOfBirth DateTime,
AssmentDate DateTime,
-- pivot-source columns
TestType Varchar(20),
TestName Varchar(20),
-- value column
TestScore INT
)
go
INSERT INTO #Table Values('AB1234', 'PATIENT', 'Test', '1/1/2000', '1/1/2020', 'Renal', 'Urgency', '0');
INSERT INTO #Table Values('AB1234', 'PATIENT', 'Test', '1/1/2000', '1/1/2020', 'Renal', 'Retention', '1');
INSERT INTO #Table Values('AB1234', 'PATIENT', 'Test', '1/1/2000', '1/1/2020', 'GI', 'Proctitis', '2');
INSERT INTO #Table Values('AB1234', 'PATIENT', 'Test', '1/1/2000', '1/1/2020', 'GI', 'Diarrhea', '3');
INSERT INTO #Table Values('AB1234', 'PATIENT', 'Test', '1/1/2000', '6/6/2021', 'Renal', 'Urgency', '1');
INSERT INTO #Table Values('AB1234', 'PATIENT', 'Test', '1/1/2000', '6/6/2021', 'Renal', 'Retention', '0');
INSERT INTO #Table Values('AB1234', 'PATIENT', 'Test', '1/1/2000', '6/6/2021', 'GI', 'Proctitis', '1');
INSERT INTO #Table Values('AB1234', 'PATIENT', 'Test', '1/1/2000', '6/6/2021', 'GI', 'Diarrhea', '2');
INSERT INTO #Table Values('YZ6789', 'PATIENT2', 'Test2', '1/1/1999', '7/7/2020', 'Renal', 'Urgency', '2');
INSERT INTO #Table Values('YZ6789', 'PATIENT2', 'Test2', '1/1/1999', '7/7/2020', 'Renal', 'Retention', '5');
INSERT INTO #Table Values('YZ6789', 'PATIENT2', 'Test2 ', '1/1/1999', '7/7/2020', 'GI', 'Proctitis', '3');
INSERT INTO #Table Values('YZ6789', 'PATIENT2', 'Test2', '1/1/1999', '7/7/2020', 'GI', 'Diarrhea', '1');
INSERT INTO #Table Values('YZ6789', 'PATIENT2', 'Test2', '1/1/1999', '6/7/2021', 'Renal', 'Urgency', '2');
INSERT INTO #Table Values('YZ6789', 'PATIENT2', 'Test2', '1/1/1999', '6/7/2021', 'Renal ', 'Retention', '9');
INSERT INTO #Table Values('YZ6789', 'PATIENT2', 'Test2', '1/1/1999', '6/7/2021', 'GI', 'Proctitis', '4');
INSERT INTO #Table Values('YZ6789', 'PATIENT2', 'Test2', '1/1/1999', '6/7/2021', 'GI', 'Diarrhea', '5');
go
DECLARE #cols NVARCHAR(2000)
DECLARE #query NVARCHAR(4000)
SELECT #cols = STUFF(( SELECT DISTINCT TOP 100 PERCENT
'],[' + t.TestType + '-' + t.TestName
FROM #Table AS t
FOR XML PATH('')
), 1, 2, '') + ']'
SELECT #cols
SET #query = N'SELECT PatientId, LastName, FirstName, DateOfBirth, AssmentDate, '
+ #cols
+' FROM
(SELECT PatientId, LastName, FirstName, DateOfBirth, AssmentDate, '
+' TestType + ''-'' + TestName AS ColName, TestScore FROM #Table AS t1) p
PIVOT (MAX([TestScore]) FOR ColName IN ( '+ #cols +' ))
AS pvt;'
PRINT(#query)
EXECUTE(#query)
DROP TABLE #Table
GO
In your case, you would use the query you have in your question to load #Table. I had to guess about the length of the Varchar(..) columns, so you will need to check and correct them.
Pivot is based on column values so the answer depends on what values are there in the columns.
CREATE TABLE #Table (
-- key columns
PatientId Varchar(8),
LastName VarChar(32),
FirstName Varchar(32),
DateOfBirth DateTime,
AssesmentDate DateTime,
-- pivot-source columns
TestType Varchar(20),
TestName Varchar(20),
-- value column
TestScore INT
)
go
INSERT INTO #Table Values('AB1234', 'PATIENT', 'Test', '1/1/2000', '1/1/2020', 'Renal', 'Urgency', '0');
INSERT INTO #Table Values('AB1234', 'PATIENT', 'Test', '1/1/2000', '1/1/2020', 'Renal', 'Retention', '1');
INSERT INTO #Table Values('AB1234', 'PATIENT', 'Test', '1/1/2000', '1/1/2020', 'GI', 'Proctitis', '2');
INSERT INTO #Table Values('AB1234', 'PATIENT', 'Test', '1/1/2000', '1/1/2020', 'GI', 'Diarrhea', '3');
INSERT INTO #Table Values('AB1234', 'PATIENT', 'Test', '1/1/2000', '6/6/2021', 'Renal', 'Urgency', '1');
INSERT INTO #Table Values('AB1234', 'PATIENT', 'Test', '1/1/2000', '6/6/2021', 'Renal', 'Retention', '0');
INSERT INTO #Table Values('AB1234', 'PATIENT', 'Test', '1/1/2000', '6/6/2021', 'GI', 'Proctitis', '1');
INSERT INTO #Table Values('AB1234', 'PATIENT', 'Test', '1/1/2000', '6/6/2021', 'GI', 'Diarrhea', '2');
INSERT INTO #Table Values('YZ6789', 'PATIENT2', 'Test2', '1/1/1999', '7/7/2020', 'Renal', 'Urgency', '2');
INSERT INTO #Table Values('YZ6789', 'PATIENT2', 'Test2', '1/1/1999', '7/7/2020', 'Renal', 'Retention', '5');
INSERT INTO #Table Values('YZ6789', 'PATIENT2', 'Test2 ', '1/1/1999', '7/7/2020', 'GI', 'Proctitis', '3');
INSERT INTO #Table Values('YZ6789', 'PATIENT2', 'Test2', '1/1/1999', '7/7/2020', 'GI', 'Diarrhea', '1');
INSERT INTO #Table Values('YZ6789', 'PATIENT2', 'Test2', '1/1/1999', '6/7/2021', 'Renal', 'Urgency', '2');
INSERT INTO #Table Values('YZ6789', 'PATIENT2', 'Test2', '1/1/1999', '6/7/2021', 'Renal', 'Retention', '9');
INSERT INTO #Table Values('YZ6789', 'PATIENT2', 'Test2', '1/1/1999', '6/7/2021', 'GI', 'Proctitis', '4');
INSERT INTO #Table Values('YZ6789', 'PATIENT2', 'Test2', '1/1/1999', '6/7/2021', 'GI', 'Diarrhea', '5');
go
--select * from #Table
DECLARE #SQL AS VARCHAR(MAX)
, #cols_ AS VARCHAR(MAX)
--Making the column list dynamically
SELECT #cols_ = STUFF((SELECT DISTINCT ', '+QUOTENAME( C.TestType +'-'+C.TestName)
FROM #Table C
FOR XML PATH('')), 1, 1, '')
--preparing PIVOT query dynamically.
select #cols_ --View the columns
SET #SQL = ' SELECT
pivoted.PatientId
,pivoted.FirstName
,pivoted.LastName
,pivoted.DateOfBirth
,pivoted.AssesmentDate
,'+#cols_+'
FROM
(
SELECT PatientId ,
LastName ,
FirstName,
DateOfBirth,
AssesmentDate,
TestType+''-''+ TestName as [PivotedCol],
TestScore
FROM #Table
) AS cp
PIVOT
(
MAX([CP].[TestScore])
FOR [CP].[PivotedCol] IN (' + #cols_ + ')
) AS pivoted; ' ;
PRINT(#SQL)
EXECUTE(#SQL)
DROP TABLE #Table

Snowflake Pandas connection issue

I'm trying to insert a dataframe into a snowflake table using the pandas connector and am getting permission issues, but using the "normal" snowflake connector works fine.
import snowflake.connector as snow
from snowflake.connector.pandas_tools import *
cur = self.conn.cursor()
my_schema = "my_schema"
my_table = "my_table"
cur.execute(f"""INSERT INTO {my_schema}.{my_table}(load_date, some_id)
values (current_timestamp, 'xxx')""")
write_pandas(self.conn, daily_epc_df, table_name=my_table, schema=my_schema)
But I'm getting
File "/Users/abohr/virtualenv/peak38/lib/python3.8/site-packages/snowflake/connector/errors.py", line 85, in default_errorhandler
raise error_class(
snowflake.connector.errors.ProgrammingError: 001757 (42601): SQL compilation error:
Table '"my_schema"."my_table"' does not exist
the same connection can insert and then doesn't work on the same table.
I also tried
df.to_sql(..., method=pd_writer)
and get
pandas.io.sql.DatabaseError: Execution failed on sql 'SELECT name FROM sqlite_master WHERE type='table' AND name=?;': not all arguments converted during string formatting
Why is it talking about sqlite_master if I'm trying to connect to Snowflake? Do the pandas functions require different connections?
my libs:
name = "snowflake-connector-python"
version = "2.3.3"
description = "Snowflake Connector for Python"
category = "main"
optional = false
python-versions = ">=3.5"
[[package]]
name = "pandas"
version = "1.0.5"
description = "Powerful data structures for data analysis, time series, and statistics"
category = "main"
optional = false
python-versions = ">=3.6.1"```
on Python 3.8
I found my issue - I added quote_identifiers=False to
write_pandas(self.conn, daily_epc_df, table_name=my_table, schema=my_schema, quote_identifiers=False)
and now it works.
But seems very wrong that the default behavior would break, I'm still suspicious.
Hmm I've done something superior I think to pandas ...
Tell me if you agree ...
CREATE OR REPLACE PROCEDURE DEMO_DB.PUBLIC.SNOWBALL(
db_name STRING,
schema_name STRING,
snowball_table STRING,
max_age_days FLOAT,
limit FLOAT
)
RETURNS VARIANT
LANGUAGE JAVASCRIPT
COMMENT = 'Collects table and column stats.'
EXECUTE AS OWNER
AS
$$
var validLimit = Math.max(LIMIT, 0); // prevent SQL syntax error caused by negative numbers
var sqlGenerateInserts = `
WITH snowball_tables AS (
SELECT CONCAT_WS('.', table_catalog, table_schema, table_name) AS full_table_name, *
FROM IDENTIFIER(?) -- <<DB_NAME>>.INFORMATION_SCHEMA.TABLES
),
snowball_columns AS (
SELECT CONCAT_WS('.', table_catalog, table_schema, table_name) AS full_table_name, *
FROM IDENTIFIER(?) -- <<DB_NAME>>.INFORMATION_SCHEMA.COLUMNS
),
snowball AS (
SELECT table_name, MAX(stats_run_date_time) AS stats_run_date_time
FROM IDENTIFIER(?) -- <<SNOWBALL_TABLE>> table
GROUP BY table_name
)
SELECT full_table_name, aprox_row_count,
CONCAT (
'INSERT INTO IDENTIFIER(''', ?, ''') ', -- SNOWBALL table
'(table_name,total_rows,table_last_altered,table_created,table_bytes,col_name,',
'col_data_type,col_hll,col_avg_length,col_null_cnt,col_min,col_max,col_top,col_mode,col_avg,stats_run_date_time)',
'SELECT ''', full_table_name, ''' AS table_name, ',
table_stats_sql,
', ARRAY_CONSTRUCT( ', col_name, ') AS col_name',
', ARRAY_CONSTRUCT( ', col_data_type, ') AS col_data_type',
', ARRAY_CONSTRUCT( ', col_hll, ') AS col_hll',
', ARRAY_CONSTRUCT( ', col_avg_length, ') AS col_avg_length',
', ARRAY_CONSTRUCT( ', col_null_cnt, ') AS col_null_cnt',
', ARRAY_CONSTRUCT( ', col_min, ') AS col_min',
', ARRAY_CONSTRUCT( ', col_max, ') AS col_max',
', ARRAY_CONSTRUCT( ', col_top, ') AS col_top',
', ARRAY_CONSTRUCT( ', col_MODE, ') AS col_MODE',
', ARRAY_CONSTRUCT( ', col_AVG, ') AS col_AVG',
', CURRENT_TIMESTAMP() AS stats_run_date_time ',
' FROM ', quoted_table_name
) AS insert_sql
FROM (
SELECT
tbl.full_table_name,
tbl.row_count AS aprox_row_count,
CONCAT ( '"', col.table_catalog, '"."', col.table_schema, '"."', col.table_name, '"' ) AS quoted_table_name,
CONCAT (
'COUNT(1) AS total_rows,''',
IFNULL( tbl.last_altered::VARCHAR, 'NULL'), ''' AS table_last_altered,''',
IFNULL( tbl.created::VARCHAR, 'NULL'), ''' AS table_created,',
IFNULL( tbl.bytes::VARCHAR, 'NULL'), ' AS table_bytes' ) AS table_stats_sql,
LISTAGG (
CONCAT ('''', col.full_table_name, '.', col.column_name, '''' ), ', '
) AS col_name,
LISTAGG ( CONCAT('''', col.data_type, '''' ), ', ' ) AS col_data_type,
LISTAGG ( CONCAT( ' HLL(', '"', col.column_name, '"',') ' ), ', ' ) AS col_hll,
LISTAGG ( CONCAT( ' AVG(ZEROIFNULL(LENGTH(', '"', col.column_name, '"','))) ' ), ', ' ) AS col_avg_length,
LISTAGG ( CONCAT( ' SUM( IFF( ', '"', col.column_name, '"',' IS NULL, 1, 0) ) ' ), ', ') AS col_null_cnt,
LISTAGG ( IFF ( col.data_type = 'NUMBER', CONCAT ( ' MODE(', '"', col.column_name, '"', ') ' ), 'NULL' ), ', ' ) AS col_MODE,
LISTAGG ( IFF ( col.data_type = 'NUMBER', CONCAT ( ' MIN(', '"', col.column_name, '"', ') ' ), 'NULL' ), ', ' ) AS col_min,
LISTAGG ( IFF ( col.data_type = 'NUMBER', CONCAT ( ' MAX(', '"', col.column_name, '"', ') ' ), 'NULL' ), ', ' ) AS col_max,
LISTAGG ( IFF ( col.data_type = 'NUMBER', CONCAT ( ' AVG(', '"', col.column_name,'"',') ' ), 'NULL' ), ', ' ) AS col_AVG,
LISTAGG ( CONCAT ( ' APPROX_TOP_K(', '"', col.column_name, '"', ', 100, 10000)' ), ', ' ) AS col_top
FROM snowball_tables tbl JOIN snowball_columns col ON col.full_table_name = tbl.full_table_name
LEFT OUTER JOIN snowball sb ON sb.table_name = tbl.full_table_name
WHERE (tbl.table_catalog, tbl.table_schema) = (?, ?)
AND ( sb.table_name IS NULL OR sb.stats_run_date_time < TIMESTAMPADD(DAY, - FLOOR(?), CURRENT_TIMESTAMP()) )
--AND tbl.row_count > 0 -- NB: also excludes views (table_type = 'VIEW')
GROUP BY tbl.full_table_name, aprox_row_count, quoted_table_name, table_stats_sql, stats_run_date_time
ORDER BY stats_run_date_time NULLS FIRST )
LIMIT ` + validLimit;
var tablesAnalysed = [];
var currentSql;
try {
currentSql = sqlGenerateInserts;
var generateInserts = snowflake.createStatement( {
sqlText: currentSql,
binds: [
`"${DB_NAME}".information_schema.tables`,
`"${DB_NAME}".information_schema.columns`,
SNOWBALL_TABLE, SNOWBALL_TABLE,
DB_NAME, SCHEMA_NAME, MAX_AGE_DAYS, LIMIT
]
} );
var insertStatements = generateInserts.execute();
// loop over generated INSERT statements and execute them
while (insertStatements.next()) {
var tableName = insertStatements.getColumnValue('FULL_TABLE_NAME');
currentSql = insertStatements.getColumnValue('INSERT_SQL');
var insertStatement = snowflake.createStatement( {
sqlText: currentSql,
binds: [ SNOWBALL_TABLE ]
} );
var insertResult = insertStatement.execute();
tablesAnalysed.push(tableName);
}
return { result: "SUCCESS", analysedTables: tablesAnalysed };
}
catch (err) {
return {
error: err,
analysedTables: tablesAnalysed,
sql: currentSql
};
}
$$;

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

Boolean conditions in SQL where clause

I wanted to write an sql query to fetch data as:
1. when param = 'all' it should list data across the table
2. when param = 'yes' it should list data where invoicenumber is not empty.
3. when param = 'no' it should list data where invoicenumber is empty.
i tried below query for yes and no
declare #invoiced as nvarchar(10) = 'no'
select * from OrderSummary
where
((#invoiced = 'yes') or (InvoiceNumber = ''))
and
((#invoiced = 'no') or (InvoiceNumber <> ''))
now i also want to incorporate all condition, could anyone suggest how could i achieve that
declare #invoiced as nvarchar(10) = 'no'
select * from OrderSummary
where
#invoiced = 'all'
OR
(#invoiced = 'yes' AND InvoiceNumber <> '')
OR
(#invoiced = 'no' AND InvoiceNumber = '')
Try this
declare #invoiced as nvarchar(10) = 'no'
select
*
from OrderSummary
where
(
#invoiced = 'all'
OR
(
#invoiced = 'yes'
AND
InvoiceNumber <> ''
)
OR
(
#invoiced = 'no'
AND
InvoiceNumber = ''
)
)
It should fulfill your requirement.
declare #invoiced as nvarchar(10) = 'no'
select * from OrderSummary
where
((#invoiced in ('all','no')) OR (#invoiced = 'yes' AND InvoiceNumber <> ''))
and
((#invoiced in ('all','yes')) OR (#invoiced = 'no' AND InvoiceNumber = ''))
and
(#invoiced in ('no','yes'))
declare #invoiced as nvarchar(10) = 'no'
select * from OrderSummary
where
((#invoiced = 'yes') and (InvoiceNumber <> '') )
or
((#invoiced = 'no') and ( (InvoiceNumber = '') or (InvoiceNumber = null)))
or (#invoiced = 'all')
Please update this query with above query.

Reduce multiple if else statement

I have the following 5 variables to check for a condition.
Example:
DECLARE #Col1 VARCHAR(10) = ''
DECLARE #Col2 VARCHAR(10) = ''
DECLARE #Col3 VARCHAR(10) = ''
DECLARE #Col4 VARCHAR(10) = ''
DECLARE #Col5 VARCHAR(10) = ''
DECLARE #String VARCHAR(MAX)
IF #Col1 = '' AND #Col2 = '' AND #Col3 = '' AND #Col4 = '' AND #Col5 = ''
BEGIN
SET #String = ''
END
ELSE IF #Col1 <> '' AND #Col2 = '' AND #Col3 = '' AND #Col4 = '' AND #Col5 = ''
BEGIN
SET #String = '#Col1'
END
ELSE IF #Col1 = '' AND #Col2 <> '' AND #Col3 = '' AND #Col4 = '' AND #Col5 = ''
BEGIN
SET #String = '#Col2'
END
ELSE IF #Col1 = '' AND #Col2 = '' AND #Col3 <> '' AND #Col4 = '' AND #Col5 = ''
BEGIN
SET #String = '#Col3'
END
ELSE IF #Col1 = '' AND #Col2 = '' AND #Col3 = '' AND #Col4 <> '' AND #Col5 = ''
BEGIN
SET #String = '#Col4'
END
.....
.....
.....
As the above conditions show, there are many probabilities.
How can I reduce the occurrences of multiple if conditions?
You can use CASE WHEN:
SELECT #String = CASE
WHEN #Col1 = '' AND #Col2 = '' AND #Col3 = '' AND #Col4 = '' AND #Col5 = '' THEN ''
WHEN #Col1 <> '' AND #Col2 = '' AND #Col3 = '' AND #Col4 = '' AND #Col5 = '' THEN '#Col1'
WHEN #Col1 = '' AND #Col2 <> '' AND #Col3 = '' AND #Col4 = '' AND #Col5 = '' THEN '#Col2'
WHEN #Col1 = '' AND #Col2 = '' AND #Col3 <> '' AND #Col4 = '' AND #Col5 = '' THEN '#Col3'
WHEN #Col1 = '' AND #Col2 = '' AND #Col3 = '' AND #Col4 <> '' AND #Col5 = '' THEN '#Col4'
ELSE NULL
END
SQL Server 2012+:
SELECT #String = COALESCE(IIF(#Col1 <> '', '#Col1', NULL),
IIF(#Col2 <> '', '#Col2', NULL),
IIF(#Col3 <> '', '#Col3', NULL),
IIF(#Col4 <> '', '#Col4', '' ));
EDIT:
DECLARE #Col1 VARCHAR(10) = ''
DECLARE #Col2 VARCHAR(10) = ''
DECLARE #Col3 VARCHAR(10) = ''
DECLARE #Col4 VARCHAR(10) = ''
DECLARE #Col5 VARCHAR(10) = ''
DECLARE #String VARCHAR(MAX) = '';
IF #col1 <> ''
SET #String += '#col1';
IF #col2 <> ''
SET #String += '#col2';
IF #col3 <> ''
SET #String += '#col3';
...
IF #coln <> ''
SET #String += '#coln';
I would like to help as well, sorry for a different approach.
I took your case as something that can be stacked and I arrived at this.
DECLARE #Col1 VARCHAR(10) = 'test'
DECLARE #Col2 VARCHAR(10) = ''
DECLARE #Col3 VARCHAR(10) = 'tet'
DECLARE #Col4 VARCHAR(10) = ''
DECLARE #Col5 VARCHAR(10) = 't'
DECLARE #String VARCHAR(MAX)
CREATE TABLE #cols (ColName NVARCHAR(150), ColVal NVARCHAR(150))
INSERT INTO #cols VALUES ('#Col1',#Col1),('#Col2',#Col2),('#Col3',#Col3),('#Col4',#Col4),('#Col5',#Col5)
-- if you want to just concatenate things without a delimiter, you can do this
SET #String = (SELECT ColName AS [text()] FROM #cols WHERE ColVal != '' FOR XML PATH(''))
SELECT #String
-- output #Col1#Col3#Col5
-- if you want to concatenate things with a delimiter, you can do this
SET #String = (SELECT ColName + ', ' AS [text()] FROM #cols WHERE ColVal != '' FOR XML PATH(''))
SELECT #String
-- output #Col1, #Col3, #Col5
DROP TABLE #cols
Hope this adds something to the idea. Please let me know if you have concerns.
You can do in one statement using case expressions:
SELECT #String = CASE WHEN #Col1 = '' THEN 'col1' ELSE '' END +
CASE WHEN #Col2 = '' THEN 'col2' ELSE '' END +
CASE WHEN #Col3 = '' THEN 'col3' ELSE '' END +
CASE WHEN #Col4 = '' THEN 'col4' ELSE '' END +
CASE WHEN #Col5 = '' THEN 'col5' ELSE '' END

Resources