드로우홀릭 더베이직

Collection 관련 문의입니다.

2021.11.05 11:37:53 조회 수 219 추천 수 0

안녕하세요. 

 

오늘은 Collection의 사용법에 대해 문의를 드리고자 합니다.

폼에서 특정 버튼을 클릭하면 특정 Table에 있는 한 필드의 모든 값을 Collection으로 집어넣는 방법을 찾고 있습니다. 

적어도 반복문을 통해 테이블의 한 필드를 차례로 collection에 추가하는 방법은 있을 것 같은데.... 

(엑셀에서는 Range함수로 지정하여 추가할 수 있더군요.)

방법을 도저히 찾을 수가 없어서 문의드립니다.. ㅠㅠ

 

참고로 말씀드리자면, 기존에는 일련번호 필드를 활용하여 아래와 같은 형태로 collection에 추가하여서 사용하였습니다. 

다만 이번에는 일련번호를 사용하지 않고 반복문을 만들 수 있는 방법을 찾고 싶습니다...

dim i as integer

dim col as collection

For i = dmin("ID",[_table_]) to dmax("ID",[_table_]) 

     if dcount("ID",[_table_],"ID = i") >0 then

        col.add dlookup([_field_],[_table_],"ID = i")

     end if

next

 

항상 큰 도움을 받고 있습니다. 

감사합니다.


profile

돌직구

2021.11.08 16:41:17
*.38.65.95

질문이 잘 이해가 되지 않습니다.
일련번호를 사용하지 않고 반복문을 만든다? 이것이 무슨 의미입니까?
일련번호는 DB 테이블 상에서 레코드간 식별하기 위한 것입니다.
물론, 반복문을 만들 때 이 식별자를 사용하지 않아도 되기는 하지만..
식별자 없이 가져온 값들이 어떤 역할을 할 수 있을까요?

 

일단 위 코드는 제대로 동작하지 않습니다.
다음과 같이 수정해야 합니다.

    Dim i As Integer
    
    Dim col As Collection
    
    Set col = New Collection
    
    For i = DMin("제품번호", "Data1") To DMax("제품번호", "Data1")
         If DCount("제품번호", "Data1", "제품번호 = " & i) > 0 Then
            col.Add DLookup("제품명", "Data1", "제품번호 = " & i)
         End If
    Next

    For i = DMin("제품번호", "Data1") To DMax("제품번호", "Data1")
        Debug.Print col.Item(i)
    Next
 

제가 수정한 부분은 '굵게' 표시해 두었으니, 어떤 부분이 잘못되었는지 아실 겁니다.

두 번째 For 문은, 이렇게 저장한 컬렉션의 데이터를 표시해 주는 기능입니다.

 

본질적으로, 특정 Table에 있는 한 필드의 모든 값을 collection으로 왜 집어 넣으려 하시나요?
비즈니스 로직 없이, 그냥 기능만 질문하는 분들이 많은데..
대부분 잘못된 방식으로 구현합니다.
이번 경우도 그래 보입니다.
제가 수십 년 액세스로 개발해 보았지만, 한 필드의 모든 값을 collection으로 넣어 본 적이 없습니다.
그럴 필요도 없고요.

비즈니스 로직을 설명해 보십시오.
더 좋은 방법이 나올 것입니다.

지금으로서는 ADO의 Recordset 개체를 이용하는 것이 제일 나아 보이긴 합니다만..
비즈니스 로직을 모르니 덮어놓고 권장할 수도 없네요.

vrn001

2021.11.09 15:58:31
*.101.55.67

답변 감사드립니다.

우선, 말씀주신 대로 일련번호를 통해 테이블 레코드를 식별하게 하여 원하던 기능은 구현하였습니다.

혹시 일련번호를 사용하지 않고 레코드를 식별할 수 있는 방법은 없는지 궁금하였으나 역시 없군요.. ㅠㅠ

 

처음에는 로직을 설명하려 하였으나 너무 장황하여 특정 부분만 문의드렸던 것인데, 오히려 혼란을 드린 것 같아 죄송합니다.

참고로 말씀드리자면, 구현하고자 하였던 기능은 아래와 같았습니다. 

- SQL의 뷰: 두 개의 테이블 값을 바탕으로 계산식을 이용하여 조건을 추출(Dlookup 등을 사용하여 계산)

- 위의 뷰를 하위폼으로 하는 폼을 만들고, 조건절을 이용하여 recordsource를 필터링

- 조건에 해당하는 모든 레코드에 특정 값을 update

서버로 Azure를 사용하고 있는데, 조건문으로 RunSQL을 돌리면 데이터가 조금만 많아도 무척 느려지는 문제가 있더군요..

하여, 해당하는 테이블의 ID를 임시 테이블로 받고, 이 레코드를 Collection으로 지정하여 반복문을 통해 sql 구문을 만들고자 하였습니다..

하지만 사용해보니, collection으로 지정할 수 있는 숫자가 제한되어서 100개 이상의 레코드를 대상으로 하게 되면 사용할 수 없을 것 같네요.

말씀해주신 Recordset 개체를 이용하는 방법을 고민해봐야겠습니다.

 

다시 한번, 답변 감사드립니다. 

profile

돌직구

2021.11.09 16:17:01
*.38.65.95

일단 '일련번호를 사용하지 않고 레코드를 식별할 수 있는 방법' 관련해서는..
일련번호가 중요한 것이 아니고, '기본 키' 같은 '식별자'가 반드시 있어야 한다는 점을 말씀드립니다.
상황에 따라서 일련번호를 사용하지 않는 경우도 많이 있습니다.

그리고 제가 '비즈니스 로직'을 설명 요청드렸고, 그에 따라서 로직을 설명주신듯 한데..
비즈니스 로직은 이런 것이 아닙니다.
액세스 용어 하나도 없어도 설명 가능한 것이 비즈니스 로직입니다.
예를 들자면, 다음과 같은 것이 비즈니스 로직입니다.
'우리 회사가 수행한 주문건이 완료(배송 등)되었을 경우, 주문서 화면에서 '주문완료' 버튼을 클릭하면 '상태'가 '주문완료'로 변한다. 그리고 이 주문건은 더 이상 수정/삭제될 수 없어야 한다'

일단 이것이 먼저이고, 그것을 구현하기 위해서 액세스 용어를 포함한 구현로직이 나오고..
이 구현로직이 맞냐? 혹은 이 구현로직을 어떻게 하는 것이 맞냐?
이런식으로 질문이 되는 것이 좋습니다.

 

어쨌든 'Collection으로 지정할 수 있는 숫자가 제한되어서 100개 이상의 레코드를 대상으로 하게 되면' --> 이것도 좀 이상합니다. 제가 예전에 Collection 개체를 테스트해 봤는데, 3만개도 등록 가능하던데요?

 

어쨌든 좀 더 괜찮은 해결책을 원하시면 일단 '비즈니스 로직'을 먼저 설명해 주세요.
상상하지도 못했던 좋은 답변이 나올 수 있고, 이럴 때 시야가 넓어지는 겁니다. ^^

vrn001

2021.11.09 18:35:05
*.101.55.67

넵. 실제로 일련번호는 사용하지 않고 "기본 키"로써 int를 사용하는 테이블도 있긴 합니다.

다만 SQL 구문 중 "insert into [_table_](필드) select [필드] from [_table2_]"과 같은 구문을 활용할 때 자동으로 식별자를 입력하려면 일련번호 형태가 가장 적합한 것 같더군요.

또, 제가 착각한 부분이 있었네요. Collection에서는 제한이 없으나, Collection에서 string을 받아 or로 연결하여 조건식으로 쓰려니, "조건식이 너무 복잡합니다."라는 오류메시지가 출력되는 것이었습니다.

 

그리고 제가 비즈니스 로직이라는 표현을 완전히 잘못 이해한 것 같습니다.

그렇다면, "여러 직원들이 요청한 구매 목록을 진행상황에 따라 '취소', '구매요청됨', '승인 중', '발주완료', '납품완료' 등으로 구분되어 확인할 수 있고, 이를 일정 조건에 맞춰서 조회한 후, 이를 체크하여 결재를 올릴 수 있다. 이 때, 화면 상 보여지는 모든 레코드를 한번에 선택할 수 있어야 한다. 또, 납품은 나누어서 이뤄질 수도 있으며, 각각의 납품일을 따로 기록해야 한다.(예: 11/01 10개 발주, 11/15 5개 납품, 11/30 5개 납품)"

정도가 될 것 같네요. (구현하려는 폼의 형태는 아래 이미지와 같습니다.)

캡처.png.jpg

현재는 이를 아래와 같은 방법을 통해 구현한 상태입니다. 시야가 좁은 상태에서 구현하려다 보니 굉장히 비효율적인 방법을 사용하고 있는 것 같습니다... 일단 지금은 잘 작동되고 있지만... ㅠㅠ

- [주문ID]를 기본키로 갖는 [주문서] 테이블과 [납품ID를 기본키로 하고, [주문ID]필드(int)를 갖는 [납품서] 테이블을 생성

- 뷰를 통해 주문서 레코드의 상태를 계산식으로 출력할 수 있도록 설정(예: 납품서에 수량합이 주문서의 수량과 같으면 '납품완료'로 출력) 

- 뷰를 하위폼으로 볼 수 있게 해두고 설정하는 조건에 따라 string으로 조건문을 형성하고, 이를 통해 recordsource를 변환하여 조회할 수 있도록 설정

- 테이블에 [체크] 필드를 int로 생성하고, 뷰에는 [체크] = 사용자고유번호(사번) 일 때 -1을 출력하는 필드 [체크상태]를 생성 

- [체크상태] 를 체크박스 형태로 두고, 클릭 시 update 구문을 통해 사번이 입력되도록 설정

- 전체체크를 클릭하는 경우, 현재 recordsource에서 where 구문만 출력하여 "insert into [Temp](ID) select 주문ID from [뷰] where ~"로 서버와 연결되지 않은 별도의 테이블 [Temp]에 ID를 입력

- [Temp]에 있는 모든 ID를 collection에 add한 뒤, for문을 통해 주문ID = col(i) 형태의 string을 or로 연결...

- "update 주문서 set 체크 = 사번 where ~"를 통해 일괄 체크 기능 구현...

- [Temp]테이블의 모든 레코드를 delete

 

>아래는 전체선택을 클릭했을 때의 코드입니다. 혹시 확인이 더 용이하실까 하여 전달드립니다.

Private Sub ckall_Click()
Dim rswh As String
Dim m As Double
Dim n As Double
Dim x As Double
Dim i As Integer
Dim j As Integer
Dim col As Collection
Dim ostr As String

Set col = New Collection

If ckall = 0 Then
DoCmd.RunSQL "update p주문서 set 체크 = null where 체크 = " & [TempVars]![ID]
Me.Requery
Else

    rswh = Form.RecordSource
    DoCmd.RunSQL "insert into [Temp](ID) select [주문ID] from sv주문조회" & Mid(rswh, InStr(rswh, "where") - 1, InStr(rswh, "Order") - InStr(rswh, "where"))

    If DCount("ID", "Temp") > 75 Then
        [TempVars]![str] = "선택하시려는 값이 너무 많습니다!"
        [TempVars]![str2] = "조건을 확인하시고 다시 시도해주세요."
        DoCmd.OpenForm "f경고"
        DoCmd.RunSQL "delete * from [Temp]"

    Else

        m = DMax("FI", "Temp")
        n = DMin("FI", "Temp")
        For x = n To m
            i = DLookup("ID", "Temp", "FI = " & x)
            If Nz(i, "") <> "" Then
                col.Add i
            End If
        Next
        ostr = " Where [주문ID] = null "
        For j = 1 To col.Count
            ostr = ostr & " OR [주문ID] = " & col(j)
        Next
            DoCmd.RunSQL "update p주문서 set 체크 = " & [TempVars]![ID] & ostr
            DoCmd.RunSQL "delete * from [Temp]"
            Me.Form.Requery
    End If
End If
End Sub

 

감사합니다.

첨부
profile

돌직구

2021.11.09 21:17:04
*.13.208.122

어떤 것인지 알겠습니다.
역시 비즈니스로직을 알아야 제대로 설명드릴 수 있습니다. ^^

'뷰' 라는 표현을 쓰시는데, 액세스에는 '뷰'가 없습니다.
혹시 SQL Server 혹은 MySQL 같은 전문 DB를 사용하시는지요?

일단 말씀하신 요구사항대로 하는 것이 액세스의 약점이기도 합니다.
체크박스를 사용하면 '동시성'이 문제가 됩니다.
이를 피하기 위해 '사번'을 이용하셨는데, 완벽한 문제 해결은 아마 안 될 겁니다.
이와 관련된 글은 다음 링크를 참고해 보십시오.
https://www.td21.com/qna/16434

이러한 의미의 체크박스를 액세스에서 사용하려면..
1. 이런 것을 지원하는 컨트롤을 사용합니다: 저희는 Codejock 사에서 개발한 컨트롤을 구입하여 사용하고 있습니다. 제일 저렴한 것은 17만원쯤 하네요: https://codejock.com/purchase/product.asp?c41q7p6VQ=EL
2. 임시 테이블을 이용합니다: 조회 조건에 맞는 데이터를 임시 테이블에 붙여넣고 사용하는 방법입니다.

지금 2번 방법일 이용하신듯 한데..

이런 것을 구현하기 위해서 collection을 사용할 필요는 없습니다.
선택한 것을 위한 또다른 임시테이블을 이용하는 것이 좋습니다. collection을 사용하는 대신, 이 새로운 임시테이블에 선택한 ID값을 넣는 겁니다. 사실상 무제한의 값을 넣을 수 있죠.

그리고, 나중에 선택한 값을 가져올 때 다음과 같은 구문을 사용하면 됩니다.
FieldName IN (SELECT ID FROM 새로운_임시_테이블)

'조건식이 너무 복잡합니다.' 라는 메시지는 이런 식으로 피해갈 수 있습니다.

 

게시판으로 설명하려니 너무 힘들군요. ^^
이 정도 수준이라면 튜터링을 하실 것을 권장합니다.
vrn001 님도 질문하기가 훨씬 쉽고, 저희도 문제 파악하고 답변 드리기가 훨씬 쉽습니다.
물론, 계속 게시판으로 질문하셔도 되고요~

vrn001

2021.11.10 09:47:34
*.101.55.67

넵. Azure와 SQL server를 사용하고 있습니다.

아무래도 여러 PC에서 접속해야 하다보니, 액세스만으로는 어렵더군요. (이 부분은 돌직구님께 튜터링 도움을 받았었습니다. 새삼 감사드립니다.)

그리고, 나중에 선택한 값을 가져올 때 다음과 같은 구문을 사용하면 됩니다.
FieldName IN (SELECT ID FROM 새로운_임시_테이블)

>> 이 부분이 바로 제가 찾고 있던 것입니다!!! 이걸 사용하면 제가 지금 원하는 기능을 충분히 구현할 수 있을 것 같아요! 감사합니다!

 

튜터링은 조만간 다시 도움을 받게 될 것 같긴 합니다... 

지난 번에 튜터링 받았던 내용을 토대로 확장하여 기능을 구현하고 있었는데, 슬슬 한계가 느껴지네요ㅋㅋ.. 

profile

돌직구

2021.11.10 14:13:21
*.13.208.122

아, Azure와 SQL Server를 이용하고 있다고 하셨었죠..

어쨌든 비즈니스 로직을 설명해 주시니, 올바른 구현방법을 설명드릴 수 있었습니다.
저도 기분이 좋네요. ^^

사실, 튜터링을 잘 이용하시는 분들은 다음과 같은 질문을 많이 하십니다.
1. 이러이러한 기능을 구현하려고 하는데 되냐 안되냐?
2. 이러이러한 비즈니스로직이 있는데, 구현 방향에 대해서 말씀해 달라.

튜터링 시간은 매우 짧고, 올바른 방향을 잡아 개발하게 되니 낭비되는 시간이 매우 줄어들죠. ^^

vrn001

2021.11.10 17:48:51
*.101.55.67

그렇군요.

다음에 튜터링 받게 되면 비즈니스로직을 먼저 말씀드리는 방향으로 진행을 해야겠네요.

답변 감사드려요!

List of Articles
번호 제목 글쓴이 날짜 조회 수
공지 FAQ: 어떤 과정을 수강하는 것이 좋을까요? 외 돌직구 2017-08-29 31765
공지 좋은 답변을 이끌어 내는 방법 [1] 돌직구 2017-07-14 27913
공지 액세스 Q/A 게시판 형식을 변경합니다. 돌직구 2014-09-10 23085
459 대화상자에서 매크로동작 2 열심 2022-07-30 1144
458 디자인보기 1 열심 2022-07-29 327
457 개발 컨셉 1 LoneStar 2022-07-29 1193
456 실행버튼 1 열심 2022-07-28 1424
455 다른PC에서는 왜정상작동이 안되는지요? 1 열심 2022-07-27 2334
454 추가쿼리에서 키위반 오류 문의드립니다 file 3 1 박형근 2022-07-17 35971
453 온라인강의(비메오vimeo) 동영상 재생 오류 7 디비32 2022-07-06 815
452 엉뚱한 질문 하나 드립니다... 아놀드 2022-06-14 528
451 액세스 화면색상이 이상해져서 문의드립니다 file 1 박형근 2022-06-05 1765
450 안녕하세요 기본적인 질문입니다. 5 으흐흐 2022-06-03 81
449 엑세스 오류 file 1 엑세스00 2022-05-12 2379
448 테이블에서 일대다 폼으로 레코드를 읽어오기 file 3 원죽 2022-04-05 775
447 날짜간의 시간차이를 "시분초"로 표현하고 싶습니다. file 1 엑세스초보탈출 2022-01-02 3765
446 압축 및 복구에 대한 문의입니다. 3 vrn001 2021-12-23 3184
445 액셀과 엑세스 VBA 차이점 문의 2 겨루기 2021-12-08 15723
444 오프라인 수업 문의 드립니다.~ 2 문건 2021-12-08 583
443 튜터링 범위에 대한 문의입니다. (Azure를 이용한 메일 보내는 기능 관련) 4 vrn001 2021-11-19 234
442 로그인된 유저이름 반환하기 가능할까요?? 2 아놀드 2021-11-08 242
» Collection 관련 문의입니다. 8 vrn001 2021-11-05 219
440 2013 초급동영상 중 질문사항 입니다 file 2 푸리쏠 2021-10-29 294


  주소  12925 경기도 하남시 미사대로 540, B동 917호 (현대지식산업센터 한강미사2차) ㈜팀데이터이십일  |  고객센터 전화번호  02-467-2998  |  대표이사  염기웅
개인정보관리책임자  염기웅 (ml_privacy@td21.com)  |  사업자등록번호  120-86-79260  |  통신판매업신고번호  제 2021-경기하남-1166 호  [사업자 정보 확인]
  TD21의 사전 서면 동의 없이 TD21 사이트 일체의 정보, 콘텐츠 및 UI 등을 상업적 목적으로 전시, 전송, 스크래핑 등 무단 사용할 수 없습니다.