선언적 프로그래밍과 명령형 프로그래밍


24

나는 명령형 프로그래밍에 매우 편안함을 느낍니다. 나는 내가 원하는 것이 무엇인지 알아 낸 후에 컴퓨터가 원하는 것을 알고리즘 적으로 표현하는 데 결코 어려움이 없다. 그러나 SQL과 같은 언어에 관해서는 필자의 머리가 명령 프로그래밍에 너무 익숙하기 때문에 종종 붙어 있습니다.

예를 들어, band (bandName, bandCountry), 개최지 (venueName, 개최지 국가), plays (bandName, 개최지 이름) 관계를 가지고 있고 모든 bandCountry에 대해 모든 경기장 국가에 대해 다음과 같은 쿼리를 작성하려고한다고 가정합니다. 그 이름의 장소에서 연주하는 국가.

예 : 모든 국가 (bandCountry)의 밴드가 연주 한 모든 개최 장 이름을 원합니다. 또한 "관계"라는 말은 SQL 테이블을 의미합니다.

내 마음 속으로 나는 즉시 "각 개최지 이름마다 모든 밴드 국가를 반복하고, 각 밴드 국가마다 그 밴드의 목록을 얻습니다. 개최지 이름에서 플레이하는 사람이 없으면 다음 개최지 이름으로 이동하십시오. 그렇지 않으면, 밴드의 끝에서 iteration "attributionName을 좋은 개최지 이름 세트에 추가하십시오."

...하지만 SQL에서는 그런 식으로 말할 수 없으며 실제로 직관적 인 명령 솔루션을 사용하여이를 공식화하는 방법에 대해 실제로 생각해야합니다. 다른 사람 이이 문제가 있었습니까? 이것을 어떻게 극복 했습니까? 패러다임 전환을 알아 냈습니까? 명령형 솔루션을 선언 형 솔루션으로 변환하기 위해 명령형 개념에서 SQL 개념으로 맵을 작성 했습니까? 좋은 책을 읽습니까?

추신 : 나는 위의 쿼리에 대한 해결책을 찾지 않고 그것을 해결했다.


1
이것은 당신이 (나 자신을 포함하여) 많은 약점을 보이기 때문에 좋은 질문입니다.
David Weiser

질문에서 "관계"가 의미하는 바를 정의하는 것이 유용 할 수 있습니다. 관계형 모델 (SQL의 수학)에서 "관계"는 SQL 테이블과 거의 유사합니다. 많은 사람들이 "관계"라는 말을 할 때 "관계"라고 말할 것입니다.
Jason Baker

세트 이론과 이산 수학을 배우십시오.

1
@ Jase21, 나는 개인적으로 둘 다에 익숙하지만 SQL의 사소한 것은 여전히 ​​우스운 느낌입니다. 깨끗한 수학 예제 중 어느 것도 이상한 현실 세계를 다루지 않습니다. 또한 LINQ를 사용할 수 있으므로 SQL에 방해가되지 않습니다. 마지막으로, asker에게 : 시간이 지남에 익숙해 질 것입니다.
Job

답변:


12

선언적으로 작업을 수행하는 데 대한 아이디어는 방법이 아니라 무엇 을 지정해야한다는 것 입니다.

나에게 그것은 당신이 올바른 길을 가고있는 것처럼 들립니다. 문제는 당신이 잘못 생각하는 것이 아닙니다. 너무 멀리 가고 있습니다. 무엇을하려고하는지 보자 :

예를 들어, band (bandName, bandCountry), 개최지 (venueName, 개최지 국가), plays (bandName, 개최지 이름) 관계를 가지고 있고 모든 bandCountry에 대해 모든 경기장 국가에 대해 다음과 같은 쿼리를 작성하려고한다고 가정합니다. 그 이름의 장소에서 연주하는 국가.

지금까지 이것은 훌륭합니다. 그러나 당신은 이것을합니다 :

내 마음 속으로 나는 즉시 "각 개최지 이름마다 모든 밴드 국가를 반복하고, 각 밴드 국가마다 그 밴드의 목록을 얻습니다. 개최지 이름에서 플레이하는 사람이 없으면 다음 개최지 이름으로 이동하십시오. 그렇지 않으면, 밴드의 끝에서 iteration "attributionName을 좋은 개최지 이름 세트에 추가하십시오."

본질적으로, 당신은 불필요한 일을하고 있습니다. 당신은 알고 무엇을 당신이 당신이 정말로 필요로하는 모든 인합니다. 그러나 당신은 계속 해서 그것을 얻는 방법 을 알아 내려고 노력 하십시오.

내가 당신이라면, 나는 다음 습관을 가지려고 노력할 것입니다 :

  1. 원하는 것을 정의하십시오 .
  2. 그것을 얻는 방법 을 정의 하는 것을 의식적으로 막으십시오 .
  3. SQL에서 원하는 것을 나타내는 방법을 알아보십시오.

약간의 시간과 노력이 필요할 수 있지만 일단 선언적 프로그래밍을 실제로 시작하면 매우 유용합니다. 실제로, 나머지 코드에서 선언적 프로그래밍을 사용하는 것을 알게 될 것입니다.

책을 찾고 있다면 SQL과 Relational Theory를 추천 합니다. 실제로 SQL 데이터베이스의 이론을 이해하는 데 도움이됩니다. Date의 권장 사항을 소금 한 알과 함께 섭취하십시오. 그는 매우 좋은 정보를 제공하지만 때때로 약간의 의견을들을 수 있습니다.


무언가를 얻는 방법을 알아내는 것이 잘못된 접근법인지 이해하지 못합니다. 사용하는 언어의 종류는 중요하지 않습니다. 원하는 언어를 지정하는 방법을 알아 내야합니다.
davidk01

9

반복자가 아닌 세트로 생각하십시오. sql 문은 원하는 출력 세트의 속성을 정의합니다 (일명 테이블 / 관계)

모든 밴드에 대해 해당 국가의 밴드가있어 그 밴드가 해당 장소에서 연주됩니다.

이것의 결과는 (당신의 의도를 올바르게 이해했다면!) 그 장소에서 연주되는 밴드가 하나 이상있는 장소 세트가 될 것입니다. PLAYS 관계에는 이미 원하는 정보가 있으므로 중복을 제거하면됩니다.

따라서 SQL에서는 다음과 같습니다.

select 
    distinct venueName
from PLAYS

편집 : 좋아, 원하는 실제 세트는 조금 더 복잡합니다. 데이터베이스에 대한 질문은 다음과 같습니다. 모든 국가 에서 어떤 장소가 밴드를 주최 했습니까?

따라서 원하는 세트의 요소에 대한 멤버십 기준을 목표로 정의한 후 뒤로 작업하여 세트를 채 웁니다. 장소는 모든 국가에서 하나 이상의 밴드에 대한 PLAYS 행이있는 경우 출력 세트의 멤버입니다. 이 정보를 어떻게 얻습니까?

한 가지 방법은 각 장소에 대해 다른 국가를 세어 모든 국가의 수와 비교하는 것입니다. 그러나 우리는 COUNTRY 관계가 없습니다. 잠시 동안 주어진 모델에 대해 생각하면 모든 국가 집합이 올바른 기준이 아님을 알 수 있습니다. 밴드가 하나 이상있는 모든 국가의 집합입니다. 따라서 국가 테이블이 필요하지 않습니다 (정규화 된 모델의 경우에는 하나가 있어야하지만). )

declare @BandCountryCount int
select
    @BandCountryCount = COUNT(distinct bandCountry)
from BAND

각 공연장의 밴드 국가를 셀 수 있습니다

select
    P.venueName, COUNT(distinct B.bandCountry) as VenueBandCountryCount
from PLAYS P
    inner join BAND B on B.bandName = P.bandName

하위 쿼리를 사용하여 둘을 함께 조각 할 수 있습니다.

select
    venueName
from (
    select
        P.venueName, COUNT(distinct B.bandCountry) as VenueBandCountryCount
    from PLAYS P
        inner join BAND B on B.bandName = P.bandName
) X
where X.VenueBandCountryCount = @BandCountryCount

이제는 가능한 가장 예쁜 쿼리는 아니지만 (GROUP BY 및 HAVING은 임시 변수 및 하위 쿼리보다 더 '우아한'솔루션으로 간주 될 수 있음) 우리가 무엇을했는지는 분명하므로 OP의 목적으로 남겨 두겠습니다. .

OP의 목적은 사고 방식을 명령형에서 선언 형으로 전환하는 방법을 배우는 것이 었습니다. 이를 위해 설명 된 명령 솔루션이 무엇을했는지 살펴보십시오.

이름은 모든 밴드 국가를 반복하고 각 밴드 국가마다 밴드 목록을 가져옵니다. 그들 중 아무것도 플레이스 이름에서 플레이하지 않으면 다음 플레이스 이름으로 이동하십시오. 그렇지 않으면, bandCountries 반복이 끝날 때 개최지 세트를 개최지 세트에 추가하십시오

위의 결정 기준은 무엇입니까? 나는 그것이 생각합니다 :

... 아무도 [특정 국가의 밴드 세트]가 개최지 이름에서 연주하지 않는 경우 ...

이것은 실격 기준 입니다. 명령 적 사고 과정은 전체 버킷으로 시작하여 기준에 맞지 않는 것들을 버리고 있습니다. 우리는하고 필터링 된 데이터를.

간단한 것은 괜찮지 만 원하는 결과 집합을 구성하는 데 도움이됩니다. 버킷을 대신 채울 수 있는 해당 자격 기준 은 무엇 입니까?

  • 실격자 : 공연장에서 연주하는 밴드의 밴드가없는 경우, 해당 공연장은 실격 처리됩니다.
  • (부분) 한정자 : bandCountry에서 하나 이상의 밴드가 장소에서 연주하는 경우, 장소가 정상일 수 있습니다. 밴드의 나머지 부분을 계속 확인하십시오
  • (전체) 예선 : 각 밴드에서 하나 이상의 밴드가 한 장소에서 연주하면 해당 장소는 자격이됩니다.

최종 한정자는 카운트를 사용하여 단순화 할 수 있습니다. 밴드가 하나 이상의 밴드가 공연장에서 연주되는 경우 bandCountry는 '만족'됩니다. 장소에 대한 '만족 된'밴드 국가의 수는 장소가 자격을 갖도록 밴드 국가의 수와 같아야합니다.

이제 탐색을 통해 관계를 넘어 추론 할 수 있습니다.

  • VENUE 관계로 시작합니다. [답변에는 필요하지 않지만 관계형 탐색의 개념적 시작점입니다.]
  • 개최 장소에서 PLAYS에 가입
  • bandCount를 얻으려면 bandName에서 BAND에 가입하십시오.
  • 밴드 이름은 신경 쓰지 않습니다. 개최지 이름과 밴드 국가 만 선택하십시오
  • 우리는 여분의 bandCountries에 대해서는 신경 쓰지 않습니다. DISTRICT 또는 GROUP BY를 사용하여 중복 제거
  • 우리는 이름이 아닌 별개의 밴드 카운트에만 관심이 있습니다.
  • 우리는 별개의 bandCountries의 수가 총 bandCountries의 수와 동일한 장소만을 원합니다.

위의 솔루션 (또는 합리적인 팩시밀리)으로 돌아갑니다.

개요

  • 이론을 설정하다
  • 관계형 탐색 경로
  • 포함 대 배타적 기준 (자격과 실격)

실제로는 "모든 국가의 밴드 (bandCountry> = venueCountry)가 참여한 공연장"입니다.
EpsilonVector

@EpsilonVector : 편집 참조
Steven A. Lowe

4

선언적 스타일로 사고하고 프로그래밍하는 방법을 배우는 한 가지 방법은 APL 또는 J와 같은 범용 배열 언어를 배우는 것입니다. SQL은 선언적으로 프로그래밍하는 방법을 배우는 데 가장 좋은 방법은 아닙니다. APL 또는 J에서는 명시적인 반복 또는 반복없이 전체 배열 (벡터, 행렬 또는 더 높은 순위의 배열)에서 작동하는 방법을 배웁니다. 이를 통해 SQL 및 관계형 대수를보다 쉽게 ​​이해할 수 있습니다. 매우 간단한 예로, 값이 100보다 큰 벡터 V에서 항목을 선택하기 위해 APL에서 다음과 같이 씁니다.

(V>100)/V

여기서 V> 100은 V와 동일한 모양의 부울 배열로 평가되며 1은 유지하려는 값을 표시합니다. 그것은 반복이 진행되는 노련한 APLer에게는 일어나지 않으며, 우리는 벡터 V에 마스크를 적용하여 새로운 벡터를 반환합니다. 물론 이것은 개념적으로 SQL where 절 또는 관계형 대수 제한 연산이 수행하는 작업입니다.

나는 당신이 선언적 프로그래밍을 많이하지 않고도 잘 이해할 수 있다고 생각하지 않으며 SQL은 일반적으로 너무 구체적입니다. 루프, if / then / else 구조 및 명령, 절차 및 스칼라 스타일 프로그래밍에 참여하는 모든 장치없이 수행하는 방법을 배우는 많은 범용 코드를 작성해야합니다.

이러한 사고 방식에도 도움이되는 다른 기능적 언어가있을 수 있지만 배열 언어는 SQL에 매우 가깝습니다.


"많이하지 않으면 좋은 그립을 얻지 못한다"는 +1입니다. 아무도 a = a + 1밤새 명령형 프로그래밍을 배우지 못했습니다 . 명령형 프로그래밍을 배우는 데 시간이 걸리는 것처럼 논리, 기능 등의 선언적 스타일을 배우는 데 시간이 걸립니다.
저의 정확한 의견 그냥

1

먼저 두 가지를 모두 배워야합니다. 선호하는 것이있을 수 있지만 다른 쪽이 더 나은 곳에서 일할 때는 싸우지 마십시오. 많은 프로그래머들은 관계형 데이터베이스에서 커서를 사용하고 싶어합니다. 각 레코드를 단계별로 사용하는 데 사용되기 때문에 데이터베이스가 훨씬 좋습니다. 당신은 "이런 식으로하는 방법을 알고 가장 통제력이 있고, blah, blah, blah"라는 사고 방식을 원하지 않습니다.


1

당신은 명령 적으로 생각하는 법을 배운 것처럼 선언적으로 생각하는 법을 배우게됩니다. 연습은 더 간단한 문제로 시작하고 "가져올 때"작업하는 것입니다.

명령형 프로그래밍에 대한 첫 경험에는 " a = a + 1" 와 같은 반 직관적 인 (그리고 실제로는 우스운) 진술이 포함되었습니다 . 당신은 그 진술에 명백한 비진리에서 반동을 기억조차하지 않을 정도로 당신의 마음을 그 주위에 감쌌습니다. 선언적 스타일의 문제점은 명령형 스타일을 처음 시작했을 때의 위치가 "클루리스 (cueless) newb"라는 것입니다. 더 나쁜 것은,이 새로운 스타일과 전혀 상반되는 스타일로 수년간의 연습을 해왔으며, "모든 비용으로 제어하는 ​​습관"과 같이 수년간의 습관을 취소 할 수 있습니다.

선언적 스타일은 직관이 부족한 다른 접근 방식으로 작동합니다 (수년 동안 수학 기술을 매우 예리하게 유지하지 않은 한 대부분의 사람들은 그렇지 않습니다). 한 번에 한 단계 씩 생각하는 방법과 그것을 배우는 유일한 방법을 다시 배워야합니다.

개념을 배우고 싶다면 선언적 프로그래밍의 첫 번째 방법으로 SQL을 선택하는 것은 실수가 될 수 있습니다. 물론 그것이 기반으로 한 튜플 미적분은 실제로 선언적이지만, 불행히도 튜플 미적분의 순도는 구현의 현실에 의해 심하게 손상되었으며 언어는 사실상 약간 혼란스러워졌습니다. 당신은 (같은 의미에서 당신이 사용하고) 다른 더 직접적으로 유용한에서 선언적 언어를 보는 대신 할 수 Lisps (특히. 계획 ), 하스켈MLS의 (주로) 프로그래밍 기능 또는 대안 프롤로그수은 에 대한 (주로) 논리 프로그래밍.

다른 언어를 배우면 몇 가지 이유로 선언적 프로그래밍이 어떻게 작동하는지에 대한 더 나은 통찰력을 얻을 수 있습니다.

  1. "크래들-그레이"프로그래밍에 유용합니다. 처음부터 끝까지이 언어로 전체 프로그램을 작성할 수 있습니다. 대부분의 사람들에게 독립형 언어로 사용하는 SQL과는 달리 SQL과는 달리 독립적으로 유용합니다.

  2. 그들은 각각 당신에게 선언적인 프로그래밍에 대해 다른 경사를 부여하여 최종적으로 "얻는"다른 길을 줄 수 있습니다.

  3. 또한 프로그래밍에 대한 일반적인 생각에 대해 각각 다르게 생각합니다. 직접 직접 사용하지 않아도 문제 및 코딩에 대한 추론 능력이 향상됩니다.

  4. 그들로부터 배운 교훈은 SQL에 대해서도 도움이 될 것입니다. 특히 데이터에 대한 순수한 사고 방식을 위해 관계형 데이터베이스 뒤에있는 튜플 미적분학을 연마하는 경우.

나는 특히 (기능적 언어 중 하나 학습 권하고 싶습니다 Clojure의를 Lisps의 하나로서, 아마 좋은의 여기 선택) 논리 언어 중 하나 (수성 가장 좋아하는 나는,하지만 프롤로그는이 많은 학습을위한 유용한 자료) 최대 사고 과정 확장.


1

SQL과 같은 선언적 설정에서 반드시 생각하는 것은 잘못이 아닙니다. 명령 적 사고는 당신이 묘사 한 것보다 조금 더 높은 수준에서 일어나야한다는 것입니다. SQL을 사용하는 데이터베이스를 쿼리해야 할 때마다 항상 내 자신을 생각합니다.

  • 여기 내가 필요한 조각들이 있습니다.
  • 나는 이런 방식으로 그것들을 하나로 묶을 것입니다.
  • 나는 내가 정말로 찾고있는 것을 얻기 위해 다음 술어로 방금 얻은 것을 내려 놓을 것입니다.

위의 명령은 높은 수준의 명령 알고리즘이며 SQL 설정에서 꽤 잘 작동합니다. 나는 이것이 하향식 접근법으로 간주되고 Steven A. Lowe는 꽤 좋은 상향식 접근법을 설명합니다 .


1

질문의 핵심은 다음 단락에서 말한 내용입니다. "SQL에서는 그렇게 말할 수 없습니다." 이 단계에서는 프로그래밍 언어가 아닌 외국어로 SQL에 접근하는 것이 더 유용 할 수 있습니다. 이런 식으로 생각하면 SQL 쿼리를 작성하면 실제로 원하는 것을 영어로 "SQLish"로 번역 할 수 있습니다. 컴퓨터는 SQL을 완벽하게 이해하고 정확하게 말한대로 처리하므로 올바르게 번역하는 한 구현에 대해 걱정할 필요가 없습니다.

외국어를 배우는 가장 좋은 방법은 무엇입니까? SQL 문서에서 얻을 수있는 문법과 어휘를 반드시 배워야합니다. 가장 중요한 것은 연습입니다. 가능한 한 많은 SQL을 읽고 써야하며 구문을 먼저 알아야 할 필요는 없습니다. 당신은 당신이 따라 가면서 물건을 찾을 수 있습니다. 영어보다 SQL에서 원하는 데이터를 설명하는 것이 더 쉽다는 것을 알게되면 알게 될 것입니다.


1

SQL을 머리로 감싸는 데 오랜 시간이 걸렸습니다. 우리는 대학과 당시에 문제를 복잡하게 만드는 관계 이론을 수행했습니다. 결국, 내 학습 과정은 여러 가지 학습 자료와 예제를 통해 많은 시행 착오를 거쳤으며 그 과정에서 유용하다고 생각했습니다. 본질적으로, 당신은 결국 그것에 익숙해 질 것이고, 데이터와 쿼리에 대한 새로운 사고 방식을 추가하는 것은 당신의 정신 발달에 어떤 가치가있을 것입니다.

각 언어 기능을 사용하는 방법과 알려진 테이블에서 특정 결과를 얻는 방법 (참조 용 테이블 정의 포함)을 보여주는 간단한 스크립트 모음을 점차적으로 구축하여 학습 속도를 높일 수 있음을 알게되었습니다.

올해 초 저는 지저분한 Oracle 데이터베이스에서 데이터 마이그레이션 프로젝트와 관련된 공식적인 교육을 받았습니다. 여기서 라이브러리에서 조각을 점진적으로 조합하여 원하는 결과를 얻을 때까지 다양한 방식으로 쿼리 결과를 필터링 한 다음 다음과 같이 변환했습니다. 필요 등. 일부 쿼리는 매우 복잡해져 디버깅하기가 어려워졌습니다. 나는 지금 그것들을 읽을 수는 없지만 의심의 여지가있는 참조 빌딩 블록을 사용하여 비슷한 해결책에 다시 도달 할 수 있기를 바랍니다.

선언적이고 기능적인 공간에 대한 직관적 인 인식을 높이는 다른 방법은 특정 패러다임에 더 적합한 학습 세트 이론 및 프로그래밍 언어입니다. 나는 현재 수학 능력을 유지하고 향상시키기 위해 하스켈을 배우는 과정에 있습니다.


0

문제가 발생하면 일반적으로 문제를 해결하는 방법을 생각합니다. 그러나 컴퓨터가 어떻게 당신을 위해 그것을 해결하는지 안다면! 그러면 어떻게 제거 될지 에 대한 우려 가 있습니다.

나는 그것이 어떻게 일어나는지 말하려고합니다.

재귀 프로그램에 대해서는 이미 잘 알고있을 것입니다. 재귀 프로그램에서는 문제가 어떻게 해결되는지 말하기보다는 문제 를 정의 합니다. 베이스 를 정의 하고 n-1 에 따라 n정의 합니다 . (예 :) 그러나 컴퓨터 가 어떻게 이를 해결 하는지 이미 알고있을 것입니다. 함수에서 시작하여 기본 정의에 도달 할 때까지 함수를 재귀 적으로 호출 한 다음 기본 값을 기준으로 다른 모든 함수를 평가합니다.factorial(n) = n * factorial(n-1)

선언적 프로그래밍에서 일어나는 일입니다. 기존 정의에 따라 모든 것을 정의합니다. 컴퓨터는 기본 기능을 기반으로 답을 도출하는 방법을 알고 있습니다.

SQL에서는 정의를 서로 관련시키지 않을 수 있지만 객체 나 정보를 서로 관련 시키거나 제공 한 관계에 따라 원하는 것을 지정하고 컴퓨터 검색을 무언가 (오브젝트, 정보)로 지정합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.