포스팅 목차
23. Display the names of employees who are not working as managers.
* 관리자 역할(mgr 변수 기준)을 수행하지 않는 직원의 이름을 출력하시오.
- 파이썬 & R 패키지 호출 및 예제 데이터 생성 링크
- [데이터 필터링 & 서브쿼리] 서브쿼리 기반의 데이터 필터링
|
1. 오라클(Oracle)
1차적으로 관리자로 근무하는 사원을 선택 후 emp 테이블에서 관리자를 제외한 다른 사원을 추출한다.
Oracle Programming |
select * from emp
minus
(select * from emp where empno in (select mgr from emp));
Oracle Programming |
select * from emp
where empno not in (select mgr from emp where mgr is not null);
Oracle Programming |
select * from emp e
where empno not in (select mgr from emp where e.empno=mgr);
2. 파이썬(Pandas)
isin 함수
isin 함수를 사용하여서 관리자 사원 번호를 선택 후, 물결(tilde) 모양의 NOT 연산자를 사용하여서 관리자를 제외한 다른 사원들의 정보를 추출한다.
Python Programming |
emp[~emp['empno'].isin(emp['mgr']) ]
Results |
empno | ename | job | mgr | hiredate | sal | comm | deptno | |
0 | 7369 | SMITH | CLERK | 7902.0 | 1980/12/17 | 800 | NaN | 20 |
1 | 7499 | ALLEN | SALESMAN | 7698.0 | 1981/02/20 | 1600 | 300.0 | 30 |
2 | 7521 | WARD | SALESMAN | 7698.0 | 1981/02/22 | 1250 | 500.0 | 30 |
4 | 7654 | MARTIN | SALESMAN | 7698.0 | 1981/09/28 | 1250 | 1400.0 | 30 |
9 | 7844 | TURNER | SALESMAN | 7698.0 | 1981/09/08 | 1500 | 0.0 | 30 |
10 | 7876 | ADAMS | CLERK | 7788.0 | 1983/01/12 | 1100 | NaN | 20 |
11 | 7900 | JAMES | CLERK | 7698.0 | 1981/12/03 | 950 | NaN | 30 |
13 | 7934 | MILLER | CLERK | 7782.0 | 1982/01/23 | 1300 | NaN | 10 |
np.isin 함수
Python Programming |
emp[~np.isin(emp['empno'],emp['mgr'])]
Results |
empno | ename | job | mgr | hiredate | sal | comm | deptno | |
0 | 7369 | SMITH | CLERK | 7902.0 | 1980/12/17 | 800 | NaN | 20 |
1 | 7499 | ALLEN | SALESMAN | 7698.0 | 1981/02/20 | 1600 | 300.0 | 30 |
2 | 7521 | WARD | SALESMAN | 7698.0 | 1981/02/22 | 1250 | 500.0 | 30 |
4 | 7654 | MARTIN | SALESMAN | 7698.0 | 1981/09/28 | 1250 | 1400.0 | 30 |
9 | 7844 | TURNER | SALESMAN | 7698.0 | 1981/09/08 | 1500 | 0.0 | 30 |
10 | 7876 | ADAMS | CLERK | 7788.0 | 1983/01/12 | 1100 | NaN | 20 |
11 | 7900 | JAMES | CLERK | 7698.0 | 1981/12/03 | 950 | NaN | 30 |
13 | 7934 | MILLER | CLERK | 7782.0 | 1982/01/23 | 1300 | NaN | 10 |
Python Programming |
emp.loc[(~emp.empno.isin(emp['mgr'])) , ["ename"]]
Results |
ename | |
0 | SMITH |
1 | ALLEN |
2 | WARD |
4 | MARTIN |
9 | TURNER |
10 | ADAMS |
11 | JAMES |
13 | MILLER |
사원번호(empno)에서 해당 사원의 상위 관리자(mgr)의 사번을 제외한 사원들의 정보를 추출한다.
Python Programming |
emp.query('empno not in mgr', engine='python')[['ename']]
Results |
empno | ename | job | mgr | hiredate | sal | comm | deptno | |
0 | 7369 | SMITH | CLERK | 7902.0 | 1980/12/17 | 800 | NaN | 20 |
1 | 7499 | ALLEN | SALESMAN | 7698.0 | 1981/02/20 | 1600 | 300.0 | 30 |
2 | 7521 | WARD | SALESMAN | 7698.0 | 1981/02/22 | 1250 | 500.0 | 30 |
4 | 7654 | MARTIN | SALESMAN | 7698.0 | 1981/09/28 | 1250 | 1400.0 | 30 |
9 | 7844 | TURNER | SALESMAN | 7698.0 | 1981/09/08 | 1500 | 0.0 | 30 |
10 | 7876 | ADAMS | CLERK | 7788.0 | 1983/01/12 | 1100 | NaN | 20 |
11 | 7900 | JAMES | CLERK | 7698.0 | 1981/12/03 | 950 | NaN | 30 |
13 | 7934 | MILLER | CLERK | 7782.0 | 1982/01/23 | 1300 | NaN | 10 |
3. R Programming (R Package)
사원번호(empno)에서 해당 사원의 상위 관리자(mgr)의 사번을 제외한 사원들의 정보를 추출한다.
R Programming |
%%R
emp[!emp$empno %in% emp$mgr,"ename"]
Results |
# A tibble: 8 x 1
ename
<chr>
1 SMITH
2 ALLEN
3 WARD
4 MARTIN
5 TURNER
6 ADAMS
7 JAMES
8 MILLER
R Programming |
%%R
emp[which(!emp$empno %in% emp$mgr), c("empno","ename") ]
Results |
# A tibble: 8 x 2
empno ename
<dbl> <chr>
1 7369 SMITH
2 7499 ALLEN
3 7521 WARD
4 7654 MARTIN
5 7844 TURNER
6 7876 ADAMS
7 7900 JAMES
8 7934 MILLER
R Programming |
%%R
subset(emp,subset= (!empno %in% mgr) , select=c(empno,ename) )
Results |
# A tibble: 8 x 2
empno ename
<dbl> <chr>
1 7369 SMITH
2 7499 ALLEN
3 7521 WARD
4 7654 MARTIN
5 7844 TURNER
6 7876 ADAMS
7 7900 JAMES
8 7934 MILLER
R Programming |
%%R
require(sqldf)
sqldf("select * from emp e where empno not in (select mgr from emp where e.empno=mgr)")
Results |
empno ename job mgr hiredate sal comm deptno
1 7369 SMITH CLERK 7902 1980-12-17 800 NA 20
2 7499 ALLEN SALESMAN 7698 1981-02-20 1600 300 30
3 7521 WARD SALESMAN 7698 1981-02-22 1250 500 30
4 7654 MARTIN SALESMAN 7698 1981-09-28 1250 1400 30
5 7844 TURNER SALESMAN 7698 1981-09-08 1500 0 30
6 7876 ADAMS CLERK 7788 1983-01-12 1100 NA 20
7 7900 JAMES CLERK 7698 1981-12-03 950 NA 30
8 7934 MILLER CLERK 7782 1982-01-23 1300 NA 10
setdiff 차집합 함수
R Programming |
%%R
dplyr::setdiff (emp,emp[emp$empno %in% emp$mgr ,])
Results |
# A tibble: 8 x 8
empno ename job mgr hiredate sal comm deptno
<dbl> <chr> <chr> <dbl> <date> <dbl> <dbl> <dbl>
1 7369 SMITH CLERK 7902 1980-12-17 800 NA 20
2 7499 ALLEN SALESMAN 7698 1981-02-20 1600 300 30
3 7521 WARD SALESMAN 7698 1981-02-22 1250 500 30
4 7654 MARTIN SALESMAN 7698 1981-09-28 1250 1400 30
5 7844 TURNER SALESMAN 7698 1981-09-08 1500 0 30
6 7876 ADAMS CLERK 7788 1983-01-12 1100 NA 20
7 7900 JAMES CLERK 7698 1981-12-03 950 NA 30
8 7934 MILLER CLERK 7782 1982-01-23 1300 NA 10
4. R Dplyr Package
%in%
R Programming |
%%R
emp %>% filter( !empno %in% mgr ) %>% select(ename)
Results |
# A tibble: 8 x 1
ename
<chr>
1 SMITH
2 ALLEN
3 WARD
4 MARTIN
5 TURNER
6 ADAMS
7 JAMES
8 MILLER
dplyr::anti_join
R Programming |
%%R
emp %>% dplyr::anti_join(emp, by = c("empno" = "mgr"))
Results |
# A tibble: 8 x 8
empno ename job mgr hiredate sal comm deptno
<dbl> <chr> <chr> <dbl> <date> <dbl> <dbl> <dbl>
1 7369 SMITH CLERK 7902 1980-12-17 800 NA 20
2 7499 ALLEN SALESMAN 7698 1981-02-20 1600 300 30
3 7521 WARD SALESMAN 7698 1981-02-22 1250 500 30
4 7654 MARTIN SALESMAN 7698 1981-09-28 1250 1400 30
5 7844 TURNER SALESMAN 7698 1981-09-08 1500 0 30
6 7876 ADAMS CLERK 7788 1983-01-12 1100 NA 20
7 7900 JAMES CLERK 7698 1981-12-03 950 NA 30
8 7934 MILLER CLERK 7782 1982-01-23 1300 NA 10
5. R sqldf Package
상호연관쿼리를 사용하여서 개별 사원의 차 상위 관리자를 제외한 사원들의 정보를 추출한다.
R Programming |
%%R
require(sqldf)
sqldf("select * from emp e where empno not in (select mgr from emp where e.empno=mgr)")
Results |
empno ename job mgr hiredate sal comm deptno
1 7369 SMITH CLERK 7902 1980-12-17 800 NA 20
2 7499 ALLEN SALESMAN 7698 1981-02-20 1600 300 30
3 7521 WARD SALESMAN 7698 1981-02-22 1250 500 30
4 7654 MARTIN SALESMAN 7698 1981-09-28 1250 1400 30
5 7844 TURNER SALESMAN 7698 1981-09-08 1500 0 30
6 7876 ADAMS CLERK 7788 1983-01-12 1100 NA 20
7 7900 JAMES CLERK 7698 1981-12-03 950 NA 30
8 7934 MILLER CLERK 7782 1982-01-23 1300 NA 10
6. Python pandasql Package
Python Programming |
ps.sqldf("select * from emp e where empno not in (select mgr from emp where e.empno=mgr)")
Results |
empno | ename | job | mgr | hiredate | sal | comm | deptno | hiredate_D | to_date | day_gap | |
0 | 7369 | SMITH | CLERK | 7902.0 | 1980/12/17 | 800 | NaN | 20 | 1980-12-17 00:00:00.000000 | 2020-09-10 09:45:49.454895 | 14512 |
1 | 7499 | ALLEN | SALESMAN | 7698.0 | 1981/02/20 | 1600 | 300.0 | 30 | 1981-02-20 00:00:00.000000 | 2020-09-10 09:45:49.454895 | 14447 |
2 | 7521 | WARD | SALESMAN | 7698.0 | 1981/02/22 | 1250 | 500.0 | 30 | 1981-02-22 00:00:00.000000 | 2020-09-10 09:45:49.454895 | 14445 |
3 | 7654 | MARTIN | SALESMAN | 7698.0 | 1981/09/28 | 1250 | 1400.0 | 30 | 1981-09-28 00:00:00.000000 | 2020-09-10 09:45:49.454895 | 14227 |
4 | 7844 | TURNER | SALESMAN | 7698.0 | 1981/09/08 | 1500 | 0.0 | 30 | 1981-09-08 00:00:00.000000 | 2020-09-10 09:45:49.454895 | 14247 |
5 | 7876 | ADAMS | CLERK | 7788.0 | 1983/01/12 | 1100 | NaN | 20 | 1983-01-12 00:00:00.000000 | 2020-09-10 09:45:49.454895 | 13756 |
6 | 7900 | JAMES | CLERK | 7698.0 | 1981/12/03 | 950 | NaN | 30 | 1981-12-03 00:00:00.000000 | 2020-09-10 09:45:49.454895 | 14161 |
7 | 7934 | MILLER | CLERK | 7782.0 | 1982/01/23 | 1300 | NaN | 10 | 1982-01-23 00:00:00.000000 | 2020-09-10 09:45:49.454895 | 14110 |
7. R data.table Package
사원번호(empno)에서 관리자(mgr)들의 사번을 제외한 사원들의 정보를 추출한다.
R Programming |
%%R
DT <- data.table(emp)
dept_DT <- data.table(dept)
DT[!empno %in% mgr , ]
Results |
empno ename job mgr hiredate sal comm deptno
1: 7369 SMITH CLERK 7902 1980-12-17 800 NA 20
2: 7499 ALLEN SALESMAN 7698 1981-02-20 1600 300 30
3: 7521 WARD SALESMAN 7698 1981-02-22 1250 500 30
4: 7654 MARTIN SALESMAN 7698 1981-09-28 1250 1400 30
5: 7844 TURNER SALESMAN 7698 1981-09-08 1500 0 30
6: 7876 ADAMS CLERK 7788 1983-01-12 1100 NA 20
7: 7900 JAMES CLERK 7698 1981-12-03 950 NA 30
8: 7934 MILLER CLERK 7782 1982-01-23 1300 NA 10
emp 테이블을 사원번호와 관리자 사번을 기준으로 셀프 조인(Self Join)한 후에 관리자 사번이 존재하지 않는, 즉 관리자를 제외한 사원들의 정보를 추출한다.
R Programming |
%%R
DT[DT, nomatch=NULL, on = .(empno = mgr), i_mgr := i.mgr][is.na(i_mgr),]
Results |
empno ename job mgr hiredate sal comm deptno i_mgr x i.empno
1: 7902 FORD ANALYST 7566 1981-12-03 3000 NA 20 7902 7902 7369
2: 7698 BLAKE MANAGER 7839 1981-03-01 2850 NA 30 7698 7698 7499
3: 7698 BLAKE MANAGER 7839 1981-03-01 2850 NA 30 7698 7698 7521
4: 7839 KING PRESIDENT NA 1981-11-17 5000 NA 10 7839 7839 7566
5: 7698 BLAKE MANAGER 7839 1981-03-01 2850 NA 30 7698 7698 7654
6: 7839 KING PRESIDENT NA 1981-11-17 5000 NA 10 7839 7839 7698
7: 7839 KING PRESIDENT NA 1981-11-17 5000 NA 10 7839 7839 7782
8: 7566 JONES MANAGER 7839 1981-04-02 2975 NA 20 7566 7566 7788
9: 7698 BLAKE MANAGER 7839 1981-03-01 2850 NA 30 7698 7698 7844
10: 7788 SCOTT ANALYST 7566 1982-12-09 3000 NA 20 7788 7788 7876
11: 7698 BLAKE MANAGER 7839 1981-03-01 2850 NA 30 7698 7698 7900
12: 7566 JONES MANAGER 7839 1981-04-02 2975 NA 20 7566 7566 7902
13: 7782 CLARK MANAGER 7839 1981-01-09 2450 NA 10 7782 7782 7934
i.ename i.job i.hiredate i.sal i.comm i.deptno i.i_mgr i.x
1: SMITH CLERK 1980-12-17 800 NA 20 NA NA
2: ALLEN SALESMAN 1981-02-20 1600 300 30 NA NA
3: WARD SALESMAN 1981-02-22 1250 500 30 NA NA
4: JONES MANAGER 1981-04-02 2975 NA 20 7566 7566
5: MARTIN SALESMAN 1981-09-28 1250 1400 30 NA NA
6: BLAKE MANAGER 1981-03-01 2850 NA 30 7698 7698
7: CLARK MANAGER 1981-01-09 2450 NA 10 7782 7782
8: SCOTT ANALYST 1982-12-09 3000 NA 20 7788 7788
9: TURNER SALESMAN 1981-09-08 1500 0 30 NA NA
10: ADAMS CLERK 1983-01-12 1100 NA 20 NA NA
11: JAMES CLERK 1981-12-03 950 NA 30 NA NA
12: FORD ANALYST 1981-12-03 3000 NA 20 7902 7902
13: MILLER CLERK 1982-01-23 1300 NA 10 NA NA
emp 테이블을 사원번호와 관리자 사번을 기준으로 셀프 조인(Self Join)한 후에 관리자 사번이 존재하지 않는, 즉 관리자를 제외한 사원들의 정보를 추출한다. suffixes = c("", ".y") 을 사용하여서 왼쪽 테이블의 변수명은 emp원본 테이블의 변수명을 부여하고, 오른쪽 테이블의 변수명에는 접미어(".y")를 추가하여서 테이블을 조인한다.
조인된 테이블에서 오른쪽 테이블의 정보가 존재하지 않는 관측치를 선택하고, colnames(DT) 를 사용하여서 변수명이 원본테이블과 동일한 좌측 테이블의 변수를 선택한다.
R Programming |
%%R
DT <- data.table(emp)
dept_DT <- data.table(dept)
merge(DT, DT, by.x="empno", by.y="mgr", all.x = TRUE, suffixes = c("", ".y"))[is.na(empno.y), colnames(DT), with=FALSE ]
Results |
empno ename.x job.x mgr hiredate.x sal.x comm.x deptno.x empno.y
1: 7369 SMITH CLERK 7902 1980-12-17 800 NA 20 NA
2: 7499 ALLEN SALESMAN 7698 1981-02-20 1600 300 30 NA
3: 7521 WARD SALESMAN 7698 1981-02-22 1250 500 30 NA
4: 7566 JONES MANAGER 7839 1981-04-02 2975 NA 20 7788
5: 7566 JONES MANAGER 7839 1981-04-02 2975 NA 20 7902
6: 7654 MARTIN SALESMAN 7698 1981-09-28 1250 1400 30 NA
7: 7698 BLAKE MANAGER 7839 1981-03-01 2850 NA 30 7499
8: 7698 BLAKE MANAGER 7839 1981-03-01 2850 NA 30 7521
9: 7698 BLAKE MANAGER 7839 1981-03-01 2850 NA 30 7654
10: 7698 BLAKE MANAGER 7839 1981-03-01 2850 NA 30 7844
11: 7698 BLAKE MANAGER 7839 1981-03-01 2850 NA 30 7900
12: 7782 CLARK MANAGER 7839 1981-01-09 2450 NA 10 7934
13: 7788 SCOTT ANALYST 7566 1982-12-09 3000 NA 20 7876
14: 7839 KING PRESIDENT NA 1981-11-17 5000 NA 10 7566
15: 7839 KING PRESIDENT NA 1981-11-17 5000 NA 10 7698
16: 7839 KING PRESIDENT NA 1981-11-17 5000 NA 10 7782
17: 7844 TURNER SALESMAN 7698 1981-09-08 1500 0 30 NA
18: 7876 ADAMS CLERK 7788 1983-01-12 1100 NA 20 NA
19: 7900 JAMES CLERK 7698 1981-12-03 950 NA 30 NA
20: 7902 FORD ANALYST 7566 1981-12-03 3000 NA 20 7369
21: 7934 MILLER CLERK 7782 1982-01-23 1300 NA 10 NA
empno ename.x job.x mgr hiredate.x sal.x comm.x deptno.x empno.y
ename.y job.y hiredate.y sal.y comm.y deptno.y
1: <NA> <NA> <NA> NA NA NA
2: <NA> <NA> <NA> NA NA NA
3: <NA> <NA> <NA> NA NA NA
4: SCOTT ANALYST 1982-12-09 3000 NA 20
5: FORD ANALYST 1981-12-03 3000 NA 20
6: <NA> <NA> <NA> NA NA NA
7: ALLEN SALESMAN 1981-02-20 1600 300 30
8: WARD SALESMAN 1981-02-22 1250 500 30
9: MARTIN SALESMAN 1981-09-28 1250 1400 30
10: TURNER SALESMAN 1981-09-08 1500 0 30
11: JAMES CLERK 1981-12-03 950 NA 30
12: MILLER CLERK 1982-01-23 1300 NA 10
13: ADAMS CLERK 1983-01-12 1100 NA 20
14: JONES MANAGER 1981-04-02 2975 NA 20
15: BLAKE MANAGER 1981-03-01 2850 NA 30
16: CLARK MANAGER 1981-01-09 2450 NA 10
17: <NA> <NA> <NA> NA NA NA
18: <NA> <NA> <NA> NA NA NA
19: <NA> <NA> <NA> NA NA NA
20: SMITH CLERK 1980-12-17 800 NA 20
21: <NA> <NA> <NA> NA NA NA
ename.y job.y hiredate.y sal.y comm.y deptno.y
8. SAS Proc SQL
SAS Programming |
%%SAS sas
PROC SQL;
CREATE TABLE STATSAS_1 AS
SELECT *
FROM EMP
WHERE EMPNO NOT IN (SELECT MGR FROM EMP WHERE MGR IS NOT NULL);
QUIT;
PROC PRINT DATA=STATSAS_1(OBS=3);RUN;
Results |
OBS | empno | ename | job | mgr | hiredate | sal | comm | deptno |
1 | 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 800 | . | 20 |
2 | 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600 | 300 | 30 |
3 | 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250 | 500 | 30 |
SAS Programming |
%%SAS sas
PROC SQL;
CREATE TABLE STATSAS_12 AS
SELECT *
FROM EMP E
WHERE EMPNO NOT IN (SELECT MGR FROM EMP WHERE E.EMPNO=MGR);
QUIT;
PROC PRINT DATA=STATSAS_12(OBS=3);RUN;
Results |
OBS | empno | ename | job | mgr | hiredate | sal | comm | deptno |
1 | 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 800 | . | 20 |
2 | 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600 | 300 | 30 |
3 | 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250 | 500 | 30 |
SAS Programming |
%%SAS sas
PROC SQL;
CREATE TABLE STATSAS_13 AS
SELECT A.*
FROM EMP A
LEFT JOIN (SELECT distinct MGR FROM EMP) b
ON A.EMPNO = B.MGR
WHERE B.MGR = .;
QUIT;
PROC PRINT DATA=STATSAS_13;RUN;
9. SAS Data Step
SAS Programming |
%%SAS sas
DATA EMP1;
SET EMP;
RENAME EMPNO = EMP_KEY;
RUN;
PROC SORT DATA=EMP1;
BY EMP_KEY;
RUN;
DATA EMP2;
SET EMP;
RENAME MGR = EMP_KEY;
RUN;
PROC SORT DATA=EMP2;
BY EMP_KEY;
RUN;
DATA STATSAS_2;
MERGE EMP1(IN=A) EMP2(IN=B);
BY EMP_KEY;
IF A AND B=0; * IF A=1 AND B=0 THEN OUTPUT STATSAS_2;
DROP EMPNO;
RUN;
PROC PRINT DATA=STATSAS_2(OBS=3);RUN;
Results |
OBS | EMP_KEY | ename | job | mgr | hiredate | sal | comm | deptno |
1 | 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 800 | . | 20 |
2 | 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600 | 300 | 30 |
3 | 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250 | 500 | 30 |
10. Python Dfply Package
filter_by & mask
Python Programming |
emp >> filter_by( ~ X.empno.isin(X.mgr) )
Results |
empno | ename | job | mgr | hiredate | sal | comm | deptno | |
0 | 7369 | SMITH | CLERK | 7902.0 | 1980/12/17 | 800 | NaN | 20 |
1 | 7499 | ALLEN | SALESMAN | 7698.0 | 1981/02/20 | 1600 | 300.0 | 30 |
2 | 7521 | WARD | SALESMAN | 7698.0 | 1981/02/22 | 1250 | 500.0 | 30 |
4 | 7654 | MARTIN | SALESMAN | 7698.0 | 1981/09/28 | 1250 | 1400.0 | 30 |
9 | 7844 | TURNER | SALESMAN | 7698.0 | 1981/09/08 | 1500 | 0.0 | 30 |
10 | 7876 | ADAMS | CLERK | 7788.0 | 1983/01/12 | 1100 | NaN | 20 |
11 | 7900 | JAMES | CLERK | 7698.0 | 1981/12/03 | 950 | NaN | 30 |
13 | 7934 | MILLER | CLERK | 7782.0 | 1982/01/23 | 1300 | NaN | 10 |
[SQL, Pandas, R Prog, Dplyr, SQLDF, PANDASQL, DATA.TABLE] SQL EMP 예제로 만나는 테이블 데이터 처리 방법 리스트
댓글