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
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)
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
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.
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
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>
....