Java Ibatis Iterate List - ibatis

Java i am using ibatis
using in clause want to iterate inside in clause, every one talking about following solution but when i try it gives me following error.
**Cause: com.ibatis.common.beans.ProbeException: There is no READABLE property named '[]' in class 'java.util.List'**
List entityIds = new ArrayList(2);
entityIds.add(42167777);
entityIds.add(43178455);
(List<EventCategory>)sqlMapClient.queryForList("getEventCategoryByEntityIds", entityIds);
<select id="getEventCategoryByEntityIds" parameterClass="java.util.List" resultMap="eventCategoryDetails">
<![CDATA[
SELECT E.EVENTCATEGORYID, ECAT.Name EVENTCATEGORYNAME, E.EVENTSUBCATEGORYID , ESUBCAT.Name EVENTSUBCATEGORYNAME FROM
Event E (nolock)
JOIN EVENTCATEGORY ECAT (nolock) ON E.EventCategoryId=ECAT.EventCategoryId JOIN EVENTCATEGORY ESUBCAT ON E.EVENTSUBCATEGORYID=ESUBCAT.EventCategoryId
<dynamic prepend="where ENTITYID in ">
<iterate open="(" close=")" conjunction=",">
#[]#
</iterate>
</dynamic>
]]>
</select>
I am sick and tried trying this solution but not working. any help appreciated..

if you watch the ibatis doc you will find the explanation of CDATA in chapter 3.2.3.1. Escaping XML symbols.
Because you are combining SQL and XML in a single document, conflicts can occur. The most common conflict is the greater-than and less-than symbols (><). SQL statements use these symbols as operators, but they are reserved symbols in XML. A simple solution is to "escape" the SQL statements that uses XML reserved symbols within a CDATA element.
<statement
id="selectPersonsByAge" parameterClass=”int” resultClass="person">
<![CDATA[ SELECT * FROM PERSON WHERE AGE > #value# ]]>
</statement>

After reading same kind of problem over the forum, I only removed the <![CDATA[ and it started working.
Does anybody know why this happens? Please share with the rest of us.

Related

SQL: Using XML as input to do an inner join

I have XML coming in as the input, but I'm unclear on how I need to setup the data and statement to get the values from it. My XML is as follows:
<Keys>
<key>246</key>
<key>247</key>
<key>248</key>
</Keys>
And I want to do the following (is simplified to get my point across)
Select *
From Transaction as t
Inner Join #InputXml.nodes('Keys') as K(X)
on K.X.value('#Key', 'INT') = t.financial_transaction_grp_key
Can anyone provide how I would do that? What would my 3rd/4th line in the SQL look like?
Thanks!
From your code I assume this is SQL-Server but you added the tag [mysql]...
For your next question please keep in mind, that it is very important to know your tools (vendor and version).
Assuming T-SQL and [sql-server] (according to the provided sample code) you were close:
DECLARE #InputXml XML=
N'<Keys>
<key>246</key>
<key>247</key>
<key>248</key>
</Keys>';
DECLARE #YourTransactionTable TABLE(ID INT IDENTITY,financial_transaction_grp_key INT);
INSERT INTO #YourTransactionTable VALUES (200),(246),(247),(300);
Select t.*
From #YourTransactionTable as t
Inner Join #InputXml.nodes('/Keys/key') as K(X)
on K.X.value('text()[1]', 'INT') = t.financial_transaction_grp_key;
What was wrong:
.nodes() must go down to the repeating element, which is <key>
In .value() you are using the path #Key, which is wrong on two sides: 1) <key> is an element and not an attribute and 2) XML is strictly case-sensitive, so Key!=key.
An alternative might be this:
WHERE #InputXml.exist('/Keys/key[. cast as xs:int? = sql:column("financial_transaction_grp_key")]')=1;
Which one is faster depends on the count of rows in your source table as well as the count of keys in your XML. Just try it out.
You probably need to parse the XML to a readable format with regex.
I wrote a similar event to parse the active DB from an xmlpayload that was saved on a table. This may or may not work for you, but you should be able to at least get started.
SELECT SUBSTRING(column FROM IF(locate('<key>',column)=0,0,0+LOCATE('<key>',column))) as KEY FROM table LIMIT 1\G

Limit xml-namespaces to only the main root

I have this query
WITH XMLNAMESPACES(DEFAULT 'https://tribunet.hacienda.go.cr /docs/esquemas/2017/v4.2/facturaElectronica'
,'http://www.w3.org/2001/XMLSchema' AS xsd
,'http://www.w3.org/2001/XMLSchema-instance' AS xsi)
SELECT 1 AS [id]
,0 AS [pass]
(
/*Others*/
SELECT
OT.OTH_MESSAGE as Others
FROM [crdx_COREDev1].[dbo].[OTH_OTHERS] as OT
where
OT.OTH_ID=E.OTH_ID
fOR XML PATH ('Others'), type
)
,0 AS [CONSECUTIVE]
FOR XML PATH('FE');
This generates this XML
<FE xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://tribunet.hacienda.go.cr/docs/esquemas/2017/v4.2 /facturaElectronica"> <- CHANGE 2
<id>1</id>
<pass>0</pass>
<CONSECUTIVE>0</CONSECUTIVE>
<Others xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://tribunet.hacienda.go.cr/docs/esquemas/2017/v4.2 /facturaElectronica">
<MESSAGE>MESSAGE</MESSAGE>
</Others>
</FE>
Now my question: I would like only <FE> to show the namespaces, but - as you see in the xml - that declarations appear also in <Others>. How can I limit this to <FE>?
This is an annoying and well known issue and occurs whenever you use namespaces in connection with nested sub-queries in FOR XML queries...
There has been a connect issue for more than 10 years - until it disappaered recently.
It is important to mention, that these repeated namespace declarations are not wrong, just bloating your XML. And it can collide with (to) strict schema validations.
No good solution, just workarounds:
Create the inner XML without the namespace and add the wrapping node on string base, or
Create the namespaces as normal attributes (but not named xmlns) and use REPLACE to change the names.
Both workarounds need a conversion to NVARCHAR(MAX) and back to XML.
I really have no idea, why this was implemented this way...
Find some related examples
here
and here
and here
and here
Attention:
xmlns="https://tribunet.hacienda.go.cr/docs/esquemas/2017/v4.2 /facturaElectronica">
You are using namespace URLs with blanks. This is not allowed...

How to join on spatial functions in Peewee?

I'm struggling with figuring out how to join a table in Peewee based on a fairly common table postgis pattern. I need to join a table based on a postgis function (st_contains). I imagine it would look something like:
Station.select().join(Location, on=fn.ST_Intersects(Station.geom, Location.geom)).where(Location.name == 'Ravenswood')
The above query, if supported, would return all Stations in the Location named Ravenswood. The equivalent SQL would be:
SELECT station.name, station.district, station.line
FROM station INNER JOIN location ON ST_Intersects(station.geom, loc.geom)
WHERE location.name = 'Ravenswood';
Unfortunately my experiments all seem to end with this abbreviated traceback:
File "/Users/j.../python2.7/site-packages/peewee.py", line 1555, in generate_joins
left_field = field.to_field
AttributeError: 'NoneType' object has no attribute 'to_field'
Does peewee support this? I can't find it in the documentation.
Peewee's join generation checked for expressions but not function calls. I have fixed this bug in 61034c5 (released in v2.6.1). If you use peewee master you should be able to run the query now.

SQL "for XML" and built-in functions like "comment()"

I'm writing an SQL select statement which returns XML. I wanted to put in some comments and found a post asking how to do this. The answer seemed to be the "comment()" function/keyword. So, my code looks broadly like this:
select ' extracted on tuesday ' as 'comment()',
(select top 5 id from MyTable for xml path(''),type)
for xml path('stuff')
...which returns XML as follows:
<stuff>
<!-- extracted on tuesday -->
<id>0DAD4B42-CED6-4A68-AB7D-0003E4C127CC</id>
<id>24BD0E5F-8B76-43FF-AEEA-0008AA911ADD</id>
<id>AAFF5BB0-BFFB-4584-BACC-0009684A1593</id>
<id>0581AF24-8C30-408C-9A48-000A488133AC</id>
<id>01E2306D-296A-4FF7-9263-000EEFF42230</id>
</stuff>
In the process of trying to find out more about "comment()", I discovered "data()" as well.
select top 5 id as 'data()' from MyTable for xml path('')
Unfortunately, the names make searching for information on these functions very difficult.
Can someone point me at the documentation on their usage, as well as any other similar functions ?
Thanks,
Edit:
Another would appear to be "processing-instruction(blah)".
Example:
select 'type="text/css" href="style.css"' as 'processing-instruction(xml-stylesheet)',
(select top 5 id from MyTable for xml path(''),type)
for xml path('stuff')
Results:
<stuff>
<?xml-stylesheet type="text/css" href="style.css"?>
<id>0DAD4B42-CED6-4A68-AB7D-0003E4C127CC</id>
<id>24BD0E5F-8B76-43FF-AEEA-0008AA911ADD</id>
<id>AAFF5BB0-BFFB-4584-BACC-0009684A1593</id>
<id>0581AF24-8C30-408C-9A48-000A488133AC</id>
<id>01E2306D-296A-4FF7-9263-000EEFF42230</id>
</stuff>
Here is the link to the BOL info: Columns with the Name of an XPath Node Test.
This details the functionality you are interested in. (It can indeed be a pain to find)
Also you can find quick functional examples here

MyBatis: "Compile-time" mapper params replacement, keeping prepared stmt but making table names configurable?

MyBatis 3.1.1 allows either #{...} for prepared statements params,
or ${...} for every-time replacement.
I am missing something what would allow to parametrize parts of the SQL statement but still keep it prepared statement; i.e. replace during configuration.
How can I do that? Maybe using some SQL fragments?
Update:
I found:
<sql id="userColumns"> id,username,password </sql>
<select id="selectUsers" parameterType="int" resultType="hashmap">
SELECT <include refid="userColumns"/> some_table WHERE id = #{id}
</select>
See http://www.mybatis.org/core/sqlmap-xml.html#sql
This would be it if ${...} could be used inside of it.
I think I found it...
<sql id="userColumns"> id,username,password </sql>
And then
<select id="selectUsers" parameterType="int" resultType="hashmap">
SELECT <include refid="userColumns"/>
FROM some_table
WHERE id = #{id}
</select>
So I will use ${...} in that and that should get me there.
See http://www.mybatis.org/core/sqlmap-xml.html#sql
in my project we have a very simple solution for this case.
We have a String called TABLENAME in the Data Objects.
When we construct the Objects we initialize the tablename.
and in the sqls we have the tablename enquoutet.
in the DataObject:
String TABLENAME;
public String getTABLENAME() {return TABLENAME;}
public void setTABLENAME(String tablename) {this.TABLENAME = TABLENAME;}
in the sqls:
<delete id="simpleDelete" parameterClass="Integer">
delete from ${jdbc.schema}.$TABLENAME$
WHERE ID = #ID#
</delete>
I don't know if this is the best solution, but it works quite well. I am open for better solutions.
Since <sql> doesn't work as needed for this purpose, I filled a feature request.
http://code.google.com/p/mybatis/issues/detail?id=627

Resources