Generate BOD OAGIS XML from SQL Server - sql-server

I need to generate an XML document from SQL Server that conforms to the BOD OAGIS schema.
I have a partial solution but am not getting the exact format I need.
This is my query:
SELECT
(
SELECT Customer As 'SalesOrderHeader/CustomerParty/ID',
(
SELECT LinesNo As 'LineNumber'
FROM LinesInterfaccia
WHERE HeaderInterfaccia.OrderNo = LinesInterfaccia.OrderNo
FOR XML path('salesline'), TYPE
)
FROM HeaderInterfaccia
FOR XML path('salesorder'), type
).query('for $i in /salesorder return <DataArea>{$i}</DataArea>');
This is my result:
<DataArea>
<salesorder>
<SalesOrderHeader>
<CustomerParty>
<ID>BP00003184</ID>
</CustomerParty>
</SalesOrderHeader>
<salesline>
<LineNumber>10</LineNumber>
</salesline>
<salesline>
<LineNumber>20</LineNumber>
</salesline>
</salesorder>
</DataArea>
<DataArea>
<salesorder>
<SalesOrderHeader>
<CustomerParty>
<ID>BP00003184</ID>
</CustomerParty>
</SalesOrderHeader>
<salesline>
<LineNumber>10</LineNumber>
</salesline>
</salesorder>
</DataArea>
but I need this format:
<DataArea>
<Process>tenant</Process>
<salesorder>
<SalesOrderHeader>
<CustomerParty>
<ID>BP00003184</ID>
</CustomerParty>
</SalesOrderHeader>
<salesline>
<LineNumber>10</LineNumber>
</salesline>
<salesline>
<LineNumber>20</LineNumber>
</salesline>
</salesorder>
</DataArea>
<DataArea>
<Process>tenant</Process>
<salesorder>
<SalesOrderHeader>
<CustomerParty>
<ID>BP00003184</ID>
</CustomerParty>
</SalesOrderHeader>
<salesline>
<LineNumber>10</LineNumber>
</salesline>
</salesorder>
</DataArea>
I also tried:
SELECT
(
SELECT 'tenant' as 'Process',
Customer As 'SalesOrderHeader/CustomerParty/ID',
(select LinesNo as 'LineNumber/no'
with result:
<DataArea>
<salesorder>
<Process>tenant</Process>
<SalesOrderHeader>
My expected structure is:
<DataArea>
<Process>
</Process>
<SalesOrder>
<SalesLine>
</Salesline>
<SalesLine>
</Salesline>
</salesOrder>
</DataArea>

Try it like this:
DECLARE #tblOrder TABLE(OrderID INT IDENTITY, CustomerID VARCHAR(100));
INSERT INTO #tblOrder VALUES('BP00003184')
,('One More');
DECLARE #tblOrderLine TABLE(OrderLineID INT IDENTITY, OrderID INT, LineNumber INT);
INSERT INTO #tblOrderLine VALUES(1,10),(1,20)
,(2,22),(2,33);
SELECT 'tenant' AS Process
,o.CustomerID AS [salesorder/SalesOrderHeader/CustomerParty/ID]
,(
SELECT LineNumber
FROM #tblOrderLine AS ol
WHERE ol.OrderID=o.OrderID
FOR XML PATH('salesline'),TYPE
) AS salesorder
FROM #tblOrder AS o
FOR XML PATH('DataArea');
This structure is missing a root element, which is - by definition invalid XML. SQL Server has no problem with this, but other engines might have...
You can think of the process as such:
Go down the columns of the select
Oh, there's a new XPath (Process), let's open a new tag
Oh, the next one is new, close /Process
Uh, quite large (salesorder/SalesOrderHeader/CustomerParty/ID), open it!
Ah, this is an XML itself. It will be called salesorder. Nice! still open!
Good, I found the FROM, let's close the current XPath

Related

Snowflake/DBT Incremental table, inserting checksum value on the fly

I have an incremental table in dbt (running on snowflake), that I need to create a checksum (ie hash on all columns except metadata columns) from the original table I am creating. I have the query below - (I also referenced help form this post to create said query). Is this even the right approach to take to a)get an initial table loaded & b) have it load every day? (ie run --full refresh in dbt and then schedule --run daily)?
/*Set schema to vault */
{{ config(
schema = 'vault',
materialized = 'incremental',
unique_key = 'o_hashdiff'
) }}
with values_table as (
SELECT
sha2_binary(id, 256) AS o_hash_id,
id AS o_id,
min(pbi_import_dt) AS load_timestamp,
's.a' AS record_source,
CAST(
sha2_binary(
CONCAT_WS(
'||',
IFNULL(
NULLIF(UPPER(TRIM(CAST(id AS VARCHAR))), ''),
'^^'
),
IFNULL(
NULLIF(
UPPER(
TRIM(CAST('s.a' AS VARCHAR))
),
''
),
'^^'
)
),
256
) AS BINARY(64)
) AS o_hashdiff,
current_date() AS insert_date,
'{{ invocation_id }}' AS _audit_invocation_id
FROM
{{ source ('s', 'a') }}
WHERE
ultimate_id_c IS NULL
GROUP BY
1,
2,
4
)
SELECT t1.*,
t2.hash_value
FROM values_table as t1
,LATERAL (SELECT HASH(*) AS hash_value
FROM (SELECT * EXCLUDE (a,b,c)
FROM {{ source ('s', 'a') }} AS t2
WHERE t1.o_id = t2.id and t2.date is null)
) AS t2

export multiple table with ssis

I have 2 tables are like this (Table1 and Table2)
ID NAME No Addrress Notes
------------ ----------------------------
1 John 111 USA Done
2 Steve 222 Brazil Done
Now I want to create a SSIS package which will create a csv file like:
Table1;ID;NAME
Table2;No;Addrress;Notes
"Detail1";"1";"John";"2";"Steve"
"Detail2";"111";"USA";"Done";"222";"Brazil";"Done"
Can we achieve the same output? I have searched on google but haven't found any solution.
Please help ....
You can create a script task to generate a CSV file for you which can handle your issue:
You can try this:
SqlConnection sqlCon = new SqlConnection("Server=localhost;Initial Catalog=LegOgSpass;Integrated Security=SSPI;Application Name=SQLNCLI11.1");
sqlCon.Open();
SqlCommand sqlCmd = new SqlCommand(#"Select ID,Name from dbo.Table1", sqlCon);
SqlDataReader reader = sqlCmd.ExecuteReader();
string fullpath = #"C:\Users\thoje\Desktop\stack\New folder\table1.csv";
StreamWriter sw = new StreamWriter(fullpath);
object[] output = new object[reader.FieldCount];
for (int i = 0; i < reader.FieldCount; i++)
output[i] = reader.GetName(i);
sw.WriteLine(#"Table1;"+string.Join(";", output));
List<object> values = new List<object>();
while (reader.Read())
{
reader.GetValues(output);
values.Add($"\"{output[0]}\"");
values.Add($"\"{output[1]}\"");
}
sw.WriteLine(#"""Detail1"";"+ string.Join(";", values));
sw.Flush();
sw.Close();
reader.Close();
sqlCon.Close();
Dts.TaskResult = (int)ScriptResults.Success;
Result:
You really should put in your question what you have tried so far, it helps out a lot and makes it more fun to help people.
The two ways I can think of in t-sql to solve this still need you to specify in your code what your column names are. You can get around this with using dynamic SQL and creating a view that spits out data in the same fashion for all the tables you need.
If SSIS is more your thing you could use the dynamic approach with BIML.
--Option 1 (SQL Server 2008 R2 and later)
with Table1 AS (
SELECT * FROM (values(1,'John'),(2,'Steve')) AS x(ID,NAME)
)
,Table2 AS (
SELECT * FROM (values(111,'USA','Done'),(222,'Brazil','Done'))AS y(No,Addrress,Notes)
)
SELECT '"Detail1"'+ CAST(foo as VARCHAR(4000))
FROM (
SELECT ';"' + CAST(ID AS VARCHAR(4))+'";"' + [NAME] +'"' FROM Table1 FOR XML PATH('')
) AS bar(foo)
UNION ALL
SELECT '"Detail2"'+ CAST(foo as VARCHAR(4000))
FROM (
SELECT ';"' + CAST([No] AS VARCHAR(4))+'";"' + [Addrress] +'";"' + [Notes] +'"' FROM Table2 FOR XML PATH('')
) AS bar(foo)
--Option 2 (SQL Server 2017 and later)
with Table1 AS (
SELECT * FROM (values(1,'John'),(2,'Steve')) AS x(ID,NAME)
)
,Table2 AS (
SELECT * FROM (values(111,'USA','Done'),(222,'Brazil','Done'))AS y(No,Addrress,Notes)
)
SELECT '"Detail1";' + STRING_AGG('"'+CAST(ID AS varchar(4))+'";"'+[NAME]+'"',';') FROM Table1
UNION ALL
SELECT '"Detail2";' + STRING_AGG('"'+CAST([No] AS varchar(4))+'";"'+[Addrress]+'";'+'"'+[Notes]+'"',';') FROM Table2
;

Add count to the root elements using FOR XML PATH

I have a Sql statement that returns xml of products in which root element is products. How can i add count attribute to the root element.
My sql is:
SELECT
id AS 'product_id',
name AS 'product_name'
FROM product
WHERE status = 1 AND ......
ORDER BY productid
FOR XML PATH('product'), ROOT('products')
Result is
<products>
<product>
.
.
</product>
</products>
I want to change result to
<products count="100">
<product>
.
.
</product>
</products>
SELECT
COUNT(*) AS '#count',
(
SELECT *
FROM product c1 FOR XML PATH('product'), TYPE
)
FROM product ct FOR XML PATH('products')
The easiest way to filter is to add condition in both query and sub-query:
SELECT
COUNT(*) AS '#count',
(
SELECT *
FROM product c1
WHERE c1.status = 1 AND ......
FOR XML PATH('product'), TYPE
)
FROM product ct
WHERE ct.status = 1 AND ......
FOR XML PATH('products')
Or use temp-table:
SELECT *
INTO #Temp
FROM product c1
WHERE c1.status = 1 AND ......
SELECT
COUNT(*) AS '#count',
(
SELECT *
FROM #Temp c1
FOR XML PATH('product'), TYPE
)
FROM #Temp ct
FOR XML PATH('products')

combine row for each Unique value based on datetime

I have a table with three column
TICKET_ID ASSIGN ASSIGN_DATE
5692 ASSIGN-5 2013-07-17 19:37:09.000
5740 ASSIGN-5 2013-07-17 19:37:09.000
5741 ASSIGN-5 2013-07-17 19:37:09.000
5742 ASSIGN-5 2013-07-17 10:40:15.000
5742 ASSIGN-4 2013-07-17 19:37:09.000
I need to combine ASSIGN row to one row for each TICKET_ID based on datetime ascending result should be like this
TICKET_ID ASSIGN
5692 ASSIGN-5
5740 ASSIGN-5
5741 ASSIGN-5
5742 ASSIGN-4 ASSIGN-5
how can I build the result ?
You can use FOR XML PATH('')
WITH SampleData(TICKET_ID, ASSIGN, ASSIGN_DATE) AS(
SELECT 5692, 'ASSIGN-5', CAST('2013-07-17 19:37:09.000' AS DATETIME) UNION ALL
SELECT 5740, 'ASSIGN-5', '2013-07-17 19:37:09.000' UNION ALL
SELECT 5741, 'ASSIGN-5', '2013-07-17 19:37:09.000' UNION ALL
SELECT 5742, 'ASSIGN-5', '2013-07-17 10:40:15.000' UNION ALL
SELECT 5742, 'ASSIGN-4', '2013-07-17 19:37:09.000'
)
SELECT
TICKET_ID,
ASSIGN = STUFF((
SELECT ' ' + ASSIGN
FROM SampleData
WHERE TICKET_ID = sd.TICKET_ID
ORDER BY ASSIGN_DATE ASC
FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'
), 1, 1, '')
FROM SampleData sd
GROUP BY sd.TICKET_ID
Read this article by Aaron Bertrand for more details.
Here is the Required Result Set .. given two solution first is simply join two table on the basis of ticket id , 2nd join on the basis of Assign row it will give 13 rows
----------1st-------------------
Select T.*,A.* from Tikets T with(nolock)
join
Assignement A with(nolock)
on a.TICKET_ID = t.TICKET_ID
order by t.ASSIGN_DATE
-----------2nd-----------------
Select T.*,A.* from Tikets T with(nolock)
join
Assignement A with(nolock)
on a.ASSIGN like t.ASSIGN +'%'
order by t.ASSIGN_DATE
enter link description here
Thanks

SQL Server 2008 Flatten Rows

I need to flatten a record set that originally has 4 rows per user to be 1 row. I started using the PIVOT functionality but there are 2 fields that need to be flatten (and the pivot wasn't working as expected ).
The current data structure:
ContactEmail Scenario TRE Updated_On
-------------------------------------------------------------
email#email.com WTD 0.9785 2015-05-12 22:35:14.993
email#email.com MTD 0.9817 2015-05-12 22:35:57.780
email#email.com QTD 0.9542 2015-05-12 23:16:35.227
email#email.com YTD 0.9522 2015-05-12 23:39:56.533
The result should be:
ContactEmail WTD_TRE WTD_TRE_Updated MTD_TRE MTD_TRE_Updated QTD_TRE QTD_TRE_Updated YTD_TRE YTD_TRE_Updated
--------------------------------------------------------------------------------------------------------------------
email#email.com 0.9785 2015-05-12 0.9817 2015-05-12 0.9542 2015-05-12 0.9522 2015-05-12
If you're curious about the PIVOT I tried, here it is (the TRE_* were all null)
SELECT *
FROM (SELECT ContactEmail, Round((ISNULL(TRE, 0) * 100), 1) AS "TRE", Scenario, Updated_On
FROM [server].[db].[schema].[table]) AS TREData
PIVOT
(
SUM(TRE)
FOR Scenario
IN ([TRE_WTD],[TRE_MTD],[TRE_QTD],[TRE_YTD])
) AS PivotTable;
Create two pivot queries and join them...
WITH CurrentDataStructure as (
SELECT 'email#email.com' ContactEmail,
'WTD' Scenario,
0.9785 TRE,
'2015-05-12 22:35:14.993' Updated_On
UNION SELECT 'email#email.com', 'MTD', 0.9817, '2015-05-12 22:35:57.780'
UNION SELECT 'email#email.com', 'QTD', 0.9542, '2015-05-12 23:16:35.227'
UNION SELECT 'email#email.com', 'YTD', 0.9522, '2015-05-12 23:39:56.533'
), TREData as (
SELECT ContactEmail, Round((ISNULL(TRE, 0) * 100), 1) TRE, Scenario, Updated_On
FROM CurrentDataStructure
), TREs AS (
SELECT *
FROM (SELECT ContactEmail, Scenario, TRE FROM TREData) TREData
PIVOT
(
SUM(TRE)
FOR Scenario
IN ([WTD],[MTD],[QTD],[YTD])
) PivotTable
), TREsUpdated AS (
SELECT *
FROM (SELECT ContactEmail, Scenario, Updated_On FROM TREData) TREData
PIVOT
(
MAX(Updated_On)
FOR Scenario
IN ([WTD],[MTD],[QTD],[YTD])
) PivotTable
)
SELECT t.ContactEmail,
t.WTD WTD_TRE, u.WTD WTD_TRE_Updated,
t.MTD MTD_TRE, u.MTD MTD_TRE_Updated,
t.QTD QTD_TRE, u.QTD QTD_TRE_Updated,
t.YTD YTD_TRE, u.YTD YTD_TRE_Updated
FROM TREs as t
INNER JOIN
TREsUpdated as u
ON t.ContactEmail = u.ContactEmail
This is tested through and should run just like it is.

Resources