๐ŸŒป JAVA/์ž๋ฐ” ORM ํ‘œ์ค€ JPA ํ”„๋กœ๊ทธ๋ž˜๋ฐ

10-2) JPQL - ๊ธฐ๋ณธ ๋ฌธ๋ฒ•๊ณผ ๊ธฐ๋Šฅ

iseunghan 2020. 12. 29. 11:33
๋ฐ˜์‘ํ˜•

์ž๋ฐ” ORM ํ‘œ์ค€ JPA ํ”„๋กœ๊ทธ๋ž˜๋ฐ - ๊ธฐ๋ณธํŽธ์„ ๊ณต๋ถ€ํ•˜๋ฉฐ ์ •๋ฆฌํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

 

์ž๋ฐ” ORM ํ‘œ์ค€ JPA ํ”„๋กœ๊ทธ๋ž˜๋ฐ - ๊ธฐ๋ณธํŽธ - ์ธํ”„๋Ÿฐ

JPA๋ฅผ ์ฒ˜์Œ ์ ‘ํ•˜๊ฑฐ๋‚˜, ์‹ค๋ฌด์—์„œ JPA๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋งŒ ๊ธฐ๋ณธ ์ด๋ก ์ด ๋ถ€์กฑํ•˜์‹  ๋ถ„๋“ค์ด JPA์˜ ๊ธฐ๋ณธ ์ด๋ก ์„ ํƒ„ํƒ„ํ•˜๊ฒŒ ํ•™์Šตํ•ด์„œ ์ดˆ๋ณด์ž๋„ ์‹ค๋ฌด์—์„œ ์ž์‹ ์žˆ๊ฒŒ JPA๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ดˆ๊ธ‰ ์›น ๊ฐœ๋ฐœ ํ”„๋กœ๊ทธ๏ฟฝ

www.inflearn.com


๋ชฉ์ฐจ

  • JPQL ์†Œ๊ฐœ
  • ํ”„๋กœ์ ์…˜(SELECT)
  • ํŽ˜์ด์ง•
  • ์กฐ์ธ
  • ์„œ๋ธŒ์ฟผ๋ฆฌ
  • JPQL ํƒ€์ž… ํ‘œํ˜„๊ณผ ๊ธฐํƒ€์‹
  • ์กฐ๊ฑด์‹(CASE ๋“ฑ๋“ฑ)
  • JPQL ํ•จ์ˆ˜

 

 

๐Ÿ—’ JPQL ์†Œ๊ฐœ


  • JPQL์€ ๊ฐ์ฒด์ง€ํ–ฅ ์ฟผ๋ฆฌ ์–ธ์–ด์ด๋‹ค. ๋”ฐ๋ผ์„œ ํ…Œ์ด๋ธ”์„ ๋Œ€์ƒ์œผ๋กœ ์ฟผ๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋ฅผ ๋Œ€์ƒ์œผ๋กœ ์ฟผ๋ฆฌํ•œ๋‹ค.
  • JPQL์€ SQL์„ ์ถ”์ƒํ™”ํ•ด์„œ ํŠน์ • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค SQL์— ์˜์กดํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • JPQL์€ ๊ฒฐ๊ตญ SQL๋กœ ๋ณ€ํ™˜๋œ๋‹ค.

 

JPQL ๋ฌธ๋ฒ•

  • select m from Member as m where m.age > 18
    • ์—”ํ‹ฐํ‹ฐ์™€ ์†์„ฑ์€ ๋Œ€์†Œ๋ฌธ์ž ๊ตฌ๋ถ„o (Member, age)
    • JPQL ํ‚ค์›Œ๋“œ๋Š” ๋Œ€์†Œ๋ฌธ์ž ๊ตฌ๋ถ„x (SELECT, FROM, where)
    • ์—”ํ‹ฐํ‹ฐ ์ด๋ฆ„ ์‚ฌ์šฉ, ํ…Œ์ด๋ธ” ์ด๋ฆ„ ์•„๋‹˜!
    • ๋ณ„์นญ์€ ํ•„์ˆ˜(m) (as๋Š” ์ƒ๋žต๊ฐ€๋Šฅ)

์ง‘ํ•ฉ๊ณผ ์ •๋ ฌ

select
    COUNT(m),	// ํšŒ์›์ˆ˜
    SUM(m.age),	// ๋‚˜์ด ํ•ฉ
    AVG(m.age),	// ํ‰๊ท  ๋‚˜์ด
    MAX(m.age),	// ์ตœ๋Œ€ ๋‚˜์ด
    MIN(m.age)	// ์ตœ์†Œ ๋‚˜์ด
from Member m
  • GROUP BY, HAVING
  • ORDER BY

 

๐Ÿ—’ TypeQuery, Query

  • TypeQuery : ๋ฐ˜ํ™˜ ํƒ€์ž…์ด ๋ช…ํ™•ํ•  ๋•Œ ์‚ฌ์šฉ
/* ํƒ€์ž…์ด ๋ช…ํ™•ํ•  ๋•Œ */
TypedQuery<Member> query = em.createQuery("select m from Member m", Member.class);

 

  • Query : ๋ฐ˜ํ™˜ ํƒ€์ž…์ด ๋ช…ํ™•ํ•˜์ง€ ์•Š์„ ๋•Œ ์‚ฌ์šฉ
/* ๋ช…ํ™•ํ•˜์ง€ ์•Š์„ ๋•Œ */
Query query = em.createQuery("select m.username, m.age from Member m");

String(username), int(age) ๋‘๊ฐœ์˜ ํƒ€์ž…์ด ์„ž์—ฌ ์žˆ์–ด์„œ ํƒ€์ž… ์ •๋ณด๋ฅผ ๋ฐ›์•„ ์˜ฌ ์ˆ˜ ์—†์Œ.

 

๊ฒฐ๊ณผ ์กฐํšŒ API

  • query.getResultList()
    • ๊ฒฐ๊ณผ๊ฐ€ ํ•˜๋‚˜ ์ด์ƒ์ผ ๋•Œ, ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜ (๊ฒฐ๊ณผ๊ฐ€ ์—†์„ ๋• ๋น„์–ด์žˆ๋Š” ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜)
  • query.getSingleResult()
    • ๊ฒฐ๊ณผ๊ฐ€ ์ •ํ™•ํžˆ ํ•˜๋‚˜, ๋‹จ์ผ ๊ฐ์ฒด ๋ฐ˜ํ™˜
    • ๋‘˜ ๋‹ค exception ํ„ฐ์ง€๋‹ˆ๊นŒ ์ •๋ง์ •๋ง์ •๋ง ์กฐ์‹ฌํ•ด์„œ ์‚ฌ์šฉ!
    • ๊ฒฐ๊ณผ๊ฐ€ ์—†์œผ๋ฉด: javax.persistence.NoResultException
    • ๋‘˜ ์ด์ƒ์ด๋ฉด: javax.persistence.NonUniqueResultException

 

ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ - ์ด๋ฆ„ ๊ธฐ์ค€, ์œ„์น˜ ๊ธฐ์ค€

์ด๋ฆ„ ๊ธฐ์ค€

select m from Member m where m.username=:username
query.setParameter("username", usernameParam);	// username == usernameParam์ธ ๋ฐ์ดํ„ฐ ์กฐํšŒ

 

์œ„์น˜ ๊ธฐ์ค€

(๋งŒ์•ฝ ์ค‘๊ฐ„์— ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ–ˆ์„ ๋•Œ, ์ธ๋ฑ์Šค๊ฐ€ 1์”ฉ ๋ฐ€๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์—, ์™ ๋งŒํ•ด์„œ๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๊ฒƒ์ด ์ข‹๋‹ค.)

select m from Member m where m.username=?1
query.setParameter(1, usernameParam);

 

๋ฉ”์†Œ๋“œ ์ฒด์ธ ๋ฐฉ์‹์ฒ˜๋Ÿผ ์‚ฌ์šฉ

TypeQuery<Member> query = em.createQuery("select m from Member m where m.username=:username", Member.class);
query.setParameter("username", "member1");
Member singleResult = query.getSingleResult();

/* ๋ฉ”์†Œ๋“œ ์ฒด์ธ ๋ฐฉ์‹ ์‚ฌ์šฉ */
Member result = em.createQuery("select m from Member m where m.username=:username", Member.class)
    .setParameter("username", "member1")
    .getSingleResult();

 

 

๐Ÿ—’ ํ”„๋กœ์ ์…˜


  • ์ •์˜ : SELECT ์ ˆ์— ์กฐํšŒํ•  ๋Œ€์ƒ์„ ์ง€์ •ํ•˜๋Š” ๊ฒƒ
  • ํ”„๋กœ์ ์…˜ ๋Œ€์ƒ : ์—”ํ‹ฐํ‹ฐ, ์ž„๋ฒ ๋””๋“œ ํƒ€์ž…, ์Šค์นผ๋ผ ํƒ€์ž…

์—”ํ‹ฐํ‹ฐ ํ”„๋กœ์ ์…˜

select m from Member m			/* ์—”ํ‹ฐํ‹ฐ ํ”„๋กœ์ ์…˜ 	*/
select m.team from Member m		/* ์—”ํ‹ฐํ‹ฐ ํ”„๋กœ์ ์…˜ 	*/
select m.address from Member m		/* ์ž„๋ฒ ๋””๋“œ ํƒ€์ž… ํ”„๋กœ์ ์…˜ */
select m.username, m.age from Member m	/* ์Šค์นผ๋ผ ํƒ€์ž… ํ”„๋กœ์ ์…˜  */
/* DISTINCT๋กœ ์ค‘๋ณต ์ œ๊ฑฐ */

SELECT๋กœ ์กฐํšŒํ•œ ๋ชจ๋“  member๋“ค์€ ์ „๋ถ€ ๋‹ค ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๊ด€๋ฆฌ ๋œ๋‹ค.

 

List<Team> resultList = em.createQuery("select t from Member m join m.team t", Team.class)
	.getResultList();

join์€ ๋ช…์‹œ์ ์œผ๋กœ ํ‘œํ˜„ ํ•ด์ฃผ๋Š” ๊ฒƒ์ด ์ข‹๋‹ค!

 

ํ”„๋กœ์ ์…˜ - ์—ฌ๋Ÿฌ ๊ฐ’ ์กฐํšŒ

SQL

  • SELECT m.username, m.age FROM Member m
List resultList = em.createQuery("select m.age, m.username from Member m")
	.getResultList();

 

Query ํƒ€์ž…์œผ๋กœ ์กฐํšŒ

Object๊ฐ์ฒด๋ฅผ Object[] ํƒ€์ž… ์บ์ŠคํŒ…ํ•ด์„œ ์‚ฌ์šฉํ•˜๊ธฐ.

Object o = resultList.get(0);
Object[] result = (Object[]) o;	// object๋ฐฐ์—ด์— [m.age, m.username] ์ด๋Ÿฐ ์‹์œผ๋กœ ๋“ค์–ด์žˆ๋‹ค.

System.out.println("age = " + result[0]);	// age
System.out.println("username = " + result[1]);	// username

 

Object[] ํƒ€์ž…์œผ๋กœ ์กฐํšŒ

์ œ๋„ค๋ฆญ์— Object[] ํƒ€์ž… ์„ ์–ธ.

List<Object[]> resultList = em.createQuery("select m.age, m.username from Member m")
	.getResultList();
Object[] result1 = resultList.get(0);

System.out.println("age = " + result1[0]);	// age
System.out.println("username = " + result1[1]);	// username

 

new ๋ช…๋ น์–ด๋กœ ์กฐํšŒ

๊ฐ„๋‹จํ•œ DTO ์ƒ์„ฑํ•ด์„œ DTOํƒ€์ž…์œผ๋กœ ๋ฝ‘๋Š” ๋ฐฉ๋ฒ•

List<MemberDTO> resultList = em.createQuery(
	"select new package๋ช….MemberDTO(m.age, m.username) from Member m", MemberDTO.class)
    .getResultList(); // ๋งˆ์น˜ MemberDTO์˜ ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ ์ฒ˜๋Ÿผ!
    
MemberDTO memberDTO = resultList.get(0);


System.out.println("memberDTO.age = " + memberDTO.getAge());		// age
System.out.println("memberDTO.username = " + memberDTO.getUsername());	// username
SELECT new jpabook.jpql.UserDTO(m.username, m.age) FROM Member m
  • ํŒจํ‚ค์ง€ ๋ช…์„ ํฌํ•จํ•œ ์ „์ฒด ํด๋ž˜์Šค ๋ช… ์ž…๋ ฅ
  • ์ˆœ์„œ์™€ ํƒ€์ž…์ด ์ผ์น˜ํ•˜๋Š” ์ƒ์„ฑ์ž ํ•„์š”!

 

 

๐Ÿ—’ ํŽ˜์ด์ง• API


  • JPA๋Š” ํŽ˜์ด์ง•์„ ๋‹ค์Œ ๋‘ API๋กœ ์ถ”์ƒํ™”
  • setFirstResult(int startPosition) : ์กฐํšŒ ์‹œ์ž‘ ์œ„์น˜(0๋ถ€ํ„ฐ ์‹œ์ž‘)
  • setMaxResults(int maxResult) : ์กฐํšŒํ•  ๋ฐ์ดํ„ฐ ์ˆ˜
// Member 100๊ฐœ ๋ฏธ๋ฆฌ persist

List<Member> resultList = em.createQuery("select m from Member m order by m.age desc", Member.class)
	.setFirstResult(0)	// ํŽ˜์ด์ง• : ์กฐํšŒ ์‹œ์ž‘ ์œ„์น˜(0๋ถ€ํ„ฐ ์‹œ์ž‘)
    	.setMaxResults(10)  	// ํŽ˜์ด์ง• : ์กฐํšŒํ•  ๋ฐ์ดํ„ฐ ์ˆ˜(10๊ฐœ)
    	.getResultList();	// ๊ฒฐ๊ณผ๊ฐ’์„ List๋กœ
    
for(Member member : resultList) {
	System.out.println("member = " + member);	// member.toString() ์˜ค๋ฒ„๋ผ์ด๋”ฉ ํ–ˆ์Œ
}

์‹คํ–‰ ์ฟผ๋ฆฌ

order by .. desc limit ? ์ธ ์ด์œ ๋Š” setFirstResult(0)์œผ๋กœ ์คฌ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

setFirstResult(1)๋กœ ์ฃผ๋ฉด?

offset์ด ์„ค์ •๋จ.

 


๐Ÿ—’ ์กฐ์ธ(JOIN)


๋‚ด๋ถ€์กฐ์ธ (inner join)

  • inner ์ƒ๋žต ๊ฐ€๋Šฅ.
String qlString = "select m from Member m inner join m.team t";
List<Member> resultList = em.createQuery(qlString, Member.class);
	.getResultList();

์‘? team์„ ์กฐํšŒํ•œ๊ฑด ์•Œ๊ฒ ๋Š”๋ฐ, team์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜๋Š”๋ฐ ์™œ ์ฟผ๋ฆฌ๊ฐ€ ๋‚˜๊ฐˆ๊นŒ?

์ด๊ฒŒ ๋ฐ”๋กœ @ManyToOne์˜ fetch ๊ธฐ๋ณธ ๊ฐ’์ด EAGER์ด๊ธฐ ๋•Œ๋ฌธ! (LAZY๋กœ ๋ฐ”๊ฟ”์ฃผ๋„๋ก ํ•˜์ž)

 

์™ธ๋ถ€ ์กฐ์ธ(outer join)

  • outer ์ƒ๋žต ๊ฐ€๋Šฅ
String qlString = "select m from Member m left outer join m.team t";
List<Member> resultList = em.createQuery(qlString, Member.class);
	.getResultList();

 


๐Ÿ—’ on ์ ˆ


์กฐ์ธ ๋Œ€์ƒ ํ•„ํ„ฐ๋ง

String qlString = "select m from Member m left join m.team t on t.name = 'teamA'";
List<Member> resultList = em.createQuery(qlString, Member.class)
	.getResultList();

member.id ์™€ team.id๋ฅผ ๋น„๊ตํ•ด์„œ andํ•ด์„œ ์ถ”๊ฐ€๋กœ member.username ๊ณผ team.name์ด ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์ด๋‹ค.

 

+ where๋กœ ์กฐํšŒ ๊ฒฐ๊ณผ

String qlString = "select m from Member m join m.team t where t.name = 'teamA'";
List<Member> resultList = em.createQuery(qlString, Member.class)
	.getResultList();

 

์—ฐ๊ด€๊ด€๊ณ„ ์—†๋Š” ์—”ํ‹ฐํ‹ฐ ์™ธ๋ถ€ ์กฐ์ธ

String qlString = "select m from Member m left join Team t on m.username = t.name";
List<Member> resultList = em.createQuery(qlString, Member.class)
	.getResultList();

์—ฐ๊ด€๊ด€๊ณ„๊ฐ€ ์—†๋Š” ํ•„๋“œ(id๊ฐ€ ์•„๋‹Œ username์ด๋ผ๋˜์ง€ ๋“ฑ๋“ฑ..)๋ฅผ ์กฐ์ธํ•  ๋•Œ, id๊ฐ’์„ ๊ฐ€์ ธ์˜ค์ง€ ์•Š๊ณ  name๋ผ๋ฆฌ๋งŒ ๋น„๊ตํ•˜์—ฌ ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์˜จ๋‹ค.

 

+ where๋กœ ์กฐํšŒ ๊ฒฐ๊ณผ

String qlString  = "select m from Member m join m.team t where m.username = t.name";
List<Member> resultList = em.createQuery(qlString, Member.class)
	.getResultList();

 

 

Member, Team์€ ์—ฐ๊ด€๊ด€๊ณ„๊ฐ€ ์žˆ๋Š”๋ฐ ์™œ ์—ฐ๊ด€๊ด€๊ณ„๊ฐ€ ์—†๋‹ค๊ณ  ๋งํ• ๊นŒ?

ํšŒ์›๊ณผ ํŒ€์ด ์—ฐ๊ด€๊ด€๊ณ„๊ฐ€ ์žˆ๋Š” ๊ฑด ๋งž์ง€๋งŒ, ํšŒ์›์˜ ์ด๋ฆ„๊ณผ ํŒ€ ์ด๋ฆ„์€ ์„œ๋กœ ์•„๋ฌด๋Ÿฐ ์—ฐ๊ด€๊ด€๊ณ„๊ฐ€ ์—†๋Š” ํ•„๋“œ์ด๋‹ค.
์ด๋Ÿฌํ•œ ์—ฐ๊ด€๊ด€๊ณ„๊ฐ€ ์—†๋Š” ํ•„๋“œ๋กœ ์กฐ์ธํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ธํƒ€ ์กฐ์ธ์ด๋ผ๊ณ  ํ•˜๊ณ , ์˜ˆ๋ฅผ ๋“ค์–ด์„œ ์„ธํƒ€ ์กฐ์ธ์„ ์‚ฌ์šฉํ•˜๋ฉด
ํšŒ์›๊ณผ ํŒ€์ด ์•„๋‹ˆ๋ผ, ํŒ€ ์ด๋ฆ„๊ณผ ํšŒ์› ์ด๋ฆ„์ด ๊ฐ™์€ ํ•„๋“œ๋กœ๋„ ์กฐ์ธ์ด ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.

 

๐Ÿ—’ ์„œ๋ธŒ ์ฟผ๋ฆฌ


์„œ๋ธŒ ์ฟผ๋ฆฌ

  • ์ฟผ๋ฆฌ ์•ˆ์— ๋˜ ๋‹ค๋ฅธ ์ฟผ๋ฆฌ

 

์„œ๋ธŒ ์ฟผ๋ฆฌ ์ง€์› ํ•จ์ˆ˜

  • EXISTS : ์„œ๋ธŒ ์ฟผ๋ฆฌ์— ๊ฒฐ๊ณผ๊ฐ€ ์กด์žฌํ•˜๋ฉด ์ฐธ
  • ALL, ANY, SOME : ALL์€ ๋ชจ๋‘ ๋งŒ์กฑํ•˜๋ฉด ์ฐธ, ANY, SOME์€ ์กฐ๊ฑด์„ ํ•˜๋‚˜๋ผ๋„ ๋งŒ์กฑํ•˜๋ฉด ์ฐธ
  • IN : ์„œ๋ธŒ ์ฟผ๋ฆฌ์˜ ๊ฒฐ๊ณผ ์ค‘ ํ•˜๋‚˜๋ผ๋„ ๊ฐ™์€ ๊ฒƒ์ด ์žˆ์œผ๋ฉด ์ฐธ

 

์˜ˆ์ œ 1. ๋‚˜์ด๊ฐ€ ํ‰๊ท ๋ณด๋‹ค ๋งŽ์€ ํšŒ์›

SELECT m FROM Member m WHERE m.age > (SELECT avg(m2.age) FROM Member m2)

์„œ๋ธŒ ์ฟผ๋ฆฌ๋ฅผ ๋ณด๋ฉด ๊ธฐ์กด์˜ Member m์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ , ์ƒˆ๋กœ์šด m2๋ฅผ ๋งŒ๋“ค์–ด์„œ ์กฐํšŒ ํ–ˆ๋‹ค. (์ด๋ ‡๊ฒŒ ํ•ด์•ผ ์„ฑ๋Šฅ์ด ์ž˜ ๋‚˜์˜ค๊ฒŒ ๋œ๋‹ค.)

 

์˜ˆ์ œ 2. ํ•œ ๊ฑด์ด๋ผ๋„ ์ฃผ๋ฌธํ•œ ๊ณ ๊ฐ

SELECT m FROM Member m WHERE (SELECT count(o) FROM Order o WHERE m = o.member) > 0

๋ฉ”์ธ ์ฟผ๋ฆฌ์—์„œ ์กฐํšŒํ•œ member์™€ ์ผ์น˜ํ•œ Order.member์˜ ์ฃผ๋ฌธ ๊ฑด์ˆ˜๊ฐ€ 0 ๋ณด๋‹ค ํด ๋•Œ ์กฐํšŒ ํ•ด ์˜จ๋‹ค.

 

์„œ๋ธŒ ์ฟผ๋ฆฌ ์‚ฌ์šฉ

SELECT m FROM Member m WHERE exists (SELECT t FROM m.team t WHERE t.name = 'teamA')

exists ํ•จ์ˆ˜๋Š” ๊ฒฐ๊ณผ๊ฐ€ ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ true๋ฅผ, ์—†๋Š” ๊ฒฝ์šฐ false๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค.

์œ„์— ์ฝ”๋“œ๋Š” member๊ฐ€ 'teamA' ์†Œ์†์ธ์ง€ ํ™•์ธ ํ•˜๋Š” sql์ด๋‹ค.

 

SELECT o FROM Order o WHERE o.orderAmount > ALL (SELECT p.stockAmount FROM Product p)

์ „์ฒด ์ƒํ’ˆ ๊ฐ๊ฐ์˜ ์žฌ๊ณ ๋ณด๋‹ค ์ฃผ๋ฌธ๋Ÿ‰์ด ๋งŽ์€ ์ฃผ๋ฌธ๋“ค์„ ์กฐํšŒํ•ด ์˜ค๋Š” sql์ด๋‹ค.

 

SELECT m FROM Member m WHERE m.team = ANY(select t from Team t)

์–ด๋–ค ํŒ€์ด๋“  ํŒ€์— ์†Œ์†๋œ ํšŒ์›์„ ์กฐํšŒํ•ด ์˜ค๋Š” sql์ด๋‹ค.

 

 

๐Ÿ—’ JPQL ํƒ€์ž… ํ‘œํ˜„๊ณผ ๊ธฐํƒ€์‹


  • ๋ฌธ์ž : 'HELLO' , 'She''s' (์ค‘๊ฐ„์— ' ๋„ฃ๊ธฐ ์œ„ํ•ด์„œ)
  • ์ˆซ์ž : 10L(Long), 10D(Double), 10F(Float)
  • Boolean : True, False (๋Œ€์†Œ๋ฌธ์ž ๊ตฌ๋ถ„ x)
  • Enum : ํŒจํ‚ค์ง€๋ช… ํฌํ•จ
  • ์—”ํ‹ฐํ‹ฐ ํƒ€์ž… : Type(m) = Member (์ƒ์† ๊ด€๊ณ„์—์„œ ์‚ฌ์šฉ)

 

๋ฌธ์ž, boolean, Enum ํƒ€์ž…

// enum ํƒ€์ž…์€ ํ•ญ์ƒ FQCN(Fully Qualified Class Name)์„ ์ ์–ด์ค˜์•ผ ํ•œ๋‹ค.
String sql = "select m.username, 'HELLO', true From Member m " +
                    "where m.type = ch10.MemberType.ADMIN";

List<Object[]> result = em.createQuery(sql)
	.getResultList();
	
for (Object[] objects : result) {
	System.out.println(objects[0]);
	System.out.println(objects[1]);
	System.out.println(objects[2]);
}

 

์ฟผ๋ฆฌ๋ฅผ ๋ณด๋ฉด, MemberType.ADMIN์œผ๋กœ ์กฐํšŒ ํ•˜๊ณ  ์žˆ๋‹ค.

 

DTYPE

String sql = "select i From Item i" + 
		"where type(i) = Book";		// DTYPE = 'BOOK' ์œผ๋กœ ์ฟผ๋ฆฌ๊ฐ€ ๋‚˜๊ฐ„๋‹ค.

 

 

๐Ÿ—’ ์กฐ๊ฑด์‹(CASE ๋“ฑ๋“ฑ)


๊ธฐ๋ณธ CASE ์‹ (๋„์–ด์“ฐ๊ธฐ ์ฃผ์˜)

String query = "select " +
                    "case when m.age <= 10 then 'ํ•™์ƒ์š”๊ธˆ'" +
                        "when m.age >= 60 then '๊ฒฝ๋กœ์š”๊ธˆ'" +
                        "else '์ผ๋ฐ˜์š”๊ธˆ'" +
                    "end " +
               "from Member m";

 

 

ํ˜•ํƒœ๋Š” java์˜ switch๋ฌธ์ด๋ž‘ ๋น„์Šทํ•˜๋‹ค.

member์˜ ๋‚˜์ด๊ฐ€ 10์ดํ•˜์ด๋ฉด "ํ•™์ƒ์š”๊ธˆ", 60์ด์ƒ์ด๋ฉด  "๊ฒฝ๋กœ์š”๊ธˆ", ๋‚˜๋จธ์ง€ ๋‚˜์ด๋Š” "์ผ๋ฐ˜์š”๊ธˆ"์œผ๋กœ ์ถœ๋ ฅ๋œ๋‹ค.

 

๋‹จ์ˆœ CASE ์‹

String query = "select " +
                   "case m.team.name " +
                       "when 'teamA' then 'ํŒ€A'" +
                        "when 'teamB' then 'ํŒ€B'" +
                        "else '๊ทธ ์™ธ ํŒ€'" +
                    "end " +
            "from Member m";

๊ธฐ๋ณธ CASE๋ฌธ๊ณผ ์‚ด์ง ๋‹ค๋ฅด๋‹ค. case๋ฌธ ์˜†์— ๊ฐ’์„ ์ง€์ •ํ•ด ๋†“๊ณ , ๊ทธ ๊ฐ’์ด when 'A' ์ผ๋•Œ -> then ... ๋˜ when 'B'์ผ๋•Œ๋Š” -> then ... ์ด๋Ÿฐ ์‹์œผ๋กœ ์ž‘์„ฑํ•œ๋‹ค. 

 

 

COALESCE : ํ•˜๋‚˜์”ฉ ์กฐํšŒํ•ด์„œ null์ด ์•„๋‹ˆ๋ฉด ๋ฐ˜ํ™˜

  • ์‚ฌ์šฉ์ž ์ด๋ฆ„์ด null(์—†์œผ๋ฉด)์ด๋ฉด ์ด๋ฆ„ ์—†๋Š” ํšŒ์›์„ ๋ฐ˜ํ™˜
member.setUsername(null);

..

String query = "select coalesce(m.username, '์ด๋ฆ„ ์—†๋Š” ํšŒ์›') from Member m";

 

NULLIF : ๋‘ ๊ฐ’์ด ๊ฐ™์œผ๋ฉด null ๋ฐ˜ํ™˜, ๋‹ค๋ฅด๋ฉด ์ฒซ๋ฒˆ์งธ ๊ฐ’ ๋ฐ˜ํ™˜

  • ์‚ฌ์šฉ์ž ์ด๋ฆ„์ด '๊ด€๋ฆฌ์ž'์ด๋ฉด null์„ ๋ฐ˜ํ™˜, ์•„๋‹ˆ๋ฉด ์ž๊ธฐ ์ž์‹ ์˜ ์ด๋ฆ„ ๋ฐ˜ํ™˜

 

member.setUsername("๊ด€๋ฆฌ์ž");

..

String query = "select nullif(m.username, '๊ด€๋ฆฌ์ž') from Member m";โ€‹

 

 

๐Ÿ—’ JPQL ๊ธฐ๋ณธ ํ•จ์ˆ˜, ์‚ฌ์šฉ์ž ์ •์˜ ํ•จ์ˆ˜


JPQL ๊ธฐ๋ณธ ํ•จ์ˆ˜

 

์‚ฌ์šฉ์ž ์ •์˜ ํ•จ์ˆ˜

  • ํ•˜์ด๋ฒ„๋„ค์ดํŠธ๋Š” ์‚ฌ์šฉ์ „์— ๋ฐฉ์–ธ์— ์ถ”๊ฐ€ํ•ด์•ผ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.
    • ์‚ฌ์šฉํ•˜๋Š” DB ๋ฐฉ์–ธ์„ ์ƒ์†๋ฐ›๊ณ , ์‚ฌ์šฉ์ž ์ •์˜ ํ•จ์ˆ˜๋ฅผ ๋“ฑ๋กํ•œ๋‹ค.

๋“ฑ๋ก ํ›„์—” ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

select function('group_concat' , i.name) from Item i

๋‹คํ–‰ํžˆ๋„ ์›ฌ๋งŒํ•˜๋ฉด, DB์— ์ด๋ฏธ ๋‹ค ๋“ฑ๋ก์ด ๋˜์–ด์žˆ๊ธด ํ•˜๋‹ค.

MySQLDialect class

 

  • concat (๋ฌธ์ž์—ด ๋”ํ•˜๊ธฐ)
String query = "select concat('a', 'b') from Member m";
// ์‹คํ–‰ ๊ฒฐ๊ณผ : ab

 

  • SUBSTRING (๋ฌธ์ž์—ด ์ž๋ฅด๊ธฐ)
String query = "select substring('abcdef', 2, 3) from Member m";
// ์‹คํ–‰ ๊ฒฐ๊ณผ : bcd

 

  • TRIM (๊ณต๋ฐฑ ์ œ๊ฑฐ)
    • LTRIM (์‹œ์ž‘ ๋ฌธ์ž์—ด ๊ณต๋ฐฑ ์ œ๊ฑฐ)
    • RTRIM (๋ ๋ฌธ์ž์—ด ๊ณต๋ฐฑ ์ œ๊ฑฐ)
String query = "select trim('  abcdef  ') from Member m";	// "abcdef"

String query = "select Ltrim('  abcdef  ') from Member m";	// "abcdef  "

String query = "select Rtrim('  abcdef  ') from Member m";	// "  abcdef"

 

  • LOCATE (ํ•ด๋‹น ๋ฌธ์ž ์œ„์น˜)
    • return Integer ํƒ€์ž…
String query = "select locate('cd', 'abcdef') from Member m";	// ๊ฒฐ๊ณผ ๊ฐ’ : 3

 

SIZE (ํฌ๊ธฐ)

String query = "select size(t.members) from Team t";	// team์— ์žˆ๋Š” ๋ฉค๋ฒ„๋ฅผ ์ €์žฅํ•˜๋Š” ์ปฌ๋ ‰์…˜์˜ ์‚ฌ์ด์ฆˆ๋ฅผ ์กฐํšŒ

 

์‚ฌ์šฉ์ž ์ •์˜ ํ•จ์ˆ˜ ๋งŒ๋“ค๊ธฐ

 

1. ํŒจํ‚ค์ง€ ์ƒ์„ฑ - MyH2Dialect ํด๋ž˜์Šค ์ƒ์„ฑ

 

์ง€๊ธˆ์€ H2๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, H2Dialect๋ฅผ ์ƒ์† ๋ฐ›์•„์„œ ์ž‘์„ฑํ•œ๋‹ค.

package dialect;

import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.function.StandardSQLFunction;
import org.hibernate.type.StandardBasicTypes;

/**
 * H2Dialect ๋ฅผ ์ƒ์†๋ฐ›์•„์„œ ๋‚ด๊ฐ€ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์€ ํ•จ์ˆ˜๋ฅผ ๋“ฑ๋ก ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.
 * <p>
 * ์–ด๋–ป๊ฒŒ ์ƒ์„ฑํ•˜๋Š”์ง€๋Š” H2Dialect ํด๋ž˜์Šค ๋“ค์–ด๊ฐ€์„œ registerFunction ๋ฉ”์†Œ๋“œ๋ฅผ ๋ณด๊ณ  ์ฐธ์กฐํ•˜๋ฉด ๋œ๋‹ค.
 */
public class MyH2Dialect extends H2Dialect {
    public MyH2Dialect() {
        registerFunction("group_concat", new StandardSQLFunction("group_concat", StandardBasicTypes.STRING));
    }
}

 

์ •์˜ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค๋•Œ H2Dialect ํด๋ž˜์Šค์˜ ๋“ฑ๋ก๋œ ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ดํŽด๋ณด๊ณ  ์ฐธ์กฐํ•˜์ž.

H2Dialect ํด๋ž˜์Šค - registerFuction ์ฐธ์กฐ

 

persistence.xml ํŒŒ์ผ์— ๊ธฐ์กด์— ๋“ฑ๋ก๋˜์–ด์žˆ๋˜ H2Dialect๋ฅผ ํ˜„์žฌ ์ƒ์„ฑํ•œ MyH2Dialect๋กœ ๋ฐ”๊ฟ”์ค€๋‹ค.

//  <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
    <property name="hibernate.dialect" value="dialect.MyH2Dialect"/>

 

group_concat ์€ ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ์ค„๋กœ ๋งŒ๋“ค์–ด์ฃผ๋Š” ํ•จ์ˆ˜์ด๋‹ค.

String query = "select function('group_concat', m.username) from Member m";

 

์ฐธ๊ณ ๋กœ, ํ•˜์ด๋ฒ„๋„ค์ดํŠธ ์‚ฌ์šฉ์ค‘์ผ ๋•Œ๋Š” ์•„๋ž˜ ๋ฐฉ๋ฒ•๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.

String query = "select group_concat(m.username) from Member m";		// member1, member2
๋ฐ˜์‘ํ˜•