sql(셀프조인,LIMIT,EL,JSTL)

제이·2023년 6월 1일
0

셀프조인

자기 자신의 것을 스스로 참조하는거 = 셀프조인

CREATE TABLE students (
s_id INT PRIMARY KEY AUTO_INCREMENT,
s_name CHAR(20) NOT NULL,
s_manitto INT
);

INSERT INTO students (s_name, s_manitto) values
('a',2), ('b',3), ('c',null), ('d',1);

SELECT * FROM students;

--각 학생에 이름과 마니또 이름을 표시하라.
SELECT s1.s_name, s2.s_name
FROM sudents s1, student s2 --논리적으로 두개로 본다.
WHERE s1.s_id = s2.s_manitto;

SELECT s1.s_name, s2.s_name
FROM students s1 INNER JOIN students s2
ON s1.s_id = s2.s_manitto;

SELECT s1.s_name, s2.s_name
FROM students s1 LEFT OUTER JOIN students s2
ON s1.s_id = s2.s_manitto
WHERE s2.s_manitto IS NULL;


LIMIT

mysql에만 있다.
앞의 숫자는 시작위치(인덱스처럼 0부터 시작)
뒤의 숫자는 몇개를 보여줄 지 결정하는 숫자.
이걸 가지고 페이징처리를 한다.
SELECT FROM products LIMIT 3; -- 3넣으니까 3줄만 나온다.
SELECT
FROM products LIMIT 2, 3; -- 2는 시작위치. 인덱스와 비슷한 느낌. 리밋은 mysql밖에 없다. 이걸 가지고 페이징처리를 할 것이다.

bookDao.java

여기 안에 2개의 메서드를 적어준다.
getList()는 한페이지에 3개씩 나눠서 list를 구성한다는 것 같고,
getTotalCount()는 테이블의 레코드(행)의 총 개수를 구하는 것.



public Vector<Book> getList(Connection con, int pageNum, int perPage) {
		Vector<Book> list = new Vector<Book>();
		String sql = "SELECT * FROM a_book ORDER BY b_num DESC LIMIT ?, ?";
		PreparedStatement pStmt = null;
		ResultSet rs = null;
		
		try {
			pStmt = con.prepareStatement(sql);
			pStmt.setInt(1, (pageNum -1) * perPage);
			pStmt.setInt(2, perPage);
			rs = pStmt.executeQuery();
			while(rs.next()) {
				list.add(rowMapping(rs));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			close(rs);
			close(pStmt);
		}
		return list;
		
	}
	
	public int getTotalCount(Connection con) {
		int count = 0;
		String sql = "SELECT COUNT(*) FROM a_book";
		PreparedStatement pStmt = null;
		ResultSet rs = null;
		try {
			pStmt = con.prepareStatement(sql);
			rs = pStmt.executeQuery();
			if(rs.next()) {
				count = rs.getInt(1); //열 순서임! 
                //이름으로 들고오면 문제가 있다. 
                //접근하는 속도도 이게 더 빠름. 
                //첫번째 열을 들고오라는 뜻인듯.			
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			close(rs);
			close(pStmt);
		}
		return count;
	}

listCmd.java

그 다음 listCmd를 아래와 같이 바꿔준다.

public class ListCmd implements ICmd { 
//이걸 잘알아야 한다. 페이징하는 연산은 다 이렇게 생김. 
페이징하려면 뭐가 필요한지 알지.
	public void action(HttpServletRequest request) {
		int perPage = 3;
		int pageNum = 1;
		String temp = request.getParameter("pageNum");
		if(temp != null) {
			pageNum = Integer.parseInt(temp);
		}
		BookDao dao = BookDao.getInstance();
		Connection con = dao.connect();
		
		int totalCount = dao.getTotalCount(con); //몇페이지까지 나오는지..
		int pageCount = totalCount / perPage;
		if(totalCount % perPage !=0) {
			pageCount++; //딱 안떨어지면 한페이지 늘여야 하니까.
		}
		
		request.setAttribute("list", dao.getList(con,pageNum, perPage));
		dao.disconnect(con);
		
		request.setAttribute("pageNum", pageNum); 
		request.setAttribute("pageCount", pageCount); 
	}
}

EL(Expression Language)

<%= %> , out.println()과 같은 자바코드를 더 이상 사용하지 않고 좀더 간편하게 출력을 지원하기 위한 도구.
배열, List, map도 가능.

<결과>

<%@page import="java.util.Hashtable"%>
<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<%@page import="kr.ac.green.Some" %>
<%@page import="java.util.*" %>

<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>elEx.jsp</title>
</head>
<body>
<%
//값을 잡아넣는 것은 jsp에서 하는 일이 아니다. 
%>

<%
	pageContext.setAttribute("myString", "aaa"); //영역이 다른데 이름이 같은 속성
	request.setAttribute("myString", null);	
	
	Some s = new Some(100, "myValue");
	session.setAttribute("some", s);
	
	
	Vector<String> vec = new Vector<String>();
	vec.add("a");
	vec.add("b");
	vec.add("c");
	vec.add("d");
	
	request.setAttribute("list", vec);
	
	Map<String, String> map = new Hashtable<String,String>();
	map.put("aKey", "aValue");
	map.put("bKey", "bValue");
	map.put("cKey", "cValue");
	map.put("dKey", "dValue");
	
	request.setAttribute("map", map);
	
	Vector<String> otherList = new Vector<String>();
	request.setAttribute("otherList", otherList);
	
	request.setAttribute("arr", new int[]{});
%>

${ list[2] } ${ map["cKey"] } ${ empty otherList } ${ empty arr }
 <%-- 배열도 되고  list도 된다. --%>
 <%-- ${ empty otherList } null검사가 된다. null도 검사하고 원소가 몇개 들었는지도 알수 있다. 비었습니까? 이런느낌. 
 배열에서 empty는 원소값이 없음에도 false가 나온다. 배열은 안에 비었는지 알지 못한다. 배열이 길이가 0인거 만들면 걍 무조건 0이다. 
 null의 유무만 검사하고, 원소가 있는지 아닌지 배열이 비었는지는 검사하지 못한다./ not empty도 가능  --%>
<hr>
 <%--jstl을 써야 for아니 if문 쓸 수 있다. 코드를 만들 수 있는 일을 태그로 사용한거...jstl은 외부라이브러리다. -->
<%
	String str = (String) request.getAttribute("myString");
%>
<%=str %>

${ requestScope.myString } <%--표현식은 null값이 나오지만, requestScope는 null값이 표현되지 않고 결과가 안나온다!!! requestScope는 리퀘스트 객체가 아니라 그냥 속성값만 가져오는 것이다.--%>
<%-- ${ myString }--%> <% //얘는 4개의 객체를 차례로 검사 pageContext-request-session-application 순으로 있는지 없는지 확인하고 page가 먼저 나온다. 4개 다 없으면 null이 뜬다. %>
<hr>
<%
	Some temp = (Some)session.getAttribute("some");

%>
<%= temp.getNum()%> <%=temp.getStr()%>
${ sessionScope.some.num }
<%--${ sessionScope.some.str } --%>
${some.str } <%--이렇게 써도 값은 똑같이 나온다. --%>
<%--${some[str] }  --%><%--이렇게 써도 값은 똑같이 나온다. --%>

<hr>
<%=application.getInitParameter("pname") %>
${ initParam.pname }

<%-- http://localhost:8080/06.01/elEx.jsp?myParam=cat --%>
${ param.myParam }

<hr>
${ pageContext.request.contextPath } <%--pageContext.request : 이렇게 쓰면 레퀘스트 객체를 가져오게 된다. el에서 사용할 수 있는 것은 pageContext객체 밖에 안된다. 다른 3가지는 객체 직접 못 들고 온다.--%>
<hr>
${ 4 < 3 } <%-- 참거짓판단가능 --%>
${ 3 == 3 } <%-- 참거짓판단가능 --%>

</body>
</html>

JSTL(Jsp Standard Tag Library)

JSP는 자신만의 태그를 추가할 수 있는 기능을 제공하고 있는데요.

<jsp:include>나 <jsp:usebean>과 같은 커스텀 태그처럼 연산이나 조건문이나 반복문인 if문, for문, DB를 편하게 처리할 수 있는것이 JSTL.

if문 사용 - else if 없음
<c:if test = ${}>

<c:if test**="${4 > 0}">
	true
</c:if>

if - else if - else문

<c:choose>
<c:when test="${ myValue >10 }"> :if느낌. 
		10보다 크다
        </c:when>
	<c:when test="${ myValue>5 }"> :else if느낌.
		5보다 크다
	</c:when>
	<c:otherwise> : else느낌. 
		5 이하이다.
	</c:otherwise>
</c:choose>

for구문
end는 '이하'이다. 10을 포함함. 역순은 안된다.
var : 변수 step : 더해지는 단위

<c:forEach var="i" begin="0" end="10" step="2"> 
	${ i }
</c:forEach>

foreach문
varStatus="status":반복문의 정보를 가지고 있다.

<c:foreach items="${리스트가 받아올 배열이름}"
                var="for문 내부에서 사용할 변수"
                varStatus="상태용 변수">

<c:forEach items="${ list }" var="myString" varStatus="status"> 
	${ status.count }번째 반복 :  ${ myString } -> ${ status.index }
	<br>
</c:forEach>

<결과>

<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page import ="java.util.*" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
<%
	//int num = 100;	//el에서 참조할 수 없다.${ num } 이렇게 못 쓴다. el는 getAttribute인 느낌인듯.
%>
<c:set var="num" value="100" scope="request" /> <%--이런 거 사용은 되는데 하지마라. jsp는 속성을 정의하는 곳이 아니다. --%>
${ num }
<c:remove var="num" scope="request"/> <%--이런 거 사용은 되는데 하지마라. jsp는 속성을 정의하는 곳이 아니다. --%>
${ num }
<hr><%--여기만 보기--%>
<c:if test="${4 > 0}"><%--else if가 없다. --%>
	true
</c:if>
<c:set var="myValue" value="1"/>
<c:choose>
	<c:when test="${ myValue >10 }"><%--if느낌. --%>
		10보다 크다
	</c:when>
	<c:when test="${ myValue>5 }"><%--else if느낌. --%>
		5보다 크다
	</c:when>
	<c:otherwise><%--else느낌. --%>
		5 이하이다.
	</c:otherwise>
</c:choose>

<hr><%--반복문--%>
<c:forEach var="i" begin="0" end="10" step="2"> <%--end는 '이하'이다. 10을 포함함. 역순은 안된다.--%>
	${ i }
</c:forEach>
<hr>
<%
	ArrayList<String> list = new ArrayList<String>();
	list.add("a");
	list.add("b");
	list.add("c");
	list.add("d");
	
	request.setAttribute("list", list);
%>
<c:forEach items="${ list }" var="myString" varStatus="status"> <%-- varStatus="status":반복문의 정보를 가지고 있다. --%>
	${ status.count }번째 반복 :  ${ myString } -> ${ status.index }
	<br>
</c:forEach>
</body>
</html>

걍)
book의 list.jsp를 jstl로 바꾼 거

<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<%@ taglib prefix ="c" uri ="http://java.sun.com/jsp/jstl/core" %>
<%@ page import="java.util.*" %>
<%@ page import="kr.ac.green.Book" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>list.jsp</title>
</head>
<body>
	<h1>list</h1>
	<a href="add.book">책 등록하기</a>
	<hr>
	<form action="findByTitle.book" method="get">
		제목으로 검색할 수 있어요 : <input type="text" name="findTitle" />
		<input type="submit" />
	</form>
	<hr>
	<table>
		<tr>
			<th>번호</th>
			<th>제목</th>
			<th>저자</th>			
		</tr>
		<c:choose>
			<c:when test="${ empty list }">
				<tr>
					<td colspan="3">no data</td>
				</tr>
		</c:when>
		<c:otherwise>
			<c:forEach items="${ list }" var="book">
				<tr onclick="showBookInfo(${ book.num})">
					<td>${ book.num}</td>
					<td>${ book.title}</td>
					<td>${ book.writer}</td>
				</tr>		
		 		</c:forEach>
			</c:otherwise>
		</c:choose>
		<tr>
			<th colspan ="3"/>
			<c:forEach var="i" begin="1" end="${ pageCount }">
				<c:choose>
					<c:when test="${ i == pageNum }">
						[${i }]
					</c:when>
					<c:otherwise>
						<a href="list.book?pageNum=${i }"> [${i }]</a>
					</c:otherwise>

				</c:choose>
			</c:forEach>
		</tr>
		
	</table>
	<script>
		function showBookInfo() {
			location.href="view.book?num=" + arguments[0];
		}
	</script>
</body>
</html>

배열로 바꾸기

public Book[] getAllByArray(Connection con) {
Book[] arr = null;
PreparedStatement pStmt = null;
ResultSet rs =null;

	String sql = "SELECT * FROM a_book";
	try {
		pStmt = con.prepareStatement(sql);
		rs = pStmt.executeQuery();
		rs.last();	//마지막으로 옮김. -> 다음게 없음. rs.last()가 제일 마지막 레코드로 이동함.
		int count = rs.getRow();//현재 커서가 몇번째위치에 있는 지 알려주는 게 getRow()
		arr = new Book[count];
		rs.beforeFirst();//위치를 첫번째레코드 위에 있다. 최초위치에 있다.
		int idx = 0;
		while(rs.next()) {//next()의 의미 : 현재위치라는 게 있어야 한다. 다음레코드가 있습니까? 물어볼 수 있는 거. 처음위치가 어디있나? 열이름들 나오는 저기부분. 최초위치는 열이름있는 부분. 현재위치 담고있는 부분을 cursor라고 함.
			arr[idx++] = rowMapping(rs);
		}
		//콜렉션 등도 기반이 배열이다. 길이가 늘어났을 때 배열을 바꾼다. 리스트등은 capacity 용량이라는 것을 가짐. 진짜로 몇개를 넣을 수 있는가의 정보. 용량이 먼저 10으로 잡혀있고, 나중에 10개 넘으면 2배로 양을 늘인다. 넣는 원소개수가 많은면 많을수록 공간의 낭비가 심해진다.
		//가변길이인것처럼 보이게 한다. 
	} catch (SQLException e) {
		e.printStackTrace();
	} finally {
		close(rs);
		close(pStmt);
	}
	return arr;
}

`클라이언트가 요청을 보낸다 -> 로직(커맨드클래스) -> 연결 -> 데이터베이스(질의연산)`
profile
Hello :)

0개의 댓글