컴퓨터활용 - 엑세스

아현·2021년 7월 19일
0

Algorithm

목록 보기
230/400
post-custom-banner

1. DB구축



필수





유효성 검사 규칙


  • 유효성 검사

    • 입력 글자 전체를 가지고 입력여부를 판단

      • 500 이상의 자료만 입력 받아라


입력 마스크


  • 입력 마스크

    • 입력할 글자 하나하나를 제어

      • 00LL: 숫자 2개, 문자 2개
    • 입력 자료의 형식이나 범위를 지정

      • 한글 몇글자, 숫자 몇글자, 대소문자 여부
    • 입력형식; 문자 저장 여부; 기본값







형식


  • 형식

    • 입력한 자료를 표현하는 방법

      • 1-51월 5일로 표현

      • 1212개로 표현




관계






엑셀파일 엑세스에 가져오기







입력 및 수정


폼 필드 바운드


  • 디자인 모드


    • F4 혹은 오른쪽 버튼 후 속성 버튼



폼 레코드 삭제 설정





폼 탐색단추, 구분선 표시 설정




폼 바닥글





  • 폼의 머리글과 바닥글은 집계가 가능하다.

    • 참고로 데이터가 나오는 곳은 불가능!



연속폼 설정




하위 폼


  • 드래그해서 칸 지정





드래그로 하위폼 만들기





폼에 조건부 서식 넣기





조회 및 출력


보고서


  • 보고서 바닥글은 사용되지 않으니 아래 범위 드래그해서 없애기

  • 보고서 머리글을 추가할 때는 레이블 드래그해서 집어 넣기



보고서 정렬





바운드




AVG()


  • 소수 자릿수를 1로 표시하는 것과 형식을 0.0으로 두는 것은 동일하다.



FORMAT(), NOW()




이벤트 프로시저 ①





Filter, FilterOn 속성


- 문자열일때 : `Me.filter = "필드명 ='" & 컨트롤명 & "'"`
  • 큰 따옴표 안에 문자열이 들어갈 때, 다시 큰 따옴표를 사용하지 않고 작은 따옴표를 사용한다.

  • But, 컨트롤 이름은 따옴표 안에서는 인식이 되지 않기에, &로 작은 따옴표를 포함하여 연결해 준다.

  • 숫자일 때 : Me.filter = "필드명 =" & 컨트롤명

  • 날짜일 때 : Me.filter = "필드명 = #" & 컨트롤명 & "#"

  • 문자열 일부 : Me.filter = "필드명 like '*" & 컨트롤명 & "*'"

-Me는 현재 폼에 대한 지정자




위의 문제가 매크로 작성으로 나왔을 때


<폼의 값 가져오기>

  • 현재 폼: [컨트롤명]

  • 외부 폼: [FORMS]![폼이름]![컨트롤명]

  • 하위 폼: [폼이름].FORM![컨트롤명]




이벤트 프로시저 ②


<폼, 보고서 출력>

  • 보고서 열기

    • Docmd.OpenReport "보고서이름",acViewPreview,,조건

      • acViewPreview : 생략불가

      • ,, : 출력내용을 제한하는 필터이름(늘생략)

      • 조건 : "필드명 = '" & 컨트럴명 & "'"

  • 폼 열기

    • Docmd.OpenForm "폼이름",Acnormal,,조건

      • Acnormal : 생략가능

      • 조건 : "필드명 = '" & 컨트럴명 & "'"



위에 문제 매크로로 풀이




처리


쿼리 (질의)




  • 엑셀의 고급필터처럼 같은 줄에 주면 and, 다른 줄에 주면 or

    • 이 방법도 동일

  • 소수 둘째자리까지 나오도록


    • 소수 자릿수를 주기 전에 형식을 고정이나 표준으로 무조건 변경해야 적용가능



크로스탭 질의 (쿼리 마법사)


  • 엑셀에서의 피벗테이블과 동일한 개념


  • 합계 금액 지워주기




  • A로 시작하는 자료들에 대해서만 요약



크로스탭 질의 (쿼리 디자인 - 수동)






불일치 검색 쿼리


  • 보통 기본 키를 기준으로 포함, 불포함을 확인하면 된다.





  • 양쪽에서 가진 필드만 비교 기준으로 둘 수 있다.





2. DB구축


유효성 검사 규칙


🛑 큰 따옴표가 필드명에 자동 추가 되면 잘못 인식된 것이기 때문에, [](대괄호)로 변경해준다.



색인(중복가능) 설정



입력 마스크




필수


  • 인덱스가 설정되어 있어도 반드시 데이터를 입력해야 한다.



필드 추가




관계


  • 키가 한 개인 곳이 1이 되고, 키가 여러개 인 곳은 키가 없는 것에 가까워 다(∞)를 가지게 된다.

  • 하지만, 두개의 필드를 연결할 때, 두개 다 키나 인덱스 설정이 되어 있지 않다면 참조 무결성을 사용할 수 없다.

  • 그러므로 <부서> 테이블에 기본키를 먼저 설정해야 한다.

    • 만약 고유 인덱스(기본키)라는 문구가 없으면 그냥 인덱스에서 중복불가를 체크래줘도 된다!






텍스트 파일 가져와서 테이블 추가하기








입력 및 수정


컨트로 간격



데이터 함수 (DCOUNT, DLOOKUP, DSUM, DAVG, DMAX, DMIN)


  • =함수명("계산할 필드", "테이블(쿼리)","조건)

    • DCOUNT: 조건에 맞는 자료의 개수

    • DLOOKUP: 조건에 맞는 자료의 특정 필드값 추출

    • DSUM: 조건에 맞는 자료의 합

    • DAVG: 조건에 맞는 자료의 평균

    • DMAX: 조건에 맞는 자료의 최댓값

    • DMIN: 조건에 맞는 자료의 최솟값



  • 데이터 함수는 문자열을 포함하여도 값을 비교하는 데 어려움이 없으나, 일반 함수의 경우 txt사번에는 A라는 문자를 포함하고 있기 때문에 '', &를 이용하여 묶어주어야 한다.



글자 붙여서 출력


  • 수를 구할 때는 아무 필드나 선택해도 되지만, 비어있는 필드를 서택하면 올바른 데이터가 나오지 않을 수도 있다.

    • 그러므로, 또 다른 옵션은 =Count(*)를 사용하는 것이다.

  • '건' 붙이기

    • 형식 필드 이용하기

      • 하지만 여기서는 숫자 형식이 되기 때문에 자동으로 오른쪽 정렬이 되기 때문에 정렬을 수정해야함

      • 문자열은 왼쪽 정렬
      • 숫자는 오른쪽 정렬



    날짜 형식 지정




    SWITCH()


  • 각 조건에 따른 값 배정

  • SWITCH(조건1, 값1, 조건2, 값2 ...)

    • 조건1에 맞으면 값1이 출력되고, 조건2에 맞으면 값2가 출력



    =switch(직무역량>=80,100000, 직무역량>=50, 50000, 직무역량<50, 0)



하위 폼


  • 디자인 모드에서 하위폼으로 쓸 폼을 드래그 한다.


  • 레이블 삭제



조건부 서식


  • 필드 하나만은 '필드 값이' 선택

  • 행 전체는 '식이'를 선택

  • 커서가 있는 곳에 서식 지정은 '필드에 포커스가 있음' 선택



조회 및 출력


보고서 페이지 머리글 설정


  • 페이지 머리글 영역 늘리고, 원래 있던 것들 밑으로 내리기

  • 레이블 추가



보고서 정렬





중복 데이터 표시 설정





그룹 바닥글에 글자 붙여서 출력


🟡 참고로 페이지 바닥글에는 집계함수를 사용할 수 없다.




페이지 바닥글에 페이지 번호 나오도록


  • 현재 페이지 번호: [page]

  • 전체 페이지 번호: [pages]

🛑 인쇄 미리보기를 클릭해야만 페이지 번호를 볼 수 있다.



<형식으로 지정하기>


<Format함수>

=Format([Page],"000페이지")



이벤트 프로시저①




위의 문제를 매크로로 구현할 시 (ApplyFilter)

이벤트 프로시저②




위의 문제를 매크로로 구현할 시 (OpenReport)



처리기능 구현


쿼리 작성


WEEKDAY(), CHOOSE()


<WEEKDAY()>

  • 특정 날짜값의 요일을 출력

  • =WEEKDAY(날짜, 형식)

  • 형식 구분

    • 1: 일(1), 월, 화, 수, 목, 금, 토

    • 2: 월(1), 화, 수, 목, 금, 토, 일

    • 3: 월(0), 화, 수, 목, 금, 토, 일


<CHOOSE()>

  • 주어진 번호에 맞는 값 출력

  • CHOOSE(번호, 1일때, 2일때 ... )

  • Expr1: Choose(Weekday([입사일],2),"월요일","화요일","수요일","목요일","금요일","토요일","일요일")



요약 쿼리

  • 직무 역량, 행동 역량의 요약은 평균으로 설정해주기



쿼리 필드 소수점 자리 지정

  • 선택하고, F4번 누르기
  • 형식으로만 지정하기

  • 소수 자릿수 이용하기



쿼리 필드 정렬하기


  • 속성에서 정렬을 설정하면 가 나 다... 순으로 정렬되기 때문에 정확하지 않음

    • 우리가 원하는건 월요일, 화요일...



    매개변수 쿼리

  • 사용자가 입력한 매개변수를 통해서 거기에 해당하는 정보만 보여주는 것이 매개변수 쿼리이다.



  • 기본적인 제작 순서는 일반 쿼리와 동일하다.

    🛑 매개 변수 쿼리를 만드는 유일한 차이점

  • 위와 같이 조건에 []안에 질의를 넣어주면 알림창이 뜬다.



    추가 쿼리 (테이블 내용 추가)


  • 기본적인 제작 순서는 일반 쿼리와 동일하다.

    • 쿼리 유형을 변경해주어야 한다.


  • 필드는 전부 다 포함해야 한다.



IN, NOT IN (중복 체크)


**<IN>** ![](https://velog.velcdn.com/images%2Fcorone_hi%2Fpost%2F9d70c8e2-0dfc-447f-b265-fedd89c5aece%2Fimage.png) ![](https://velog.velcdn.com/images%2Fcorone_hi%2Fpost%2F2001dacd-9e10-4d6f-a5aa-b9ec850eb4c5%2Fimage.png)

<NOT IN>

  • SQL문으로 추가된명단 테이블을 선택해서 같은 데이터가 있는지를 검사해서 중복되지 않은 데이터만 표시되도록



🛑 추가쿼리는 실제로 실행 버튼을 눌려서 데이터를 추가시켜 주어야한다.



3. DB구축


기본키 설정


  • 엑세스에서는 다대다 관계 설정이 불가능하기 때문에, 중간에 징검다리 역할의 테이블을 둔다.

    • 이런 경우에는 외부키들을 합쳐서 기본키를 구성한다.



유효성 검사 규칙, BETWEEN


<기본>


<BETWEEN 사용>

  • Between 값1 and 값2



입력 마스크




IME 모드


  • 컴퓨터 내부적으로 영숫자 전자는 2byte로 반자는 1byte로 처리된다.



데이터 형식


  • 255자까지는 짧은 텍스트, 그 이외는 긴 텍스트



중복 데이터 검색 쿼리






외부데이터 가져오기


  • 연결테이블로 불러오면, 엑셀에서 데이터가 변경되면 엑세스에서도 변경된 상태가 반영된다.





입력 및 수정


레코드 원본 설정





탭 순서 설정





컨트롤 설정, Dcount




컨트롤 팁 텍스트




하위폼의 폼 바닥글



  • 판매금액 필드에는 값이 들어있는 것이 아닌 참조하여 계산한 내용이 있기에 이를 그대로 활용해야 한다.

    • 즉 판매금액 필드를 불러올 수 없기에 식을 적어줘야 한다.



매크로 구현




위의 문제 프로시저로 구현할 시


  • Docmd.gotorecord 개체타입, "개체명", 이동할 위치

    • 레코드 위치 이동



폼 종료, Msgbox, Time


  • if 함수는 매크로에서 실행되지 않기 때문에 프로시저로 작성



조회 및 출력


보고서 제목, 머리글 높이 설정




그룹화, 그룹 바닥글





일련번호


  • 컨트롤 원본에 일단 =1을 무조건 적어야 한다.



파선 추가하기


  • 직선을 그으려면 shift 누르고 다 그은 다음에 놓을 것



텍스트 상자 제작, FORMAT


  • 여기서는 레이블 상자가 필요 없기 때문에 삭제시킨다.

<형식란 사용>


<FORMAT 함수 사용>



<& 사용>



이벤트 프로시저 ①




위의 문제 매크로로 구현 (ApplyFilter)



이벤트 프로시저 ②


  • 날짜에서 어떤 값을 추출하면 그것은 숫자형이 된다.



위의 문제 매크로로 구현 (OpenReport)



처리 기능 구현


쿼리 작성, IIF


  • 만약 그렇지 않은 경우가 명시되어 있지 않다면 거짓부분을 비워둘 수 있음

상위 몇개만을 출력하기



🛑🛑🛑 입력을 완료하고 인쇄미리보기나, 데이터 시트보기하면 매개변수 입력하라고 나오는건 오타가 있다는 의미이다!



크로스탭 쿼리


  • 참조 테이블이 3개 이상이면 마법사를 사용하는 것보다 수동으로하는 것이 좋다.

  • 원본에서 일정 조건에 대해 추출을 하고, 집계함수를 사용할 때에는 추출 시에 임의의 필드를 만들어야 한다.

  • 정수 부분만 표시

    • #을 넣어주어도 괜찮다.

    • 소수 자릿수를 이용하는 방법



갱신 쿼리






4. DB구축


입력 마스크




필수




필드 추가




유효성 검사 규칙


  • In으로 하는 방법



데이터 형식




관계 설정


  • 둘의 데이터 형식이 다르므로 맞춰줘야한다. 하지만 교수현황 테이블의 교수번호는 일년번호지만 학과 코드별 교수 테이블의 교수번호는 짧은 텍스트 형식으로 되어있다.

    • 이를 일련번호 형식으로 바꾸면 데이터가 유실될 수 있으니, 원래 데이터가 있는 상태에서는 숫자 형식을 지정해 준다.





조회 속성


  • 쿼리를 작성하면, 자동적으로 SQL문으로 입력된다.

  • 바운드열: 어떤 열을 컴퓨터에 저장할 것이냐 (문제에서 '필드에는 제품코드가 저장되도록 설정할 것)

    • 여기서 1은 제품코드, 2는 제품명


  • 열 개수는 문제에서 잘 언급해주지 않기 때문에 그림을 보고 변경해주어야함



입력 및 수정


레코드 원본 설계




레코드 추가 금지 , 포커스 이동 금지, 데이터 수정 금지







DLookup




폼 머릿글




폼 정렬


  • 오름차순: 점수 asc or 점수(기본값)

<오른쪽 버튼으로 정렬하기>



이벤트 프로시저 ①




이벤트 프로시저 ②




조회 및 출력


그룹 바닥글


  • 정렬 이외의 다른 것들을 포함하려면 그룹 추가!



본문 선 추가




형식




날짜 형식


  • Format 함수 사용 시



페이지 바닥글 쪽수




이벤트 프로시저 ①







위의 문제 매크로로 구현


  • 매크로에서는 전체를 큰따옴표로 감싸지 않아도 되기 때문에 필요한 *부분만 ""로 감싸주고, &로 연결한다.




이벤트 프로시저 ②




위의 문제 매크로로 구현



처리 기능 구현


쿼리 작성


DATEADD


  • 임의의 날짜/시간에 값을 더함

  • DATEADD("형식", 더할값, 입력일)

    • 년: YYYY

    • 월: M

    • 일: D

    • 일(일년기준): Y

    • 요일: W

    • 주(일년기준): WW




DATEDIFF


  • 두 날짜 사이의 차이값

  • DATEDIFF("형식", 시작일, 나중일)

    • 년: YYYY

    • 월: M

    • 일: D

    • 일(일년기준): Y

    • 요일: W

    • 주(일년기준): WW


  • 엑세스에서는 date() 형식으로 사용하고, 프로시저에서는 ()를 붙이지 않는다.





매개변수 쿼리, INSTR


  • INSTR

    • 특정 문자열이 몇 번째에 있는지 조사

    • INSTR(필드명, "찾는 문자열")

    • 공백 찾을 때: instr(사무실주소, " ")


사무실위치: IIf(InStr([사무실주소]," ")=0,[사무실주소],Left([사무실주소],InStr([사무실주소]," ")-1))



이벤트 프로시저




5. DB구축


입력 마스크




데이터 형식, 유효성 검사 규칙




조회속성(목록 상자)




정렬


  • 테이블 전체에 대한 정렬



유효성 검사 규칙


  • 여러 필드에 대해 유효성 검사 규칙을 걸 때에는 테이블 전체 속성



조회속성(목록 상자)


  • 숨겨진 열도 열 개수에 포함된다.

  • 위의 SELECT문에 지정된 순서대로 열 너비를 주면 된다.



공백 들어간 자료 검색 (널값 검색 쿼리)


  • 값을 넣을 때는 NULL, 질의 할 때는 Is Null



입력 및 수정


폼 머리글


  • 바닥글은 안쓰이니까 당겨서 줄여주기



하위 폼



컨트롤 이동


  • shift를 누르고, 레이블과 컨트롤을 같이 이동시키는 것이 좋다.

  • 탭 설정으로 설정하기 (속성 시트 설정)

    • 인덱스 조정으로도 바꿀 수 있다.

  • 프로시저로 커서 지정하기



컨트롤 원본, 형식 지정




레코드 원본 지정 프로시저


  • 이것도 가능



이벤트 프로시저 ①, Orderby



  • Orderby

    • 정렬 메소드

    • Me.OrderBy = "필드명 정렬방식"

    • Me.OrderByOn = True

    • 오름차순: asc(기본값), 내림차순: desc




이벤트 프로시저 ②




조회 및 출력


정렬




DLookup




빈공간에 특수문자 반복 (형식)


  • @는 문자 표시 영역



조건부 서식, INSTR


  • 와일드 키 사용 불가

    • 조건부서식과 외부 폼의 경우에는 임의적으로 필드명에 []를 붙여줘야 한다.



페이지 바닥글


![](https://velog.velcdn.com/images%2Fcorone_hi%2Fpost%2F01ed5034-3d97-49af-9131-52bb8f16426a%2Fimage.png)



이벤트 프로시저 ①





이름이 있는 매크로 만들기




위의 문제 프로시저로 만들기



처리 기능 구현


요약 쿼리




크로스탭 쿼리








  • 2월, 7월, 9월만 나오도록 하기

    • 열 머리글 삭제

    • 조건 주기



GotFocus, MsgBox





삭제 쿼리




6. DB구축


입력 마스크




유효성 검사 규칙




기본값




캡션




유효성 검사 규칙




추가 쿼리






기본키, 업데이트 쿼리





입력 및 수정


연속 폼, 컨트롤 원본




  • 대문자: UCASE, 소문자: LCASE

    • 참고로 엑셀에서는 UPPER, LOWER



정렬




필드 바운드




종료 매크로





위의 문제 프로시저로 작성하기



콤보 상자, 중복 제거 쿼리


  • 처리 후, SQL문이 들어있는 것을 볼 수 있다.



이벤트 프로시저 ①



  • Gotorecord

    • 레코드 위치 이동

    • Docmd.gotorecord 개체타입, "개체명", 이동할 위치




위의 문제 매크로로 구현



이벤트 프로시저 ②





🛑 여기서는 필드명, 컨트롤명 둘 다 가능하다.

🛑 하지만, 요약글 같은 곳은 무조건 필드명으로 해야한다.

  • 마치 this



단추 마법사







조회 및 출력


인쇄 설정




정렬




컨트롤 원본




바운드





컨트롤 이동





이벤트 프로시저, RecordSetClone, FindFirst


  • RecordSetClone

    • 현재 폼의 레코드를 복사해 조건에 맞는 첫번째 자료를 찾는다.

    • Me.RecordSetClone.FindFirst "조건"

  • FindFirst

    • 현재 폼의 북마크에 찾아놓은 복사레코드의 북마크를 대입한다.

    • Me.Bookmark = Me.RecordsetClone.Bookmark




매크로 구현






위의 문제 이벤트 프로시저로 작성

  • 여기서의 최종 합격은 필드나 컨트롤 명이 아니라 그냥 문자이기 때문에 &로 연결할 필요는 없다.



이벤트 프로시저





위의 문제 매크로로 구현



처리 기능 구현


  • 프로그램 테이블이 주가 된다.

    • 즉, 문화센터등록에 값이 없는 것도 출력한다.



매개변수 쿼리, 테이블 만들기 쿼리








이벤트 프로시저 ①


  • mid()는 필드의 8번째에서 1개를 추출하는 의미로 사용됨

  • 큰 따옴표 안에는 또 큰따옴표를 못 사용하기에 작은 따옴표로 변경해준다.



이벤트 프로시저 ②




7. DB 구축


유효성 검사 규칙, INSTR




인덱스의 고유




입력 마스크




데이터 형식, 필드 크기


  • 여기서는 255까지 입력 가능하지만, 바이트로 지정하는 것이 최선



입력 마스크




관계, 삭제 쿼리




콤보 상자




입력 및 수정


하위 폼



  • 하위폼 / 하위 보고서 같은 것이 아니라 하위 폼의 자체 폼 속성으로 들어가야하기에, 하위 폼의 빈 공간을 한번 더 클릭해 준다.



이벤트 프로시저, VISIBLE


  • 속성으로 설정하는 방법




컨트롤 원본, LCASE




하위/ 외부 폼 개체와 비교


  • 하위폼: [폼이름].FORM![컨트롤명]


  • ... 눌러서 만드는 방법



이벤트 프로시저 ①





DSUM, IIF




이벤트 프로시저 ②, Column


  • 열 개수가 1이어서 그렇지 콤보 상자의 열 목록은 2개인 것을 알 수 있으며, 그 중 하나는 교수 번호임 즉, 0부터 시작한다고 했을 때, 1번째 열은 교수번호

  • Column은 0번부터 시작

    • 참고로 바운드 열은 1번부터 시작



이벤트 프로시저 ③, SetFocus





조회 및 출력


누계


  • 정렬 및 요약에서 자격명을 기준으로 그룹화 되어있는 것을 알 수 있다.



그룹 머리글을 페이지 머리글




IIF


  • 엑세스에서는 거짓인 경우의 변경이 없으면 빈칸으로 두는 것이 더 좋음



날짜 형식



  • format 함수 사용



페이지




이벤트 프로시저 ①


  • 바운드 열로 제품코드가 지정되어있을 때에는 굳이 Column으로 열을 지정하지 않아도 된다.

  • 폼이 로드되었을 때 기본 값 설정





매크로 구현


  • GotoRecord는 행단위 이동, GotoControl은 열단위 이동



이벤트 프로시저




위의 문제 매크로로 구현



처리 기능 구현


쿼리 작성 ①


  • 관계를 지정해야 하는 쿼리에서는 어디에 있는 필드를 가지고 오는 지 중요하다!

  • 여기서 필드 명에 &를 사용해서 kg을 붙여주는 것은 불가능하다.



쿼리 작성 ②




Ado 개체


Dim rs As ADODB.Recordset

// Dim = 선언해라 , As~ = ~의 용도로 사용, recordset = 한 행(레코드)의 자료

// rs를 ADODB의 레코드셋을 저장할 변수로 선언함


Set rs = New ADODB.Recordset

// Set = 준비해라(설정해라)

// 새로운 ADODB의 레코드값이 rs로 저장될 수 있게 설정


rs.CursorLocation = adUseClient

//adUseClient = 사용자(클라이언트) , adUseServer = 컴퓨터(서버) 두가지가 있음

// 계산과정이 있다면 그 과정을 서버에서 할 것인가, 클라이언트에서 할 것인가를 지정

// 컴활시험같은 경우 진짜 DB 서버가 연결되어 있는 것이 아니기 때문에 시험에서는 계산문제의 경우 항상 adUseClient방식 사용 (계산문제가 아니라면 클라이언트이든 서버든 상관 없음)


rs.ActiveConnection = CurrentProject.Connection

// CurrentProject = 현재 데이터베이스

// 현재 데이터베이스를 rs개체에 연결

// 외부에서 들어온 값이 rs개체로 들어옴


rs.Open "select 필드명 from 테이블명 where 조건"

// Open = 개체를 열어줌

// SQL문을 사용하여 가져올 자료의 위치를 지정함

// 해당 명령은 =을 적지 않음! 저장 흐름이 아니기 때문에!


MsgBox 나올 메시지


rs.Close

// open명령과 close명령은 한 세트라고 생각하면 됨

// 변수를 닫음


참고: https://taetoungs-branch.tistory.com/34



이벤트 프로시저, SETFOCUS, TABSTOP


  • 속성을 이용한 방법

profile
For the sake of someone who studies computer science
post-custom-banner

0개의 댓글