Read xml file and put values into sql table by MERGE - mysql

I got an XML file looking like this:
<ns0:Currency xmlns:ns0="http://bla.bla.Currency">
<Currency>
<IntComp>08</IntComp>
<Active>1</Active>
<Currency>USD</Currency>
<Text>US Dollar</Text>
</Currency>
</ns0:Currency>
Edit: I need to take all these fields inside Currency and fit them into table, this should work for all files looking like this. Not only these values.
I want to put these values into my sql table which have the same columns, i would like to Merge these values into the table so it will Update if the IntComp value && Currency match match with another file. And it will Insert if the file doesnt match.
I havent figured out how to write this sql query.
EDIT:
The tables look like this.
dbo.Integration
ID | XMLData | Entity | EntityId | Action | ....
XMLData is the string with XMLData that i want to send to another table and pick out those node from that field.
The other table:
dbo.Currency
ID | IntComp | Active | Currency | Text
This is what ive been trying so far:
SELECT XMLData.value('(/ns0:Currency xmlns:ns0="http://bla.bla.Currency/Currency/IntComp/node())[1]', 'int') as intComp,
XMLData.value('(/ns0:Currency xmlns:ns0="http://bla.bla.Currency/Currency/Active/node())[1]', 'int') as Active,
XMLData.value('(/ns0:Currency xmlns:ns0="http://bla.bla.Currency"/Currency/Currency/node())[1]', 'varchar(10)') as Currency,
XMLData.value('(/ns0:Currency xmlns:ns0="http://bla.bla.Currency"/Currency/text/node())[1]', 'varchar(MAX)') as Active
FROM dbo.Integration

May be you can try something like this..
DECLARE #DocHandle AS INT;
DECLARE #XmlDocument AS NVARCHAR(1000);
SET #XmlDocument = '<ns0:Currency xmlns:ns0="http://bla.bla.Currency"><Currency><IntComp>08</IntComp><Active>1</Active><Currency>USD</Currency><Text>US Dollar</Text></Currency></ns0:Currency>';
EXEC sys.sp_xml_preparedocument #DocHandle OUTPUT, #XmlDocument,'<ns0:Currency xmlns:ns0="http://bla.bla.Currency"/>';
MERGE INTO tmp1 AS TGT
USING (SELECT IntComp,Active,Currency,Text FROM OPENXML (#DocHandle, '/ns0:Currency/Currency',11) WITH (IntComp INT,Active INT,Currency varchar(10),Text nvarchar(100)))
AS SRC ON SRC.IntComp = TGT.IntComp and SRC.Currency = TGT.Currency
WHEN MATCHED THEN UPDATE
SET TGT.IntComp = SRC.IntComp , TGT.Currency = SRC.Currency
WHEN NOT MATCHED THEN INSERT
VALUES(SRC.IntComp,SRC.Active, SRC.Currency, SRC.Text);
select * from tmp1

Related

Querying XML in SQL Server

I'm a newbie to SQL Server. I have a table Accounts which is defined as:
OrganizationId int,
AccountDetails varchar(max)
The AccountDetails column contains XML data.
The data in the table looks like this:
1 | <Account><Id>100</Id><Name>A</Name></Account>
2 | <Account><Id>200</Id><Name>B</Name></Account>
3 | <Account><Id>300</Id><Name>C</Name></Account>
4 | <Account><Id>400</Id><Name>D</Name></Account>
I need write a SQL query to get the records from this table where AccountId is 200 or 400.
The query should return two rows (#2 and #4) in JSON format, like this:
result1 : { "account_id": 200, "account_name": B }
result2 : { "account_id": 400, "account_name": D }
I'm wondering how do I go about this?
Thank you.
For # 1 above, should I be trying to cast the AccountDetails column to XML type and then use "nodes" feature for querying/filtering?
For #2, I should be writing a SQL function to convert the XML to JSON first and querying XML to build the JSON as needed?
As already mentioned, it is much better to use a proper XML data type for the AccountDetails column.
Please try the following solution.
It will work starting from SQL Server 2016 onwards.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (OrganizationId INT IDENTITY PRIMARY KEY, AccountDetails NVARCHAR(MAX));
INSERT #tbl (AccountDetails) VALUES
('<Account><Id>100</Id><Name>A</Name></Account>'),
('<Account><Id>200</Id><Name>B</Name></Account>'),
('<Account><Id>300</Id><Name>C</Name></Account>'),
('<Account><Id>400</Id><Name>D</Name></Account>');
-- DDL and sample data population, end
;WITH rs AS
(
SELECT t.OrganizationId
, account_id = x.value('(/Account/Id/text())[1]', 'INT')
, account_name = x.value('(/Account/Name/text())[1]', 'VARCHAR(20)')
FROM #tbl AS t
CROSS APPLY (VALUES(TRY_CAST(AccountDetails AS XML))) AS t1(x)
)
SELECT *
, JSONData = (SELECT rs.account_id, rs.account_name FOR JSON PATH,WITHOUT_ARRAY_WRAPPER)
FROM rs
WHERE rs.account_id IN (200, 400);
Output
OrganizationId
account_id
account_name
JSONData
2
200
B
{"account_id":200,"account_name":"B"}
4
400
D
{"account_id":400,"account_name":"D"}

How do you add a new object to an existing JSON object in MariaDB?

I have a JSON field with an object in it that contains multiple sub objects. The table looks like this:
+---------+----------------------------------------------------------------+
|store_num| fruit_stock |
+---------+----------------------------------------------------------------+
| AL258 | '{"fruits":{"apple":67,"banana":91,"plum":53}}' |
+---------+----------------------------------------------------------------+
| OR419 | '{"fruits":{"apple":109,"banana":44,"plum":98}}' |
+---------+----------------------------------------------------------------+
I want to add an object {"mango":45} to the "AL258" store using prepared statement. I came accross some issues doing this. First was adding an object to another object was not as straight forward as I thought it would be. It turns out I had to create the mango object using the JSON_OBJECT() funtion to start with so:
JSON_OBJECT("mango", 45)
'{"mango":45}'
I then had to get the contents of the "fruits" object so I had to use the JSON_QUERY() function for that:
JSON_QUERY(fruit_stock, '$.fruits')
'{"apple":67, "banana":91, "plum":53}'
Then had to merge the new mango object and the contents of the fruits object. Since I want to replace the field I'm inserting if it already exists I needed to use the JSON_MERGE_PATCH() function:
JSON_MERGE_PATCH(
JSON_QUERY(fruit_stock, '$.fruits'), -- the contents of fruit_stock: '{"apple":67,"banana":91,"plum":53}'
JSON_OBJECT("mango", 45) -- the new mango object: '{"mango":45}'
)
Now that I have the naked object fields '{"apple":67, "banana":91, "plum":53}', and '{"mango":45}' I needed to combine them into the "fruits" object. To do this I needed to create an entirely new "fruits" object using the JSON_OBJECT() function:
JSON_OBJECT(
'fruits', -- the new fruits object
JSON_MERGE_PATCH( -- the contents of fruit_stock
JSON_QUERY(fruit_stock, '$.fruits'), -- the new mango object
JSON_OBJECT("mango", 45)
)
)
'{"fruits":{"apple":67, "banana":91, "plum":53, "mango":45}}'
Adding in a WHERE clause to select the store...
UPDATE store_table SET fruit_stock =
JSON_OBJECT(
'fruits',
JSON_MERGE_PATCH(
JSON_QUERY(fruit_stock, '$.fruits'),
JSON_OBJECT("mango", 45)
)
)
WHERE HEX(store) = 'AL258';
Results in the following table:
+---------+----------------------------------------------------------------+
|store_num| fruit_stock |
+---------+----------------------------------------------------------------+
| AL258 | '{"fruits":{"apple":67,"banana":91,"plum":53,"mango":45}}' |
+---------+----------------------------------------------------------------+
| OR419 | '{"fruits":{"apple":109,"banana":44,"plum":98}}' |
+---------+----------------------------------------------------------------+
My question: Is this the best way to do this, or is there a more efficient and/or readable option using MariaDB?
Just use the similar syntax as the existing jsons for the values to be added by using JSON_MERGE_PATCH() function :
UPDATE store_table
SET fruit_stock = JSON_MERGE_PATCH(fruit_stock, '{"fruits":{"mango": 45}}')
WHERE store_num = 'AL258';
Demo

How detect the two word of a string like “helpme”?

I have a dictionary table (words) and another table with concatenated 2 words like "helpme", "helloword" "loveme"...
I want to transform this table to "help me", "hello word", "love me"
I run this sequence :
SELECT
table_concatened.twowords,
t1.word as 'word1',
t2.word as 'word2'
FROM
table_concatened
JOIN dictionary_table AS t1 ON SUBSTRING(table_concatened.twowords,1,len(t1.word)) = t1.word
JOIN dictionary_table AS t2 ON SUBSTRING(table_concatened.twowords,len(t1.word)+1,len(table_concatened.twowords)) = t2.word;
It is working, but is took a very long time with my table.
How can I optimise my sql sequence?
---- exemple of table ---
dictionary_table
|hello|
|word |
|love |
|me |
exemple of table_concatened :
|helloword|
|loveyou |
Edit:
1) The use case is for autocorrection. For example on skype, on iPhone, on chrome, when I type "helloword", I have auto correction to "hello word".
2) The database here is not very important. Our issue is about algo logic and performance optimisation.
If you don't mind going dynamic (and if SQL Server)
-- Generate Some Sample Data
Declare #Dictionary_Table table (word varchar(50));Insert Into #Dictionary_Table values ('hello'),('word'),('love'),('me')
Declare #table_concatened table (ID int,twowords varchar(50));Insert Into #table_concatened values (1,'helloword'),(2,'loveyou')
-- Generate SQL and Execute
Declare #SQL varchar(max)=''
Select #SQL = #SQL+concat(',(',ID,',''||',replace(twowords,'''',''''''),'||'')') From #table_concatened --Where ID=2
Select #SQL = Replace(#SQL,MapFrom,MapTo)
From (
Select MapFrom = word
,MapTo = '|'+ltrim(rtrim(word))+'|'
From #Dictionary_Table
Union All
Select '|',' ' -- Remove Any Remaining |
Union All
Select ' ',' ' -- Remove Any Remaining |
) A
Select #SQL = 'Select ID,Value=ltrim(rtrim(Value)) From ('+Stuff(#SQL,1,1,'values')+') N(ID,Value)'
Exec(#SQL)
Returns
ID Value
1 hello word
2 love you

SQL - The used select statement have a different number of colums

I'm trying to make my first function, it creates without any error, but, when I try to use it it gives me error.
Here's the function -
CREATE FUNCTION isie_kontakti (condition CHAR(3))
RETURNS CHAR(100)
BEGIN
DECLARE returnthis CHAR(100);
SELECT DISTINCT Person.name, Person.lastName, Contacts.mobile, Contacts.email
FROM Person JOIN Contacts on Contacts.Person_ID = Person.ID
JOIN ParentChild on ParentChild.parentID = Person.ID
JOIN ChildGroup ON ChildGroup.Person_ID = ParentChild.childID
WHERE ChildGroup.Group_ID = 'condition' INTO returnthis;
RETURN returnthis;
END//
Table schema - http://www.imagesup.net/dm-713886347846.png
You create your function to return a single column of type char(100) yet the returnthis item contains quite a few columns.
You need to match up your query and return type.
How you do that depends on what you're trying to achieve. It's possibly as simple as just concatenating the columns from the select into a single variable, something along the lines of (untested since I don't have my DBMS available at the moment):
SELECT Person.name | ' '
| Person.lastName | ' '
| Contacts.mobile | ' '
| Contacts.email
FROM ...

SQL query to remove certain text from each field in a specific column?

I recently recoded one of my sites, and the database structure is a little bit different.
I'm trying to convert the following:
*----*----------------------------*
| id | file_name |
*----*----------------------------*
| 1 | 1288044935741310953434.jpg |
*----*----------------------------*
| 2 | 1288044935741310352357.rar |
*----*----------------------------*
Into the following:
*----*----------------------------*
| id | file_name |
*----*----------------------------*
| 1 | 1288044935741310953434 |
*----*----------------------------*
| 2 | 1288044935741310352357 |
*----*----------------------------*
I know that I could do a foreach loop with PHP, and explode the file extension off the end, and update each row that way, but that seems like way too many queries for the task.
Is there any SQL query that I could run that would allow me to remove the file exentision from each field in the file_name column?
You can use the REPLACE() function in native MySQL to do a simple string replacement.
UPDATE tbl SET file_name = REPLACE(file_name, '.jpg', '');
UPDATE tbl SET file_name = REPLACE(file_name, '.rar', '');
This should work:
UPDATE MyTable
SET file_name = SUBSTRING(file_name,1, CHAR_LENGTH(file_name)-4)
This will strip off the final extension, if any, from file_name each time it is run. It is agnostic with respect to extension (so you can have ".foo" some day) and won't harm extensionless records.
UPDATE tbl
SET file_name = TRIM(TRAILING CONCAT('.', SUBSTRING_INDEX(file_name, '.', -1) FROM file_name);
You can use SUBSTRING_INDEX function
SUBSTRING_INDEX(str,delim,count)
Where str is the string, delim is the delimiter (from which you want a substring to the left or right of), and count specifies which delimiter (in the event there are multiple occurrences of the delimiter in the string)
Example:
UPDATE table SET file_name = SUBSTRING_INDEX(file_name , '.' , 1);