Extract all the XML entry key values as rows using SQL - sql

I'm trying to extract the key values (1,2,3) from a single row in a table, but I'm only able to extract a single row at a time using what I know:
cast([attributes] as XML).value('(//Map/entry[#key="catalogItem"]/value/Map/entry/#key)[1]','VARCHAR(20)')
Depending on what number I put in the [x] I get that entry.
I tried removing the [x] and got the error: XQuery [value()]: 'value()' requires a singleton (or empty sequence), found operand of type 'xdt:untypedAtomic *'
<Map>
<entry key="catalogItem">
<value>
<Map>
<entry key="1" value="x"/>
<entry key="2" value="y"/>
<entry key="3" value="z"/>
I want the results to be a single column
1
2
3

Please try the following solution.
A combination of XQuery methods .nodes() and .value() gives what you need.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (id INT IDENTITY PRIMARY KEY, XMLColumn XML);
INSERT INTO #tbl (XMLColumn) VALUES
(N'<Map>
<entry key="catalogItem">
<value>
<Map>
<entry key="1" value="x"/>
<entry key="2" value="y"/>
<entry key="3" value="z"/>
</Map>
</value>
</entry>
</Map>');
-- DDL and sample data population, end
SELECT t.*
, c.value('#key', 'INT') AS [key]
FROM #tbl AS t
CROSS APPLY XMLColumn.nodes('/Map/entry/value/Map/entry') AS t1(c);
Output
id
key
1
1
1
2
1
3

Related

How to copy the the data from one Table to another Table Using Liquibase scripts

I want to know the solution for the below Test ( to copy the the data from one Table to another Table) using Liquibase a part of Corda.
Case: As part of I want to create a new table into an existing database which has already a table called TableA (which has id, name, value columns) which has some data init, I have created a TableB (which has same id, name, value columns) and I wanted to copy the data from TableA to TableB.
For that I had used the following liquibase script as suggested here in Liquibase and In-order to test I had connected to PostgreSQL DB and connected schema called "corda_schema" which has the tables.
<changeSet author="liquibase.corda" id="update-table">
<update schemaName="corda_schema" tableName="TableB">
<column name="id" valueComputed="(SELECT id from TableA)"/>
<column name="name" valueComputed="(SELECT name from TableA)"/>
<column name="value" valueComputed="(SELECT value from TableA)"/>
</update>
</changeSet>
I was getting the following error when I tried with the Liquibase update script
Error: liquibase.corda failed
Error: schema "CORDA_SCHEMA" not found in SQL statement
If I don't given the schema name in update like this
<update tableName="TableB">
<column name="value" valueComputed="(SELECT value from TableA)"/>
</update>
the Liquibase is searching in the Public schema for TableA and I get this error:
Error: liquibase.corda failed Error: schema "PUBLIC" not found in SQL statement`
And also I tried this Liquibase script changeSet by creating the table itself I tried to update data, this changeSet is running and table is created but data is not copied.
<changeSet author="liquibase.corda" id="update-table">
<createTable schemaName = "corda_schema" tableName="TableB">
<column name="id" valueComputed= "(SELECT id FROM TableA)"/>
</createTable>
</changeSet>
Please suggest anything I am missing or any other usages that will make my test success to get the data from one table to another table.
Thanks in advance.
I would suggest to just use custom sql:
<changeSet author="liquibase.corda" id="insert-table">
<sql>
insert into corda_schema.TableB
select id,name,value from corda_schema.TableA;
</sql>
</changeSet>

Search for a particular column name from with a XML column in SQL Server

Just wanted to get some help here. I have a situation where I need to find some data from within the <Column Name> tag as shown in the XML below.
I had a issue where some badly formatted data was exported in the system, I found that piece but now there is a process where I IMPORT data out of the system. Now I have a table which contains XML stored.
I have to iterate through the whole table to see if that column name exists in that particular ID column and if it does I will return the ID. Say for example my table name is Sample and the columns are (ID, ImportXML).
Any help on how I can achieve this ? New to dealing with XML from within SQL Server.
<?xml version="1.0" encoding="UTF-8"?>
<ExportConfiguration id="SampleExport">
<definitions>
<ClientName Value="Sample"/>
<FileType Value="XML"/>
<FileName>
<Value Value="SomeValue"/>
</FileName>
<Columns>
<Column Name="abc" DataType="String" Value="test123"/>
<Column Name="findthis" DataType="String" Value="Test456"/>
</Columns>
</definitions>
</ExportConfiguration>
So basically from the above mentioned code I want to get the value from within <Columns>/<Column Name> = "findthis" so basically findthis is my keyword and I want to get all the ID's of the columns which contain the keyword findthis just for argument sake.
Something like this:
-- Test table.
declare #xTable table (ID int identity(1,1) primary key clustered, XMLData xml)
-- Insert an XML document. I only did one, but the same would work for multiple
insert into #xTable
select '<?xml version="1.0" encoding="UTF-8"?>
<ExportConfiguration id="SampleExport">
<definitions>
<ClientName Value="Sample"/>
<FileType Value="XML"/>
<FileName>
<Value Value="SomeValue"/>
</FileName>
<Columns>
<Column Name="abc" DataType="String" Value="test123"/>
<Column Name="findthis" DataType="String" Value="Test456"/>
</Columns>
</definitions>
</ExportConfiguration>'
-- Return everything from the table with your XML where there is an attribute at the path "/ExportConfiguration/definitions/Columns/Column" with the name "Name" and the value "findthis"
select *
from #xTable
where XMLData.exist('/ExportConfiguration/definitions/Columns/Column[#Name eq "findthis"]') = 1

Update statement in JdbcBatchItemWriter

I am not able to update the database table correctly using JdbcBatchItemWriter. Below is the code fragment. insert on an empty table is getting correct response but update is not happening on input table.
<bean id="odbWriter" class="org.springframework.batch.item.database.JdbcBatchItemWriter">
<property name="dataSource" ref="dataSource"></property>
<property name="sql">
<value>
<![CDATA[
update employeethree set salary = :salary, designation = :designation, promotioneligibility = :promotionEligibility
]]>
</value>
</property>
<property name="itemSqlParameterSourceProvider">
<bean
class="batchjobreaddb.CustomBeanPropertyItemSqlParameterSourceProvider" />
</property>
If i change the query inside CDATA to :
insert into employeetwo values(:empId, :empName, :dept , :salary, :designation, :experienceInMonths, :promotionEligibility)
then it's getting me the desired results. (EmployeeTwo has same structure but is empty.)
Please help. Thanks :)
Your UPDATE query has no WHERE clause. How are you to know which record to update?
For proper update behavior, you must specify a WHERE clause that properly identifies the record(s) you wish to modify with the UPDATE query.
This is obviously not necessary with an INSERT query, because you are creating a brand new record and not modifying an existing one.
Assuming from your example INSERT query that the employee id field is empid, try modifying your JdbcBatchItemWriter to set the sql value to:
<property name="sql">
<value>
<![CDATA[
UPDATE employeethree
SET salary = :salary,
designation = :designation,
promotioneligibility = :promotionEligibility
WHERE empid = :empId
]]>
</value>
</property>

Liquibase Insert computed value with multiple ids

I am trying to insert values into a database. I think the SQL would look like this:
INSERT INTO `tb_config` (`name`, `value`, `description`, `unity_id`)
(SELECT 'new_rule', true, 'rule description', id FROM tb_unity );
However, I want to do it with Liquibase, using a changeset:
<changeSet author="Luis Sukys" id="1022" >
<insert tableName="tb_config">
<column name="name">new_rule</column>
<column name="value">false</column>
<column name="descricao">rule description</column>
<column name="unidade_id" valueComputed="SELECT id FROM tb_unity" />
</insert>
</changeSet>
I've seen the use of valueComputed but with a where clause.
The idea is that it includes one row in tb_config for each id in tb_unity.
I am actually getting a 'ValidationFailedException' from liquibase.
Any help?
I use Navicat with MySQL and when I run this code, it includes one new row int tb_config for each row in tb_unity. The field i use from tb_unity is 'id'.
If I have 05 unities in tb_unity, it must add 05 rows in tb_config, with same values, only change the unity's id.
If you try running that SQL using whatever SQL tool you use, you will see that the problem is that you do indeed need a where clause. Which row of tb_unity do you want to use the id from?

How to find xml node id using SQL Server 2012?

I have a column called content in application table that contains XML like this:
<?xml version="1.0" ?>
<XmlData>
<dataitem id="Hello" value="true" />
</XmlData>
This value in one row same like another row and so on
My problem is that now I want to find which rows have an id attribute with the value of Hello.
How can I do this?
Please help me.
Thanks in Advance
You need to study xml Data Type Methods if you want to process XML data with SQL Server. Find below one of possible solutions:
-- Here is your data
declare #YourTable table (
YourXmlField XML
)
insert into #YourTable values (
'<?xml version="1.0" ?>
<XmlData>
<dataitem id="Hello" value="true" />
</XmlData>'
)
-- Here is solution
select x.xmldata.value('(#value)[1]', 'varchar(10)')
from #YourTable t
cross apply t.YourXmlField.nodes('/XmlData/dataitem') x(xmldata)