pass list of Pair to myBatis - mybatis

I need to a list of Pair to MyBatis query:
in Mapper:
List<Usage> getUsageByUserLanguagesAndDates(
#Param("userLanguagePairList") List<Pair<String, String>> userLanguageMap,
#Param("startDate") DateTime startDate,
#Param("endDate") DateTime endDate)
List> userLanguageMap looks like this:
List<Pair<String, String>> pairs = Lists.newArrayList;
pairs.add(new Pair("12345", "en-US"));
pairs.add(new Pair("23456", "en-GB"));
...
and the query looks like this:
SELECT
...
FROM
...
WHERE 1=1
AND
(
(l.userid = '12345' AND ll.language_code = 'en-US') OR
(l.userid = '23456' AND ll.language_code = 'en-GB')
)
;
I tried to write the query as:
AND (
<foreach item="userLanguagePair" index="index" collection="userLanguagePairList" open="" separator="," close="">
(
l.userid = #{userLanguagePair.first}
AND
ll.language_code = #{userLanguagePair.second}
)
OR
</foreach>
)
...
but there will be an extra OR at the end:
AND
(
(l.userid = '12345' AND ll.language_code = 'en-US') OR
(l.userid = '23456' AND ll.language_code = 'en-US') OR
)
how can i get rid of the last 'OR'?

From http://www.mybatis.org/mybatis-3/dynamic-sql.html:
<foreach item="item" index="index" collection="list" open="(" separator="," close=")">,
so I'd say your code should be something like this:
...
WHERE 1=1 AND (
<foreach item="userLanguagePair" index="index" collection="userLanguagePairList" open="(" separator="OR" close=")">
l.userid = #{userLanguagePair.first}
AND
ll.language_code = #{userLanguagePair.second}
</foreach>
)
but right now I cannot check if this will generate the correct sentence.

Related

Use result from one operator inside another

I would like in get_birth_date use result from get_all_pets. How can i access it inside get_birth_date? Moreover i would like to print result from get_all_pets, where could i deifne such print()?
Where in my code could i do this?
import datetime
from airflow import DAG
from airflow.providers.postgres.operators.postgres import PostgresOperator
# create_pet_table, populate_pet_table, get_all_pets, and get_birth_date are examples of tasks created by
# instantiating the Postgres Operator
with DAG(
dag_id="postgres_operator_dag",
start_date=datetime.datetime(2020, 2, 2),
schedule_interval="#once",
catchup=False,
) as dag:
create_pet_table = PostgresOperator(
task_id="create_pet_table",
postgres_conn_id="postgres_robert",
sql="""
CREATE TABLE IF NOT EXISTS pet (
pet_id SERIAL PRIMARY KEY,
name VARCHAR NOT NULL,
pet_type VARCHAR NOT NULL,
birth_date DATE NOT NULL,
OWNER VARCHAR NOT NULL);
""",
)
populate_pet_table = PostgresOperator(
task_id="populate_pet_table",
postgres_conn_id="postgres_robert",
sql="""
INSERT INTO pet (name, pet_type, birth_date, OWNER)
VALUES ( 'Max', 'Dog', '2018-07-05', 'Jane');
INSERT INTO pet (name, pet_type, birth_date, OWNER)
VALUES ( 'Susie', 'Cat', '2019-05-01', 'Phil');
INSERT INTO pet (name, pet_type, birth_date, OWNER)
VALUES ( 'Lester', 'Hamster', '2020-06-23', 'Lily');
INSERT INTO pet (name, pet_type, birth_date, OWNER)
VALUES ( 'Quincy', 'Parrot', '2013-08-11', 'Anne');
""",
)
get_all_pets = PostgresOperator(task_id="get_all_pets",postgres_conn_id="postgres_robert", sql="SELECT * FROM pet;")
get_birth_date = PostgresOperator(
task_id="get_birth_date",
postgres_conn_id="postgres_robert",
sql="SELECT * FROM pet WHERE birth_date BETWEEN SYMMETRIC %(begin_date)s AND %(end_date)s",
parameters={"begin_date": "2020-01-01", "end_date": "2020-12-31"},
runtime_parameters={'statement_timeout': '3000ms'},
)
create_pet_table >> populate_pet_table >> get_all_pets >> get_birth_date
PostgresOperator is not suitable for running SELECT statements.
SELECT statements are more suitable for transfer operators or using hooks directly.
In your case you should use the PostgresHook:
from airflow.decorators import task
from airflow.providers.postgres.hooks.postgres import PostgresHook
#task()
def get_all_pets(**kwargs):
hook = PostgresHook(postgres_conn_id="postgres_robert")
df = hook.get_pandas_df(sql="SELECT * FROM pet;")
print(df)

Mybatis When test condition with Internal query

I am looking for a query where i can use either internal query returned value or direct SQL in when test= in Mybatis.
<foreach item="ID"
index="index"
collection="selectionIds"
separator=";">
UPDATE TABLE_1 SET
ACT_IND ='N', upd_by = 1234
WHERE SLCT_ID = #{ID}
AND rem= select REM from TABLE_1 where SLCT_ID=#{ID}
<choose>
<when test="rem == 3">
AND Bbsid=#{nsid}
</when>
<otherwise>
AND asid=#{asid}
</otherwise>
</choose>
</foreach>
From the above query, how can i get the rem value and use in when condition.
Thanks

Collection size in mybatis query

I have a MyBatis query that looks like this:
<if test="userIdList != null and userIdList > 0">
AND galleries.id IN (
SELECT gallery_id
FROM gallery_users
WHERE gallery_id IN (
<foreach collection="userIdList" item="item" separator="," open="(" close=")">
#{item}
</foreach>
)
GROUP BY gallery_id HAVING COUNT(gallery_id) = ???
)
</if>
That part I'm stuck on is getting the collection size which will be dynamic. So how can I get the collection size so that I can properly fill in the '???' value?
You can invoke the Collection#size() method using OGNL expression. i.e.
GROUP BY gallery_id HAVING COUNT(gallery_id) = ${userIdList.size}
Note that #{userIdList.size} won't work here because the expression in #{} is parsed by MyBatis' internal expression parser and not by OGNL.

Orientdb - How do Filter a Match with an Edge Property

Look the Match
SELECT PSQ_psq_nome AS nome, INS_ins_nome AS instituicao, COUNT(PUB_pub_id) AS qtdpub, * FROM (
MATCH
{class:Pais, as:PAI, where:(pai_id=1)} <-NASCEU- {class:Pesquisador, as:PSQ} -PUBLICOU-> {class:Publicacao, as:PUB, where: (pub_data_publicacao_int > 20141231)},
{as:PSQ} -ATUOU-> {class:Instituicao, as:INS}
RETURN PSQ.psq_nome AS nome, INS.ins_nome AS instituicao, PUB.pub_id, PUBLICOU.ordem )
GROUP BY PSQ_psq_nome, INS_ins_nome
ORDER BY qtdpub DESC, nome
I need use the property ordem, type integer, for the edge PUBLICOU. Is it possible?
something like (see PUBLICOU)
SELECT PSQ_psq_nome AS nome, INS_ins_nome AS instituicao, COUNT(PUB_pub_id) AS qtdpub, * FROM (
MATCH
{class:Pais, as:PAI, where:(pai_id=1)} <-NASCEU- {class:Pesquisador, as:PSQ} -PUBLICOU { where: (ordem = 1) -> {class:Publicacao, as:PUB, where: (pub_data_publicacao_int > 20141231)},
{as:PSQ} -ATUOU-> {class:Instituicao, as:INS}
RETURN PSQ.psq_nome AS nome, INS.ins_nome AS instituicao, PUB.pub_id, PUBLICOU.ordem )
GROUP BY PSQ_psq_nome, INS_ins_nome
ORDER BY qtdpub DESC, nome
Sure, but you cannot use arrow notation, eg. you have to replace
{class:Pesquisador, as:PSQ} -PUBLICOU-> {class:Publicacao ...}
with
{class:Pesquisador, as:PSQ} .outE("PUBLICOU"){where:(ordem = 1)}.inV() {class:Publicacao ...}
You can also assign an alias to the edge and return it in the result set if you wish

Mybatis mapper file, parameter was changed to null in foreach statement

Okay, I am trying to generate sql for a Map<String,List<String>>, I am having a nested foreach statements to generate sql. This is my mybatis xml mapper file:
<select id="UserScaleResult.listAccordingToScaleBrief" resultType="java.util.Map">
select distinct uu.id as uid, uu.fullname, ucn.card_number,
uu.mobile_number
from
<include refid="UserScaleResult.baseCondition.from" />
<include refid="UserScaleResult.UserType.from"/>
<include refid="UserScaleResult.listAccordingToScale.from"/>
<include refid="UserScaleResult.baseConditions.where" />
<include refid="UserScaleResult.UserType.where" />
<include refid="UserScaleResult.listAccordingToScale.where" />
limit #{offset}, #{pageSize}
</select>
<sql id="UserScaleResult.listAccordingToScale.where">
<if test="#Ognl#isNotEmpty(type)">
and musr.type = #{type}
</if>
<if
test="#Ognl#isNotEmpty(createTimeBegin) and #Ognl#isNotEmpty(createTimeEnd)">
and musr.create_time between #{createTimeBegin} and
#{createTimeEnd};
</if>
<if test="#Ognl#isNotEmpty(missionId)">
and musr.mission_id = #{missionId}
</if>
<if test="#Ognl#isNotEmpty(scaleId)">
and musr.scale_id = #{scaleId}
</if>
<if test="#Ognl#isNotEmpty(sdl)">
and (
<foreach collection="sdl.entrySet()" item="item" open="(" separator=") or (" close=")">
tsrdl.dimension_id = #{item.key}
<if test="#Ognl#isNotEmpty(item.value)">
and
<foreach collection="item.value" item="iitem" open="(" separator=" or " close=")">
tsrdl.level_id = #{iitem}
</foreach>
</if>
</foreach>
)
</if>
</sql>
The log shows the #{iitem} are all null when it put it down to sql, although the number of parameters are correct:
2016-05-13 14:47:27,837 DEBUG [java.sql.Connection] - <==> Preparing: select count(*) from user_user uu left join user_user_detail uud on uu.id = uud.user_id left join user_card_number ucn on uu.card_number_id =ucn.id left join org_org oo on ucn.org_id = oo.id inner join (SELECT user_id, MAX(IF(extension_item_id=?,DATA,'') )AS ? FROM user_extension_item_data GROUP BY user_id) AS ud on uu.id = ud.user_id inner join mission_user_scale_result musr on uu.id = musr.user_id inner join test_scale ts on musr.scale_id = ts.id inner join test_scale_result_dimension_level tsrdl on tsrdl.result_id = musr.id and ud.3 = ? and ( ( tsrdl.dimension_id = ? and ( tsrdl.level_id = ? or tsrdl.level_id = ? ) ) or ( tsrdl.dimension_id = ? and ( tsrdl.level_id = ? or tsrdl.level_id = ? or tsrdl.level_id = ? ) ) ) >
2016-05-13 14:47:27,838 DEBUG [java.sql.PreparedStatement] - <==> Parameters: 3(String), 3(String), 保密(String), 42(String), null, null, 47(String), null, null, null>
EDIT:
Just did some experiment, when I substitute the '#' sign in #{iitem} with '$', the value appears and the sql gets parameters all good.
We need to use ${dataBaseTable} instead of #. The difference is that # is used for PreparedStatement substitution. $ is for direct String substitution.
Replace your #{iitem} with ${iitem}
....
<foreach collection="item.value" item="iitem" open="(" separator=" or " close=")">
tsrdl.level_id = ${iitem}
</foreach>
....