<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
	<channel>
		<title>막장개발자의 블로그</title>
		<link>http://rtti.tistory.com/</link>
		<description>막창에는 막장!</description>
		<language>ko</language>
		<pubDate>Wed, 02 Nov 2011 21:15:03 +0900</pubDate>
		<generator>Tistory 1.1 (http://www.tistory.com/)</generator>
		<image>
		<title>막장개발자의 블로그</title>
		<url><![CDATA[http://cfile2.uf.tistory.com/image/167E7B4F4EB12AC33061C0]]></url>
		<link>http://rtti.tistory.com/</link>
		<description>막창에는 막장!</description>
		</image>
		<item>
			<title>Update문을 Static SQL로 구성하기</title>
			<link>http://rtti.tistory.com/entry/Update%EB%AC%B8%EC%9D%84-Static-SQL%EB%A1%9C-%EA%B5%AC%EC%84%B1%ED%95%98%EA%B8%B0</link>
			<description>Update문을 Static SQL로 구성하는 것도 쉬운 일은 아니다. 아이디어를 알고 보면 별 거 아니지만, 아무 것도 없는 상황에서 그런 아이디어를 생각하는 것은 솔직히 어렵다. 이 글도 물론-_- 필자의 아이디어는 아니다. &lt;br /&gt;
&lt;br /&gt;Update문을 Static SQL로 구성하기 어려운 것은 Parameter Binding을 사용하기 어렵기 때문이다. 보통 Update는&amp;nbsp;전체 Column에 이루어지지 않고 달라진 하나 또는 두개의 Column에만 이루어 지기 때문이다.&lt;br /&gt;
즉, 아래와 같은 방식은 통하지 않는다.&lt;br /&gt;

&lt;DIV class=txc-textbox style=&quot;BORDER-RIGHT: #f3c534 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #f3c534 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; BORDER-LEFT: #f3c534 1px solid; PADDING-TOP: 10px; BORDER-BOTTOM: #f3c534 1px solid; BACKGROUND-COLOR: #fefeb8&quot;&gt;Update Table1&amp;nbsp;Set column1 = :v1, Set column2 = :v2 &lt;br /&gt;
Where pk_column = :v3&lt;/DIV&gt;&lt;br /&gt;
그렇다고 Dynamic SQL이 정당화 될 수는 없지 않겠는가? 바로 앞 포스트에서 알아 본 Case When문과 약간의 Idea를 이용하면 간단하게 해결할 수 있다. &lt;br /&gt;

&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;Update 할 내용이 없는 경우는 원래 값으로 Update를 해준다.&lt;/LI&gt;
&lt;LI&gt;Update할 내용이 있는지 없는지 여부는 Varchar2계열이라면 Length를 Check하면 되고, 숫자라면 전혀 올 수 없는 값을 주면 될 것이다.&lt;/LI&gt;
&lt;LI&gt;미리 정해진 값이 있다면 입력값에 따라 처리할 수 있다.(ex : sysdate)&lt;br /&gt;
&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;이제 Idea를 조합해보자.&lt;/P&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-RIGHT: #f3c534 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #f3c534 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; BORDER-LEFT: #f3c534 1px solid; PADDING-TOP: 10px; BORDER-BOTTOM: #f3c534 1px solid; BACKGROUND-COLOR: #fefeb8&quot;&gt;Update Table1&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Set column1 = (case when Length(:v1) &amp;gt; 0 then :v1 else column1 end),&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Set column2 = (case when :v2 = ‘today’ then sysdate else column2 end)&lt;br /&gt;
Where pk_column = :v3&lt;br /&gt;
&lt;/DIV&gt;&lt;br /&gt;
알고 보면 간단한 Update문의 Static SQL 처리였다.&lt;br /&gt;
&lt;br /&gt;&lt;div class=&quot;entry-ccl&quot; style=&quot;clear: both; text-align: right; margin-bottom: 10px&quot;&gt;
	&lt;img id=&quot;ccl-icon-9-0&quot; class=&quot;entry-ccl-by&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black01.png&quot; alt=&quot;저작자 표시&quot;/&gt;
	&lt;img id=&quot;ccl-icon-9-1&quot; class=&quot;entry-ccl-nc&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black02.png&quot; alt=&quot;비영리&quot;/&gt;
	&lt;img id=&quot;ccl-icon-9-2&quot; class=&quot;entry-ccl-nd&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black03.png&quot; alt=&quot;변경 금지&quot;/&gt;
	&lt;!--
	&lt;rdf:RDF xmlns=&quot;http://web.resource.org/cc/&quot; xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;&gt;
		&lt;Work rdf:about=&quot;&quot;&gt;
			&lt;license rdf:resource=&quot;http://creativecommons.org/licenses/by-nc-nd/2.0/kr/&quot; /&gt;
		&lt;/Work&gt;
		&lt;License rdf:about=&quot;http://creativecommons.org/licenses/by-nc-nd/&quot;&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Reproduction&quot;/&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Distribution&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Notice&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Attribution&quot;/&gt;
			&lt;prohibits rdf:resource=&quot;http://web.resource.org/cc/CommercialUse&quot;/&gt;
		&lt;/License&gt;
	&lt;/rdf:RDF&gt;
	--&gt;
&lt;/div&gt;
</description>
			<category>Static SQL</category>
			<category>Static SQL</category>
			<category>Update</category>
			<author>막장개발자</author>
			<guid>http://rtti.tistory.com/9</guid>
			<comments>http://rtti.tistory.com/entry/Update%EB%AC%B8%EC%9D%84-Static-SQL%EB%A1%9C-%EA%B5%AC%EC%84%B1%ED%95%98%EA%B8%B0#entry9comment</comments>
			<pubDate>Mon, 09 Feb 2009 21:15:02 +0900</pubDate>
		</item>
		<item>
			<title>Static SQL을 위한 무기[2] - Case When문</title>
			<link>http://rtti.tistory.com/entry/Static-SQL%EC%9D%84-%EC%9C%84%ED%95%9C-%EB%AC%B4%EA%B8%B02-Case-When%EB%AC%B8</link>
			<description>&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;&lt;STRONG&gt;Case When 문의 의미&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;br /&gt;
Case When문이나 Decode함수를 사용하여 Select절의 결과물을 원하는 대로 변경하는 SQL은 여러 번 본 적이 있다.&lt;br /&gt;
하지만 주변 사람들과 이야기해보면 의외로&amp;nbsp;Select절 뿐만 아니라 Where절, Order By절, Group By절 등에 다 사용할 수 있다는 사실을 모르는 경우가 있었는데 오늘은 이런 사실에 대해 이야기해보고자 한다.&lt;br /&gt;
&lt;br /&gt;Case When문의 활용범위는 무궁무진하며,&amp;nbsp;이 것을 사용하지 않고 Static한 SQL을 사용한다는 것이 필자로서는 거의 불가능하게 느껴진다. 앞으로의 포스트에서도 줄기차게 사용할 것이므로 관심이 있으신 분들은 여러 활용방법을 제대로 알아두면 좋을 것 같다.&lt;br /&gt;
&lt;br /&gt;&lt;br /&gt;
&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;Case When문&lt;/SPAN&gt;&lt;br /&gt;
&lt;/STRONG&gt;간단하게는 Case When문은 Decode함수의 확장이다.&lt;br /&gt;
Decode함수는 Oracle에서 제공되는 SQL 내의 if/else의 조건문 역할을 하는 함수이나 = 연산만 가능하다. Case When문은 이를 확장한 것이며, 논리연산, 산술연산, 관계 연산을 다 지원하며 Oracle 뿐만 아니라 MS-SQL에서도 지원한다.&lt;br /&gt;
(예전에 듣기로는 My-SQL에서도 지원한다고 들은 적이 있다. Test해보지는 않았지만.)&lt;br /&gt;
복잡한 조건일 수록 Case When문은 Decode문에 비해 가독성이 높고, 수행속도도 빠르다고 할 수 있겠다.&lt;br /&gt;
&lt;br /&gt;사용하는 문법은 다음과 같다.&lt;br /&gt;

&lt;UL style=&quot;LIST-STYLE-TYPE: square&quot;&gt;
&lt;LI&gt;case when [조건1] then [결과1] when [조건2] then?[결과2] ...else [결과3] end&lt;/LI&gt;
&lt;LI&gt;case [컬럼1] when [값1] then [결과1] when [값2] then [결과2] …&amp;nbsp; else [결과 3] end&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;&lt;STRONG&gt;Select 절에서의 활용&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;br /&gt;
실제로 가장 많이 사용되는 활용은 Select절에서일 것이다. 실제 우리가 가지고 있는 Data로부터 우리가 원한 Data를 뽑아내는데 자주 사용된다.&lt;/P&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-RIGHT: #f3c534 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #f3c534 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; BORDER-LEFT: #f3c534 1px solid; PADDING-TOP: 10px; BORDER-BOTTOM: #f3c534 1px solid; BACKGROUND-COLOR: #fefeb8&quot;&gt;Select (Case When name = ‘서울’ Then ‘수도권’&amp;nbsp;&amp;nbsp;When name = ‘경기도’ Then ‘수도권’ Else ‘비수도권’ End) city_group, name From City&lt;/DIV&gt;
&lt;P&gt;이 SQL은 당연히 다음과 같이도 사용가능하다.&lt;/P&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-RIGHT: #f3c534 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #f3c534 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; BORDER-LEFT: #f3c534 1px solid; PADDING-TOP: 10px; BORDER-BOTTOM: #f3c534 1px solid; BACKGROUND-COLOR: #fefeb8&quot;&gt;Select (Case name When ‘서울’ Then ‘수도권’&amp;nbsp;When ‘경기도’ Then ‘수도권’ Else ‘비수도권’ End) city_group, name From City&lt;br /&gt;
&lt;/DIV&gt;
&lt;P&gt;&lt;br /&gt;
지역이라는 Column이 없기 때문에 수도권인지 아닌지를 가져오기 위해 위와 같은 SQL을 사용하였다.&lt;br /&gt;
(왜 수도권에 &#039;인천&#039;은 없는지에 대해서 궁금해하는 사람은 없기 바란다. PT하다보면 가끔 그런 사람을 만날 수 있는데 정말 한숨만 나온다-_- 집중해야 할 곳에 집중하자.)&lt;br /&gt;
&lt;br /&gt;&lt;br /&gt;
&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;Group By 절에서의&amp;nbsp;활용&lt;/SPAN&gt;&lt;br /&gt;
&lt;/STRONG&gt;사례를 살펴보기 위해서&amp;nbsp;&lt;A title=&quot;[http://rtti.tistory.com/6]로 이동합니다.&quot; href=&quot;http://rtti.tistory.com/6&quot; target=_blank&gt;Cartesian Product(카테시안 곱) 항목&lt;/A&gt;에서&amp;nbsp;예로 들었던&amp;nbsp;SQL을 다시 가져와 보자.&lt;/P&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-RIGHT: #f3c534 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #f3c534 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; BORDER-LEFT: #f3c534 1px solid; PADDING-TOP: 10px; BORDER-BOTTOM: #f3c534 1px solid; BACKGROUND-COLOR: #fefeb8&quot;&gt;Select (Case tbl2.no1 When 1 Then tbl1.품목 Else ‘합계’ End), Sum(수량)&lt;br /&gt;
From Table1 tbl1, (Select 1 no1 From dual Union All Select 2 From dual) tbl2&lt;br /&gt;
Group By (Case tbl2.no1 When 1 Then tbl1.품목 Else ‘합계’ End), tbl2.no1&lt;/DIV&gt;&lt;br /&gt;
복제된 Data에서 no1이 1인 것은 품목으로 Group by를 하였고, 2인 것은 &quot;합계&quot; 즉 상수로 Group by를 하였다. 따라서, 1인 경우는 품목별로 합계를 구하게 되고, 나머지 항목들은 전체 Group by가&amp;nbsp;되게 될 것이다.&lt;br /&gt;
&lt;br /&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;&lt;STRONG&gt;Order By 절에서의 활용&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;br /&gt;
회사 직원을 이름&amp;nbsp;순으로 뽑아오는 쿼리가 있다고 하자. 어느 날 직원 시스템을 한 번도 써보지 않았던 사장님이 시스템에 들어가보니 본인 이름이 중간에 있는 것을 발견하고&amp;nbsp;명색이 사장님인데 직원들 순서 중에서 내가 제일 앞에 나와야 하지 않는가 하는 의문을 제기하였다.&lt;br /&gt;
&lt;br /&gt;그런-_- 이유로 고쳐야할 시스템의 요구사항은 다음과 같다.&lt;br /&gt;
사장님의 이름만 맨 앞으로 뽑아내고 나머지는 가나다 순으로 정렬하면 되는 것이다. 물론 일단 Data를 Client로 다 가져온 다음 프로그램 상에서 처리할 수도 있겠으나, 나중에 이 사실을 알게 된 이사님도 이의를 제기한다면? 다른 관리자들은? 이런 요구사항들을 다 Client에서 처리한다면 프로그램은 갈수록 복잡해지게 될 것이다.&lt;br /&gt;
&lt;br /&gt;따라서, 그런 요구사항의 변경은 SQL에서 적용하는 것이 가장 간단할 것이며, 이 것이 우리가 추구하고자 하는 Static SQL의 본질이다. (Static SQL이란 원하는 집합을 하나의 SQL로 뽑아내는 것을 말하며&amp;nbsp;이&amp;nbsp;문제영역에서는&amp;nbsp;사장님이 맨 앞에 나오고 다른 직원들은 이름순으로 정렬된 집합이 우리가 원하는 집합이다. 따라서,&amp;nbsp;그것을 하나의 SQL로 얻어와야 한다.)&lt;br /&gt;
&lt;br /&gt;Order by절에서는 오름차순이건, 내림차순이건 사장님의 이름만 맨 앞으로 뽑아올 수 없으나, Case When문을 사용하면 간단하다.&lt;br /&gt;
&lt;br /&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-RIGHT: #f3c534 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #f3c534 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; BORDER-LEFT: #f3c534 1px solid; PADDING-TOP: 10px; BORDER-BOTTOM: #f3c534 1px solid; BACKGROUND-COLOR: #fefeb8&quot;&gt;Select 이름&lt;br /&gt;
From Emp&lt;br /&gt;
Order By (Case When 직함 = &#039;사장&#039; Then 1 Else 2 End), 이름&lt;br /&gt;
&lt;/DIV&gt;&lt;br /&gt;
&lt;br /&gt;&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;&lt;STRONG&gt;Where절에서의 활용&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;br /&gt;
외부에서 들어온 조건(:v1)에 따라 서로 다른 동작을 정의하고자 할 때 사용할 수 있다.&lt;br /&gt;

&lt;DIV class=txc-textbox style=&quot;BORDER-RIGHT: #f3c534 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #f3c534 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; BORDER-LEFT: #f3c534 1px solid; PADDING-TOP: 10px; BORDER-BOTTOM: #f3c534 1px solid; BACKGROUND-COLOR: #fefeb8&quot;&gt;Select 이름&lt;br /&gt;
From Emp&lt;br /&gt;
Where (Case When Length(:v1) =&amp;nbsp;0 Then 1 Else Instr(이름, :v1) End) &amp;gt; 0&lt;br /&gt;
&lt;/DIV&gt;&lt;br /&gt;
검색할 이름에 대한 입력이 :v1에 들어오면 이름을 검색하여 결과를 보여주고 입력이 없으면 전체 직원의 이름을 Return하는 SQL이다. Where절을 동적으로 조합하지 않고 SQL 내부에서도 이러한 방법을 통해 서로 다른 결과값을 Return할 수 있다.&lt;br /&gt;
&lt;br /&gt;&lt;br /&gt;
&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;결론&lt;/SPAN&gt;&lt;br /&gt;
&lt;/STRONG&gt;SQL을 작성하는 여러가지 방법을 배우는 것은 문제에 따라 다양한 Idea를 내기 위한 필요조건이다. Client에서 혹은 PL/SQL에서의 if/else를 상당부분 SQL로 옮겨올 수 있는 Case When문을 익혀두는 것은 그 중에서도 첫 걸음이 될 수 있을 것이다.&lt;br /&gt;
&lt;br /&gt;&lt;div class=&quot;entry-ccl&quot; style=&quot;clear: both; text-align: right; margin-bottom: 10px&quot;&gt;
	&lt;img id=&quot;ccl-icon-8-0&quot; class=&quot;entry-ccl-by&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black01.png&quot; alt=&quot;저작자 표시&quot;/&gt;
	&lt;img id=&quot;ccl-icon-8-1&quot; class=&quot;entry-ccl-nc&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black02.png&quot; alt=&quot;비영리&quot;/&gt;
	&lt;img id=&quot;ccl-icon-8-2&quot; class=&quot;entry-ccl-nd&quot; src=&quot;http://i1.daumcdn.net/cfs.tistory/v/0/static/admin/editor/ccl_black03.png&quot; alt=&quot;변경 금지&quot;/&gt;
	&lt;!--
	&lt;rdf:RDF xmlns=&quot;http://web.resource.org/cc/&quot; xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;&gt;
		&lt;Work rdf:about=&quot;&quot;&gt;
			&lt;license rdf:resource=&quot;http://creativecommons.org/licenses/by-nc-nd/2.0/kr/&quot; /&gt;
		&lt;/Work&gt;
		&lt;License rdf:about=&quot;http://creativecommons.org/licenses/by-nc-nd/&quot;&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Reproduction&quot;/&gt;
			&lt;permits rdf:resource=&quot;http://web.resource.org/cc/Distribution&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Notice&quot;/&gt;
			&lt;requires rdf:resource=&quot;http://web.resource.org/cc/Attribution&quot;/&gt;
			&lt;prohibits rdf:resource=&quot;http://web.resource.org/cc/CommercialUse&quot;/&gt;
		&lt;/License&gt;
	&lt;/rdf:RDF&gt;
	--&gt;
&lt;/div&gt;
</description>
			<category>Static SQL</category>
			<category>CASE WHEN</category>
			<category>Static SQL</category>
			<author>막장개발자</author>
			<guid>http://rtti.tistory.com/8</guid>
			<comments>http://rtti.tistory.com/entry/Static-SQL%EC%9D%84-%EC%9C%84%ED%95%9C-%EB%AC%B4%EA%B8%B02-Case-When%EB%AC%B8#entry8comment</comments>
			<pubDate>Sun, 08 Feb 2009 18:45:46 +0900</pubDate>
		</item>
		<item>
			<title>Static SQL을 위한 무기[1] - Cartesian Product(카테시안 곱)</title>
			<link>http://rtti.tistory.com/entry/Static-SQL%EC%9D%84-%EC%9C%84%ED%95%9C-%EB%AC%B4%EA%B8%B01-Cartesian-Product%EC%B9%B4%ED%85%8C%EC%8B%9C%EC%95%88-%EA%B3%B1</link>
			<description>&lt;br /&gt;
&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;&lt;STRONG&gt;Cartesian Product란&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;br /&gt;
Query의&amp;nbsp;From절에 2개 이상의 Table이 있고, 두 Table 사이의 유효한 Join 조건이 기술되어 있지 않은 경우에는 두 Table의 모든 행들이 무조건 결합하여 Table들에 존재하는 행 갯수를&amp;nbsp;곱한 만큼의 결과값이 반환되는 것을 Cartesian Product(카테시안 곱)라고 한다.&lt;br /&gt;
&lt;br /&gt;말로 써놓으니 어려운 듯 하지만, 실제로는 크게 어려운 개념이 아니다.&lt;br /&gt;
아래의 예를 보자. 각 품목별 수량의 합계와 전체합계를 한꺼번에 구하는 Static SQL이다.&lt;br /&gt;

&lt;DIV class=txc-textbox style=&quot;BORDER-RIGHT: #f3c534 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #f3c534 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; BORDER-LEFT: #f3c534 1px solid; PADDING-TOP: 10px; BORDER-BOTTOM: #f3c534 1px solid; BACKGROUND-COLOR: #fefeb8&quot;&gt;Select (Case tbl2.no1 When 1 Then tbl1.품목 Else ‘합계’ End), Sum(수량)&lt;br /&gt;
From Table1 tbl1,&amp;nbsp;(Select 1 no1 From dual Union All Select 2 From Dual) tbl2&lt;br /&gt;
Group By (Case tbl2.no1 When 1 Then tbl1.품목 Else ‘합계’ End), tbl2.no1&lt;br /&gt;
&lt;/DIV&gt;&lt;br /&gt;
&lt;div class=&quot;imageblock center&quot; style=&quot;text-align: center; clear: both;&quot;&gt;&lt;img src=&quot;http://cfs10.tistory.com/image/21/tistory/2009/02/02/20/37/4986db0899846&quot; alt=&quot;&quot; filemime=&quot;&quot; filename=&quot;CartesianProduct.jpg&quot; height=&quot;159&quot; width=&quot;490&quot;/&gt;&lt;/div&gt;&lt;br /&gt;
tbl1의 결과값과 tbl2의 결과값 사이에 유효한 Join 조건이 기술되지 않았으므로 Cartesian Product가 일어나게 되며 위 그림은 이 과정을 거친 중간 결과집합을 보여주고 있다. 이 중간집합을 Group By하여 품목별 합계와 전체합계를 한 번에 구할 수 있는 것이다. 결과가 궁금하신 분들은 실제로 한 번 Test해보셔도 좋겠다.&lt;br /&gt;
(한가지 부언하자면, Oracle도 이전 Version에서는 Sort Group By를 채택하여 전체 합계가 맨 밑에 나왔지만, Hash Group By 실행계획으로 풀린다면 품목별&amp;nbsp;합계와 전체&amp;nbsp;합계의 순서가 뒤섞여 나오게 될 것이다. 이런 경우에는 Order By절을 추가하여 원하는 순서대로 바로 잡아주도록 하자&lt;sup class=&quot;footnote&quot;&gt;&lt;a id=&quot;footnote_link_6_1&quot; href=&quot;#footnote_6_1&quot; onmouseover=&quot;tistoryFootnote.show(this, 6, 1)&quot; onmouseout=&quot;tistoryFootnote.hide(6, 1)&quot; style=&quot;color: #f9650d; font-family: Verdana, Sans-serif&quot;&gt;&lt;span style=&quot;display: none&quot;&gt;[각주:&lt;/span&gt;1&lt;span style=&quot;display: none&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;)&lt;br /&gt;
&lt;br /&gt;이러한 Cartesian Product는 Static한 SQL을 사용하기 위해 우리가 사용할 수 있는 중요한 무기 중 하나이며, &lt;A title=&quot;[http://rtti.tistory.com/2]로 이동합니다.&quot; href=&quot;http://rtti.tistory.com/2&quot; target=_blank&gt;이전 포스트&lt;/A&gt;에서도 사용자의 입력을 여러 개로 구분하기 위해 Cartesian Product를 사용한 바 있다. 개념을 잘 이해하여 중요한 순간에 쓸 수 있도록 우리의 무기창고에 잘 넣어두도록 하자.&lt;br /&gt;
&lt;br /&gt;다음 포스트에서는&amp;nbsp;오늘 Query에서도&amp;nbsp;쓰였던 Case When문에 대해 써보도록 하겠다. &lt;br /&gt;
&lt;br /&gt;
&lt;DIV&gt;
&lt;HR style=&quot;BORDER-TOP-WIDTH: 1px; DISPLAY: block; BORDER-LEFT-WIDTH: 0px; BORDER-LEFT-COLOR: black; BORDER-BOTTOM-WIDTH: 0px; BORDER-BOTTOM-COLOR: black; BORDER-TOP-COLOR: black; HEIGHT: 1px; BORDER-RIGHT-WIDTH: 0px; BORDER-RIGHT-COLOR: black&quot;&gt;
&lt;/DIV&gt;&lt;br /&gt;&lt;div class=&quot;footnotes&quot;&gt;
	&lt;ol class=&quot;footnotes&quot;&gt;
		&lt;li id=&quot;footnote_6_1&quot;&gt;Sort Group By란 Group By의 결과를 내기 위해 내부적으로 Sort를 사용하는 방식이다. 따라서, 결과값은 당연히 Group By절에 기술된 대로 Sort되어 나온다. 하지만, Hash Group By는 Sort를 사용하지 않고 Group By하게 되므로 결과값이 정렬되지 않는다.&amp;#13;&amp;#10; &lt;a href=&quot;#footnote_link_6_1&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
	&lt;/ol&gt;
&lt;/div&gt;
</description>
			<category>Static SQL</category>
			<category>Cartesian Product</category>
			<category>Static SQL</category>
			<author>막장개발자</author>
			<guid>http://rtti.tistory.com/6</guid>
			<comments>http://rtti.tistory.com/entry/Static-SQL%EC%9D%84-%EC%9C%84%ED%95%9C-%EB%AC%B4%EA%B8%B01-Cartesian-Product%EC%B9%B4%ED%85%8C%EC%8B%9C%EC%95%88-%EA%B3%B1#entry6comment</comments>
			<pubDate>Mon, 02 Feb 2009 20:58:47 +0900</pubDate>
		</item>
		<item>
			<title>사용자 선택을 Static SQL로 구성하기(부제 : getIndexString 함수의 oracle version)</title>
			<link>http://rtti.tistory.com/entry/%EC%82%AC%EC%9A%A9%EC%9E%90-%EC%84%A0%ED%83%9D%EC%9D%84-Static-SQL%EB%A1%9C-%EA%B5%AC%EC%84%B1%ED%95%98%EA%B8%B0%EB%B6%80%EC%A0%9C-getIndexString-%ED%95%A8%EC%88%98%EC%9D%98-oracle-version</link>
			<description>&lt;P&gt;원래 Static SQL이란 카테고리가 만들어 진 것보다 이 포스트를 작성한 게 먼저였으나, 쓰고보니 달랑 이 글만 올려놓기 보다는 Static SQL에 대해서 한 번 정리해보고자 하는 생각이 들어 한동안 비공개로 잠들어있던&amp;nbsp;비운의(?) 포스트이다.&lt;br /&gt;
&lt;/P&gt;
&lt;DIV&gt;&lt;br /&gt;

&lt;HR style=&quot;BORDER-TOP-WIDTH: 1px; DISPLAY: block; BORDER-LEFT-WIDTH: 0px; BORDER-LEFT-COLOR: black; BORDER-BOTTOM-WIDTH: 0px; BORDER-BOTTOM-COLOR: black; BORDER-TOP-COLOR: black; HEIGHT: 1px; BORDER-RIGHT-WIDTH: 0px; BORDER-RIGHT-COLOR: black&quot;&gt;
&lt;/DIV&gt;
&lt;P&gt;&lt;br /&gt;
Static한 SQL을 구사하는 데에 가끔 까다롭게 느껴지는 것이 사용자 선택이나 입력사항을 Static하게 구성하는 것이다.&lt;br /&gt;
예를 들어, 사용자가 A,B,C 항목을 선택했다고 할 때 &lt;br /&gt;
&lt;br /&gt;Select column1, column2, column3&lt;br /&gt;
From Table1&lt;br /&gt;
Where column1 in (&#039;A&#039;, &#039;B&#039;, &#039;C&#039;)&lt;br /&gt;
와 같은 SQL을 작성해야 한다고 하자.&lt;br /&gt;
&lt;br /&gt;사용자가 몇 개를 선택할지 알 수 없기 때문에 아래와 같은 Binding Parameter처리가 불가능한 것은 당연하다.&lt;br /&gt;
Select column1, column2, column3&lt;br /&gt;
From Table1&lt;br /&gt;
Where column1 in (:v1, :v2, :v3)&lt;br /&gt;
&lt;br /&gt;&lt;br /&gt;
이런 경우&amp;nbsp;Dynamic SQL을 작성하는 경우가 많았고, 뭔가 &#039;이건 아닌데..&#039; 하면서도 다른 대안이 없었다.&amp;nbsp;&amp;nbsp;&lt;br /&gt;
그러던 중,&amp;nbsp; &lt;A title=&quot;[http://www.devpia.com]로 이동합니다.&quot; href=&quot;http://www.devpia.com/&quot; target=_blank&gt;데브피아&lt;/A&gt;에서 &lt;A title=&quot;[http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=39&amp;amp;MAEULNo=16&amp;amp;no=532&amp;amp;ref=532]로 이동합니다.&quot; href=&quot;http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=39&amp;amp;MAEULNo=16&amp;amp;no=532&amp;amp;ref=532&quot; target=_blank&gt;박정진(bleujin)님의 글&lt;/A&gt;을 읽고 방법을 찾았는데 Cartesian Product와 사용자 정의 함수를 이용하여 멋지게 문제를 해결한 방법이었다. 이 자리를 빌어 다시 한번 감사드린다.&lt;br /&gt;
시간이 되시는 분들은 링크를 타고 원문을 한번 읽어보시기 바라며, 강좌와 팁란에서 이름으로 검색하시면 주옥같은 글들을 더 보실 수 있을 것이다.&lt;br /&gt;
&lt;br /&gt;그동안 잘 써먹었었는데, 최근 oracle용으로 이 함수가 필요해 찾아보니&amp;nbsp;예전에 작성했던 건 Backup을 안해놨고 어디 있는지 찾기도 귀찮아&amp;nbsp;그냥 다시 작성했고 나중에 또 못찾을까봐-_- 여기 올려두기로 했다.&lt;br /&gt;
v_FullString : 전체 문자열(‘a|b|c|d|’)&lt;br /&gt;
v_DivString : 구분자(’|’)&lt;br /&gt;
v_Index : 몇 번째 내용(항목)을 가지고 올 것인가&lt;br /&gt;
&lt;/P&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-RIGHT: #f3c534 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #f3c534 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; BORDER-LEFT: #f3c534 1px solid; PADDING-TOP: 10px; BORDER-BOTTOM: #f3c534 1px solid; BACKGROUND-COLOR: #fefeb8&quot;&gt;Create Or Replace Function getIndexString(v_FullString in varchar2, v_DivString in varchar2, v_Index&amp;nbsp; in number)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Return varchar2&lt;br /&gt;
Is&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; v_CurrIndex number;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; v_RetString varchar2(4000);&lt;br /&gt;
Begin&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; v_CurrIndex := 1;&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;v_RetString :=v_FullString;&lt;br /&gt;
&amp;nbsp; &amp;nbsp;While v_CurrIndex &amp;lt; v_Index Loop&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; v_RetString := Substr(v_RetString, Instr(v_RetString, v_DivString) + Length(v_DivString),&amp;nbsp;Length(v_RetString);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; v_CurrIndex :=v_CurrIndex + 1;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; End Loop&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Return Substr(v_RetString, 0, Instr(v_RetString, v_DivString) -1;&lt;br /&gt;
End;&lt;br /&gt;
&lt;/DIV&gt;
&lt;P&gt;&lt;br /&gt;
&lt;br /&gt;oracle에서 getIndexString 함수를 이용하여 변하는 사용자 입력값을 Static SQL로 변환하는 방법은 다음와 같다.&lt;/P&gt;
&lt;DIV class=txc-textbox style=&quot;BORDER-RIGHT: #f3c534 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: #f3c534 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; BORDER-LEFT: #f3c534 1px solid; PADDING-TOP: 10px; BORDER-BOTTOM: #f3c534 1px solid; BACKGROUND-COLOR: #fefeb8&quot;&gt;Select * From Table1 Where column1 in &lt;br /&gt;
( &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; Select getIndexString(tbl1.fullStr, tbl1.divStr, tbl2.no1)&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;From (Select :v1 fullStr : v2 divStr From dual) tbl1, copy_t tbl2&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;Where tbl2.no1 &amp;lt;=&amp;nbsp; (Length(tbl1.fullStr) - Length(replace(tbl1.fullStr, tbl1.divStr, ‘’)) / Length(tbl1.divStr))&lt;br /&gt;
)&lt;br /&gt;
&lt;/DIV&gt;
&lt;P&gt;&lt;br /&gt;
간단히 설명하자면, copy_t는 복제용 Table이며, 보통 1~31까지의 값을 갖는 Table이다.&lt;br /&gt;
In 절 내의 SQL에서 Where 조건에 유효한 Join 조건이 기술되지 않았으므로 tbl1과 tbl2의 곱만큼 복제(Cartesian Product)가 일어나게 되고 이 복제된 Row들이 getIndexString을 거치면서 원하는 값들을 가진 Row로 가공되어 In 절에 공급되게 된다.&lt;br /&gt;
&lt;br /&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;Where tbl2.no1 &amp;lt;=&amp;nbsp; (Length(tbl1.fullStr) - Length(replace(tbl1.fullStr, tbl1.divStr, ‘’)) / Length(tbl1.divStr)) 조건은 &lt;/SPAN&gt;&lt;br /&gt;
&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 16pt; FONT-FAMILY: 굴림; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;Where tbl2.no1 &amp;lt;=&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-spacerun: yes&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;(Length(&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 16pt; FONT-FAMILY: Arial; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;‘&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: 굴림; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;a|b|c|d|e|f|&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: Arial; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;’&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: 굴림; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;) &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: Arial; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;–&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: 굴림; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;Legnth(&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: Arial; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;‘&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: 굴림; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;abcdef&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: Arial; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;’&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: 굴림; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;) / Length(&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: Arial; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;‘&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: 굴림; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;|&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: Arial; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;’&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: 굴림; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;))&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt; 과 같으므로&lt;br /&gt;
결국 tbl2.no1 &amp;lt;= 6(들어온 입력값의 갯수)가 되고, 따라서 들어온 입력값만큼 복제가 일어나게 된다.&lt;br /&gt;
&lt;br /&gt;&lt;div class=&quot;imageblock center&quot; style=&quot;text-align: center; clear: both;&quot;&gt;&lt;img src=&quot;http://cfs15.tistory.com/image/31/tistory/2009/01/10/14/37/4968342a3c9bd&quot; alt=&quot;&quot; filemime=&quot;&quot; filename=&quot;getIndexString.jpg&quot; height=&quot;140&quot; width=&quot;492&quot;/&gt;&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/P&gt;
&lt;P&gt;&lt;/P&gt;
&lt;P&gt;getIndexString 사용자정의 함수는 no1의 값에 따라 전체문제열에서 구분된 항목을 뽑아오는 함수이므로 a, b, c, d, e, f가 In절에 공급되게 된다.&lt;br /&gt;
&lt;br /&gt;너무 깔끔하지 않은가? Static한 SQL에 한번 맛을 들이고 나면 실력이 모자라 어쩔 수 없이&amp;nbsp;Dynamic SQL을 사용하게 되는 경우 웬지모를 죄책감을 가지게 되며,&amp;nbsp;끊임없이 해결방법을 찾아 헤메이게 될 것이다.&lt;br /&gt;
&lt;br /&gt;&lt;br /&gt;
&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;div class=&quot;blogger-news-widget&quot; style=&quot;width: 100%; text-align: center&quot;&gt;
		  					&lt;embed src=&quot;http://api.v.daum.net/static/recombox1.swf&quot; quality=&quot;high&quot; flashvars=&quot;nid=2459325&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;false&quot; bgcolor=&quot;#ffffff&quot; width=&quot;400&quot; height=&quot;80&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;transparent&quot;&gt;&lt;/embed&gt;
						&lt;/div&gt;</description>
			<category>Static SQL</category>
			<category>Cartesian Product</category>
			<category>Static SQL</category>
			<author>막장개발자</author>
			<guid>http://rtti.tistory.com/2</guid>
			<comments>http://rtti.tistory.com/entry/%EC%82%AC%EC%9A%A9%EC%9E%90-%EC%84%A0%ED%83%9D%EC%9D%84-Static-SQL%EB%A1%9C-%EA%B5%AC%EC%84%B1%ED%95%98%EA%B8%B0%EB%B6%80%EC%A0%9C-getIndexString-%ED%95%A8%EC%88%98%EC%9D%98-oracle-version#entry2comment</comments>
			<pubDate>Sun, 01 Feb 2009 05:28:25 +0900</pubDate>
		</item>
		<item>
			<title>왜 Static SQL인가?</title>
			<link>http://rtti.tistory.com/entry/%EC%99%9C-Static-SQL%EC%9D%B8%EA%B0%80</link>
			<description>Static SQL에 대한 연재를 하자면 왜 Static SQL을 사용하여야 하는가에 대한 설명이 있어야하지 않겠는가? &lt;br /&gt;
어쩔 수 없이 글을 길게 쓰게 됬지만 긴 글을 읽기 싫은 분들은 결론만 읽으셔도 되겠다.&lt;br /&gt;
&lt;br /&gt;&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;Static SQL과 Dynamic SQL&lt;/SPAN&gt;&lt;br /&gt;
&lt;/STRONG&gt;DBMS는(정확히 말해서는 Optimizer는) 다음과 같은 SQL을 다 다른 SQL로 처리하며 이를 Dynamic SQL이라고 한다.&amp;nbsp; 
&lt;DIV class=O1 v:shape=&quot;_x0000_s1026&quot;&gt;
&lt;DIV style=&quot;mso-line-spacing: &#039;80 20 0&#039;; mso-margin-left-alt: 468; mso-char-wrap: 1; mso-kinsoku-overflow: 1; mso-word-wrap: 0; mso-vertical-align-special: top&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 78%; FONT-FAMILY: 굴림&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 70%; LEFT: -4.82%; COLOR: #247c41; FONT-FAMILY: Wingdings; POSITION: absolute; TOP: 0.39em; mso-special-format: bullet; mso-color-index: 5&quot;&gt;n&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: 굴림; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;Select * From Table1 Where Column1 = &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: Arial; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;‘&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: 굴림; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;1&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: Arial; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;’&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: 굴림; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV style=&quot;mso-line-spacing: &#039;80 20 0&#039;; mso-margin-left-alt: 468; mso-char-wrap: 1; mso-kinsoku-overflow: 1; mso-word-wrap: 0; mso-vertical-align-special: top&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 78%; FONT-FAMILY: 굴림&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 70%; LEFT: -4.82%; COLOR: #247c41; FONT-FAMILY: Wingdings; POSITION: absolute; TOP: 0.39em; mso-special-format: bullet; mso-color-index: 5&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;n&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: 굴림; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;Select * From Table1 Where Column1 = &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: Arial; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;‘&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: 굴림; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;2&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: Arial; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;’&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: 굴림; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/DIV&gt;
&lt;DIV style=&quot;mso-line-spacing: &#039;80 20 0&#039;; mso-margin-left-alt: 468; mso-char-wrap: 1; mso-kinsoku-overflow: 1; mso-word-wrap: 0; mso-vertical-align-special: top&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 78%; FONT-FAMILY: 굴림&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 70%; LEFT: -4.82%; COLOR: #247c41; FONT-FAMILY: Wingdings; POSITION: absolute; TOP: 0.39em; mso-special-format: bullet; mso-color-index: 5&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;n&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: 굴림; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;Select * From Table1 Where Column1 = &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: Arial; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;‘&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: 굴림; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;3&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: Arial; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;’&lt;br /&gt;
(일부 DBMS에서는 이것을 자동으로 변수처리해주기도 하는데 복잡한 SQL에서는 기대할만한 기능이 아니다.)&lt;br /&gt;
&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;br /&gt;
반면, Static SQL은 위와 같은 SQL을 다음과 같이 작성한다.&lt;br /&gt;
&lt;SPAN style=&quot;mso-bidi-font-family: Arial&quot;&gt;&lt;SPAN lang=EN-US style=&quot;FONT-SIZE: 14pt; FONT-FAMILY: 굴림; mso-ascii-font-family: 굴림; mso-fareast-font-family: 굴림; mso-hansi-font-family: Arial; mso-fareast-language: KO&quot;&gt;&lt;SPAN style=&quot;FONT-SIZE: 9pt&quot;&gt;Select * From Table1 Where Column1 = :v1&lt;br /&gt;
&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;:v1과 같은 방식을 Parameter Binding이라고 하며 변하는 부분을 변수처리한 것이라고 생각하면 되겠다.&lt;br /&gt;
Parameter Binding == Static SQL은 아니지만 오늘 이야기할 내용은 그렇게 이해해도 충분하리라 생각한다.&lt;br /&gt;
&lt;br /&gt;&lt;br /&gt;
&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;SQL의 수행과정&lt;/SPAN&gt;&lt;br /&gt;
&lt;/STRONG&gt;SQL은 어떤 단계를 거쳐 수행되는 것일까?&lt;br /&gt;
물론 SQL문은 원하는 집합을 규정하는 언어일 뿐, 처리 방법을 기술하는 언어는 아니다. 하지만 실제로는 수행되는 절차가 있는데 이에 대해서 한번 알아보자.&lt;br /&gt;
&lt;br /&gt;Oracle기준이며 DML문과 DDL문은 수행방법이 약간 다른데 Select문과 같은 DML문에 대해서만 언급하도록 하겠다.&lt;br /&gt;
1. 파싱(구문/의미검사)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; 1) 구문검사 : SQL 문법에 맞는가? 예를 들어 Select를 Selct라고 오타가 난 경우 여기서 Error를 발생한다.&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; 2) 의미검사 :&amp;nbsp;SQL이 실행가능한가? 컬럼명이나 테이블명이 명확하고 애매함이 없는가?&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;3) 공유풀검사 : 이미 실행계획이 세워져 수행된 Query인지 공유풀(Shared Pool)을 검사하고&amp;nbsp;세워진 실행계획이 있다면&amp;nbsp;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;이를 재사용하여 실행전단계까지 건너뛴다.(소프트파스)&lt;br /&gt;
&lt;br /&gt;2. 실행계획 수립&lt;br /&gt;
실행계획이란 SQL을 수행할 순서를 말한다. Table1과 Table2가 Join을 하고 있다면 Nested Loop Join방식으로 처리할 것인지 Sort Merge Join으로 처리할지 Hash Join일지를 결정한다. &lt;br /&gt;
또한, Nested Loop Join이라면 Table1을 먼저&amp;nbsp;Driving(읽을)할 것인지 어떤 Index를 사용할 것인지... 등등을 결정하게 된다.&lt;br /&gt;
실행계획은 Optimizer가 세우게 되는데&amp;nbsp;그 Optimizer가 RBO(Rule Based Optimizer)인지 CBO(Cost Based Optimizer)인지에 따라&amp;nbsp;실행계획을 세우는 방법은 다르지만 어쨋든 실행계획은 이 단계에서 수립된다.&lt;br /&gt;
&lt;br /&gt;잘 이해가 안된다면 Optimizer가 실행계획이란 것을 세우고, 그 계획에 따라 SQL이 처리된다는 것만 이해하고 넘어가자. 여기서 설명하고자 하는 요점은 바로 그 것이다.&lt;br /&gt;
&lt;br /&gt;3.&amp;nbsp; Parameter Binding 및 실행&lt;br /&gt;
Parameter 처리된 실제 값을 적용하고 SQL을 실행한다.&lt;br /&gt;
&lt;br /&gt;&lt;br /&gt;
&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;&lt;STRONG&gt;실행계획 수립의 비용&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;br /&gt;
이 실행계획 수립은 비용이 많이 드는 연산이다.&amp;nbsp;이 단계를 건너뛸 수 있다면 우리는 상당한 시간을 절약할 수 있을 것이다.&lt;br /&gt;
또한 하나의 실행계획을 세우기 위해서는 공유풀에 접근하여 현재 사용가능한 Index가 어떤 것이 있는지 Column의 분포도가 어떠한지를 살펴보아야 한다. 하지만 이러한 구조을 살펴보기 위해서는 이 구조에 대한 다른 접근을 막아야 한다. Index를 타는 것이 타당한지 살펴보고 있는데 다른 사용자가 Index를 지운다고 생각해보자. 당연히 문제가 발생하지 않겠는가.&lt;br /&gt;
따라서 이런 구조에 대한 접근은 직렬화되며 따라서 실행계획을 수립하기 위한 SQL이 많다면 자신의 차례가 올때까지 기다려야 한다.&lt;br /&gt;
&lt;br /&gt;&lt;br /&gt;
&lt;STRONG&gt;실행계획 확인의 비용&lt;/STRONG&gt;&lt;br /&gt;
어느날 DBA가&amp;nbsp;어떤 Table에 하나의 Index를 더 만들겠다고 선언했다. Optimizer는 새로운 Index가 생겼으므로 기존의 실행계획을 다시 검토해볼 수 있다. 따라서, 우리는 그 Index가 그 Table을 접근하는 SQL의 실행계획에 영향을 주지 않는지 검토해보아야 할 것이다. 하지만, Dynamic SQL을 사용한 경우에는 확인 자체도 그리 만만하지 않다.&lt;br /&gt;
예를 들어 Where절을 동적으로 결합하기 위한 if/else 문이 2개가 있다고 하면 그 경우의 수는 4가지이며 그 4가지 경로에 대한 실행계획의 변경을 재검토해보아야 할 것이다.(3개라면 경우의 수는 8개이다.)&lt;br /&gt;
하지만 Static SQL은 하나의 SQL로 모든 것을 처리하므로 하나의 SQL에 대한 실행계획만 검토해보면 된다.&lt;br /&gt;
&lt;br /&gt;&lt;br /&gt;
&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;Parameter Binding과 SQL Injection&lt;/SPAN&gt;&lt;br /&gt;
&lt;/STRONG&gt;Parameter Binding 방식은 SQL Injection을 방지하는 한가지 방법이다. SQL Injection이란 Query에 SQL을 주입하여 원하지 않는 행동(Admin 권한 획득 혹은 Table Drop 등)을 할 수 있는 악의적인&amp;nbsp;보안 Issue&amp;nbsp;중 하나이다.&lt;br /&gt;
SQL Injection만으로도 엄청난 주제이니 관련 사항은 인터넷을 찾아보기 바란다.&lt;br /&gt;
&lt;br /&gt;&lt;br /&gt;
&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;왜 Static SQL인가&lt;/SPAN&gt;&lt;br /&gt;
&lt;/STRONG&gt;공유풀을 적절히 활용하고, 보안문제도 손쉽게 해결할 수 있으며 Debugging 혹은 실행계획 검토도 쉽게 만들어줄 수 있는 방식이다. 이 방법을 몰랐다면 모르지만 알면서도 사용하지 않는다면 꿈에 Optimizer가 나타나서 괴롭힐지도 모른다.-_-&lt;br /&gt;
Dynamic SQL은 Toad와 같은 DB 개발 Tool에서는&amp;nbsp;사용해도 무방한 방식이지만&amp;nbsp;프로그램에 의해 자주 사용되는 SQL이 Dynamic SQL이어서는 안될 것이다. &lt;br /&gt;
&lt;br /&gt;물론 단점도 있다.&lt;br /&gt;
처음&amp;nbsp;예로 든 SQL은 누가 봐도 이해할 만하지만 알다시피 현실세계의 문제들은 그리 간단하지 않다. SQL이 복잡해지면 질수록&amp;nbsp;Static한 SQL은 더더욱 복잡해진다. 따라서 일부 사람들이 가독성의 문제를 제기하기도 한다. (필자의 경우에는 if/then/else를 사용한 SQL이 더 가독성이 없다고 생각한다.) 가독성에 대한&amp;nbsp;문제제기를 받았다면&amp;nbsp;&lt;A title=&quot;[http://rtti.tistory.com//1]로 이동합니다.&quot; href=&quot;http://rtti.tistory.com//1&quot; target=_blank&gt;&lt;A title=&quot;[http://rtti.tistory.com/1]로 이동합니다.&quot; href=&quot;http://rtti.tistory.com/1&quot; target=_blank&gt;이 포스트&lt;/A&gt;&lt;/A&gt;를 참고하라.&lt;br /&gt;
또, CBO는 Parameter Binding된 변수에 대해 통계정보를 활용하지 못한다. 이에 대해서는 이후에 다시 설명하게 될 것이다.&lt;br /&gt;
&lt;br /&gt;하나 하나의 주제만 해도 수십페이지는 될 내용을&amp;nbsp;한 번에 &amp;nbsp;요약하였으니, 잘 이해가 안 갈만도 하다. 이해가 안가는 부분이나 용어는&amp;nbsp;인터넷에 많은 자료들이 있으니 한번 찾아보기 바란다. &lt;br /&gt;
무책임해서 미안하다.-_-&lt;br /&gt;
&lt;br /&gt;다음 포스트부터는 이제&amp;nbsp;본격적으로 Static SQL을 뒤집어보자.&lt;br /&gt;
&lt;br /&gt;&lt;div class=&quot;blogger-news-widget&quot; style=&quot;width: 100%; text-align: center&quot;&gt;
		  					&lt;embed src=&quot;http://api.v.daum.net/static/recombox1.swf&quot; quality=&quot;high&quot; flashvars=&quot;nid=2459326&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;false&quot; bgcolor=&quot;#ffffff&quot; width=&quot;400&quot; height=&quot;80&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;transparent&quot;&gt;&lt;/embed&gt;
						&lt;/div&gt;</description>
			<category>Static SQL</category>
			<category>Static SQL</category>
			<category>실행계획</category>
			<author>막장개발자</author>
			<guid>http://rtti.tistory.com/4</guid>
			<comments>http://rtti.tistory.com/entry/%EC%99%9C-Static-SQL%EC%9D%B8%EA%B0%80#entry4comment</comments>
			<pubDate>Sun, 01 Feb 2009 05:27:45 +0900</pubDate>
		</item>
		<item>
			<title>카테고리 설명[Static SQL]</title>
			<link>http://rtti.tistory.com/entry/%EC%B9%B4%ED%85%8C%EA%B3%A0%EB%A6%AC-%EC%84%A4%EB%AA%85Static-SQL</link>
			<description>&lt;P&gt;Static한 SQL란 무엇일까?&lt;br /&gt;
Static SQL란 Dynamic SQL에 반대되는 개념으로서 &lt;STRONG&gt;원하는 집합&lt;sup class=&quot;footnote&quot;&gt;&lt;a id=&quot;footnote_link_3_1&quot; href=&quot;#footnote_3_1&quot; onmouseover=&quot;tistoryFootnote.show(this, 3, 1)&quot; onmouseout=&quot;tistoryFootnote.hide(3, 1)&quot; style=&quot;color: #f9650d; font-family: Verdana, Sans-serif&quot;&gt;&lt;span style=&quot;display: none&quot;&gt;[각주:&lt;/span&gt;1&lt;span style=&quot;display: none&quot;&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;을 얻어오는 데 필요한 Query를 하나의 SQL문으로 작성&lt;/STRONG&gt;하는 것을 말한다. 즉, 프로그래밍 언어나 PL/SQL을 이용해 동적으로 생성하지 않는 것이며,&amp;nbsp;if/then/else 와 문자열 합성을 사용하지 않는 것을 말한다. &lt;br /&gt;
&lt;br /&gt;개념은 간단하나 알아야 할 내용은 생각보다 많다. 하지만 조금씩 알아갈수록 뭔가 가슴 뿌듯해지는 주제이기도 하다.&lt;br /&gt;
요즘 사용하고 있는 DB가 Oracle이라 Oracle 위주로 적어나가겠지만, 타 DB에서도 개념적으로 크게 다른 부분은 없으리라 생각한다.&lt;br /&gt;
&lt;br /&gt;그럴 듯하게 적어놨지만, 필자도 쌩초보에서 그냥 초보 사이를 왔다갔다 하는 수준이라 삽질이 좀 필요할 것이다. 워낙 천성이 게으른지라 연재의 마무리가 언제일지는 아무도 모른다. &lt;br /&gt;
&lt;br /&gt;어쨋든!!&lt;br /&gt;
이 카테고리에서는 Static Query를 위한 개념, 기법, 사례를 중심으로 기술할 예정이다.&lt;br /&gt;
&lt;br /&gt;&lt;br /&gt;
&lt;/P&gt;
&lt;DIV&gt;
&lt;HR style=&quot;BORDER-TOP-WIDTH: 1px; DISPLAY: block; BORDER-LEFT-WIDTH: 0px; BORDER-LEFT-COLOR: black; BORDER-BOTTOM-WIDTH: 0px; BORDER-BOTTOM-COLOR: black; BORDER-TOP-COLOR: black; HEIGHT: 1px; BORDER-RIGHT-WIDTH: 0px; BORDER-RIGHT-COLOR: black&quot;&gt;
&lt;br /&gt;
&lt;/DIV&gt;&lt;div class=&quot;footnotes&quot;&gt;
	&lt;ol class=&quot;footnotes&quot;&gt;
		&lt;li id=&quot;footnote_3_1&quot;&gt;원하는 집합 :  &quot;원하는 집합&quot;이라는 용어에 대해서도 하고 싶은 말이 있지만, 추후 기회가 되면 포스팅하도록 하겠다.&amp;#13;&amp;#10; &lt;a href=&quot;#footnote_link_3_1&quot;&gt;[본문으로]&lt;/a&gt;&lt;/li&gt;
	&lt;/ol&gt;
&lt;/div&gt;
</description>
			<category>Static SQL</category>
			<category>Static SQL</category>
			<author>막장개발자</author>
			<guid>http://rtti.tistory.com/3</guid>
			<comments>http://rtti.tistory.com/entry/%EC%B9%B4%ED%85%8C%EA%B3%A0%EB%A6%AC-%EC%84%A4%EB%AA%85Static-SQL#entry3comment</comments>
			<pubDate>Thu, 29 Jan 2009 21:26:02 +0900</pubDate>
		</item>
		<item>
			<title>Code의 가독성에 대한 진실</title>
			<link>http://rtti.tistory.com/entry/Code%EC%9D%98-%EA%B0%80%EB%8F%85%EC%84%B1%EC%97%90-%EB%8C%80%ED%95%9C-%EC%A7%84%EC%8B%A4</link>
			<description>&lt;P&gt;&lt;br /&gt;
프로그램 쪽으로 밥을 먹고 살다 보면 많이 듣게 되는 용어들이 있다.&amp;nbsp; 오늘 포스트의 주제인 &#039;가독성&#039;도 그 중 한가지인데 그에 대한 이야기를 해보고자 한다.&lt;br /&gt;
&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;&lt;br /&gt;
&lt;br /&gt;가독성 있는 Code&lt;/SPAN&gt;&lt;br /&gt;
&lt;/STRONG&gt;전직장에서 있었던 일이다.&amp;nbsp; 새로 오신 과장님 한 분과 Project를 하나 같이 진행했었는데 재미있는 일이 하나 생겼다.&amp;nbsp; 그분 왈, 필자가 짠 Query는 도무지 알아볼수가 없으며 실력을 자랑하기 위해 일부러 어렵게 짠, 일명 잘난 체하는 Query라는 것이다. 모름지기 모든 Code와 Query는 가독성이 우선이란다.&lt;br /&gt;
&lt;br /&gt;필자가 일하고 있는 공장자동화 분야 중 상위시스템에서 다루는 데이터들은 년단위로 쌓이면 수백만~수천만건은 금방이다.&amp;nbsp; 그런 다량의 데이터를 다룰 때 프로그래머는 본인이 작성한 SQL이 하는 일을 정확하게 알고 Control해야 함에도 불구하고, 현실은 그렇지 못하다. 동적쿼리가 이리저리 날라다니는 건 기본, History성 데이터여서 Index를 반드시 타야하는데도 Full Scan 실행계획으로 수행되는 일도 다반사다. 그러다보니, 사용자가 조회 버튼을 누른 후 멍하게 기다리는 것이 싫어 동료들이랑 커피 마시러 가거나, 화면 Loading에만 몇 분이 걸려 그 화면을 아예 안 쓰는 경우도 발생한다.&lt;br /&gt;
&lt;br /&gt;사용자가 프로그램이 죽은 건지 계속 실행되고 있는건지 궁금해하는 상황에서 가독성만 있는 Query가 무슨 소용인가?&amp;nbsp; 그때 필요한 것은 가독성만 있는 Query도 아니고, 프로그램이 죽지 않았다는 걸 알리기 위한 ProgressBar도 아니며 그러한 문제를 해결할 수 있고 빠른 시간에 응답을 줄 수 있는 Query뿐이다.&lt;br /&gt;
&lt;br /&gt;필자도&amp;nbsp;가독성의 중요성을 부인하지 않으며, 일부러 어렵게 짜서 분석하는 사람이 어려워 하는 걸보고 기쁨을 느끼는 변태-_-도 당연히 아니다.&amp;nbsp; 물론 Static하면서 부분범위처리를 하기 위한 기법, 카테시안 Product 등이 섞인 Query를 그런 개념을 모르는 사람이 보면 가독성이 없다고 느낄만 하다고 생각한다.&amp;nbsp; 하지만 그런 부분은 이미 널리 알려진 기법들이며 넉넉잡아 6개월만 노력하면 능숙하게 쓸 수 있는 단계의 SQL일 뿐이다.&amp;nbsp; &lt;br /&gt;
자신이 이해하지 못한다고 해서 가독성이 없다고 단정지어서야 되겠는가?&lt;br /&gt;
&lt;br /&gt;필자는 그 사실에 분개했다.&lt;br /&gt;
&lt;br /&gt;그런데, 이런 가독성에 대한 논란들은 SQL에 대한 부분뿐만 아니라, 다른 곳에서도 자주 볼 수 있었다.&amp;nbsp; &lt;br /&gt;
예를 들자면 Design Pattern 혹은 Interface을 사용한 Program이 분석하기 복잡하니 Dialog 하나 및 Class 한두개에 모든 Logic을 넣기를 바란다거나.&amp;nbsp; 아니면 회사에 있는 C++ Template 혹은 STL을 모르는 개발자의 가독성을 위해 나머지 개발자들이 검증된 STL을 포기하라는 요구를 받는다거나. (필자의 경험으로 볼때 그 이야기를 하는 사람은 STL이 C++ 표준이라는 걸 모르거나 한 번도 사용해본 적이 없다는 데에 내 한달치 술값을 걸겠다.)&lt;br /&gt;
&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;&lt;br /&gt;
&lt;br /&gt;왜 이런 논란이 발생하는 것일까.&lt;/SPAN&gt;&lt;br /&gt;
&lt;/STRONG&gt;가독성이라는 표현이 굉장히 애매모호한 표현이기 때문이며, &quot;리더쉽&quot;처럼 뭔가 언듯 들으면 좋은 말처럼 들리기 때문이다. &lt;br /&gt;
사장의 리더쉽과 말단 직원의 리더쉽이 같을 수 없듯이 가독성이라는 표현도 대상이 누구냐에 따라 다르게 표현된다. &lt;br /&gt;
따라서, 가독성을 이야기할 때는 어떤 대상를 기준으로 할지가 정의되어야 한다. 즉, 신입사원도 다 이해할 수 있는 Code를 말하는 것인지 아니면 사내 Coding 표준이나 SQL 작성 Guide에 맞는 것을 가독성이 있다고 할 것인지를 정해야 한다.&lt;br /&gt;
그런데도 몇몇 사람들은 그 애매모호함을 이용하여 악의적인 발언을 서슴치 않는다.&lt;br /&gt;
또한, 성능이나 유연성 혹은 검증된 방식이라는 이야기는 모두 뺀 채로 가독성!! 이라는 한가지만 물고 늘어진다.&lt;br /&gt;
(물론 본인이 모르는 개념이라는 걸 인정하기&amp;nbsp;싫다거나&amp;nbsp;새로운 걸 배우고 싶지 않다거나 하는 이야기도 하지 않는다.)&lt;br /&gt;
&lt;br /&gt;이런 상황이 문제가 되는 또다른 이유는 결정권자들이 그런 뻔한 음해성 거짓말을 믿는 경우가 생기기 때문이다.&amp;nbsp; &lt;br /&gt;
결정권자들은 그런 세부사항에 대해 잘 모르며, 그들도 그런 Code 혹은 Query는 본 적이 없을 수도 있다.&amp;nbsp; 또,&amp;nbsp;이런 현상은 어려운 Code를 짰다고 지목당한 사람과 다른 사람들의 기술적인 수준의 편차가 심할 수록 자주 나타나는데, 그런 상황에 처한 회사는 추후 이 사람이 다른 프로젝트로 이동하거나 퇴사했을 때도 누군가가 수정할 수 있는 코드를 원하는 것이 당연하다.&lt;br /&gt;
&lt;br /&gt;&lt;br /&gt;
어쨋든 서로가 서로를 이해하기 힘든 상황이라는 것은 분명하다.&amp;nbsp; &lt;br /&gt;
필자는 그런 일을 겪고 업무에 대한 정열이 사그라들었으며, 그 사람의 말만 믿고 나를 &#039;나름 똑똑하긴 하지만 데리고 일하기는 힘든&#039; 직원으로 보는 경영진의 판단에 변명할 의욕마저 없어졌다. 필자가 회사에 있던 기간 동안 어느 누구보다도 많은 사내 교육과 Seminar를 진행했으며 알고 있는 내용을 나누고자 했던만큼, 그만큼 더 서운했다.&lt;br /&gt;
&lt;br /&gt;회사를 떠난 후&amp;nbsp;전해들은 소식에 의하면 지금은 하나의 SQL로 처리할 문제를 몇개~몇십개의 SQL로 알아보기 쉽게 나누고 SQL로 해결안되는 부분은 프로그램으로 어떻게든 짜지만 어떻게 실행되는지는 아직도 아무도 모르고 있다고 하며, STL을 사용한 Code들도 SQL 가독성 문제를 제기한 분의 문제제기로 결국은 다 새로 짜고 있다고 한다.&lt;br /&gt;
(회사를 나온 것은 그 일 때문은 아니다. 물론 전혀 관련이 없진 않았겠지만.)&lt;br /&gt;
&lt;br /&gt;&lt;br /&gt;
이제 아무도 새로운 것을 배우지 않아도 되며 누구든 Code를 고칠 수 있다. 모두 행복해졌다.&lt;br /&gt;
&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;&lt;br /&gt;
&lt;br /&gt;&lt;br /&gt;
이런 일을 겪고 있다면&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;br /&gt;
그런 사내 분위기에 시달리고 있는 사람이 있다면 한가지 충고를 해주고 싶다.&amp;nbsp; 본인이 옳다고 생각하는 길을 버리지 말고 계속 실력을 쌓아라.&amp;nbsp; 언젠가 여러분의 실력을 인정해주는 상사 혹은 회사를 반드시 만나게 될 것이다.&lt;br /&gt;
&lt;br /&gt;물론 막연히 기다리기만 한다고 해서 그런 환경이 오지는 않는다.&amp;nbsp; 본인이 가진 걸 주변 사람들에게 나누고, 회사가 안심하고 그 방법을 선택할 수 있도록 여건을 만들어야 한다.&lt;br /&gt;
먼저 주변의 준비 안된 사람들을 위해 사내교육이나 세미나를 시작하라. 본인의 수준까지 한번에 올라오기를 기다리지 말고 SQL이라면 Parameter Binding의 잇점부터, STL의 문제라면 Template에 대한 이해를 도와라. 말이 쉽지 생각보다 지루한 기간일 것이다. &lt;br /&gt;
그리고, 여러분의 실력과 당당함에 꿀려 발악하는 그 가여운-_- 사람은 그러려니 하고 좀 토닥여주라.&amp;nbsp; 속으로는 &#039;저런 멍청한 놈이 있나&#039; 싶겠지만, 그 사람이 멍청하다는 것을 증명해봐야 달라지는 것은 아무것도 없다.&lt;br /&gt;
&lt;STRONG&gt;&lt;SPAN style=&quot;FONT-SIZE: 10pt&quot;&gt;&lt;br /&gt;
&lt;br /&gt;이런 사람을 고용하고 있다면&lt;/SPAN&gt;&lt;br /&gt;
&lt;/STRONG&gt;회사의 입장에서는 조금 불안할 수도 있을 것이다. 하지만 위에 나온 상황과 같은 실력의 하향평준화가 정말 회사가 원하는 상황인가를 한번 생각해보라.&amp;nbsp; 이 기회를 전체 직원들의 수준을 올릴 수 있는 기회로 삼는 것은 어떨까?&amp;nbsp; 그리고, 당장 결과가 나오지 않더라도 좀 더 기다려주라.&amp;nbsp; 사람들의 실력향상은 기본실력과 재능에 따라 사람마다 편차가 있으며 몇 주 안에는 쉽게 오르지 않는다.&lt;/P&gt;
&lt;P&gt;&lt;br /&gt;
이 포스트는 새로운 개념이나 방법론의 도입을 무조건적으로 찬양하기 위해서 쓴 글은 아니며, 또 회사에 없던 개념을 도입하는 것이 꼭 올바른 정의의 편이라는 것을 의미하는 것은 아니다. 다만,&amp;nbsp;자기개발을 꾸준히 하는 사람이 회사내의 여론몰이에 휘말려 오히려 역적이 되는 상황이 안타까웠을 뿐이다.&lt;br /&gt;
&lt;br /&gt;직원들 비싼 돈 들여가며 사외교육을 보내고 있는 회사라면 지금이라도 주위를 둘러보라.&lt;br /&gt;
의외로 파랑새는 옆에 있을 수도 있다.&lt;br /&gt;
&lt;br /&gt;&lt;/P&gt;&lt;div class=&quot;blogger-news-widget&quot; style=&quot;width: 100%; text-align: center&quot;&gt;
		  					&lt;embed src=&quot;http://api.v.daum.net/static/recombox1.swf&quot; quality=&quot;high&quot; flashvars=&quot;nid=2459322&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;false&quot; bgcolor=&quot;#ffffff&quot; width=&quot;400&quot; height=&quot;80&quot; type=&quot;application/x-shockwave-flash&quot; wmode=&quot;transparent&quot;&gt;&lt;/embed&gt;
						&lt;/div&gt;</description>
			<category>IT/직장</category>
			<category>CODE</category>
			<category>가독성</category>
			<author>막장개발자</author>
			<guid>http://rtti.tistory.com/1</guid>
			<comments>http://rtti.tistory.com/entry/Code%EC%9D%98-%EA%B0%80%EB%8F%85%EC%84%B1%EC%97%90-%EB%8C%80%ED%95%9C-%EC%A7%84%EC%8B%A4#entry1comment</comments>
			<pubDate>Tue, 06 Jan 2009 22:28:17 +0900</pubDate>
		</item>
	</channel>
</rss>

