SQL 문법 과 ORM 문법 비교
SQL과 django ORM
기본 준비 사항
# 폴더구조
TIL
00_StartCamp
...
04_db
00_sql # only SQL
hellodb.csv
tutorial.sqlite3
users.csv
01_sql_orm # SQL + ORM
...
users.csv # 해당 디렉토리로 다운로드
-
django app
-
가상환경 세팅
-
django project :
sql
-
django app :
users
-
django_extensions
설치 및 등록 -
users.csv 파일에 맞춰
models.py
작성 및 migratation# users/models.py from django.db import models class User(models.Model): first_name = models.CharField(max_length=10) last_name = models.CharField(max_length=10) age = models.IntegerField() country = models.CharField(max_length=10) phone = models.CharField(max_length=15) balance = models.IntegerField()
$ python manage.py makemigrations $ python manage.py migrate
아래의 명령어를 통해서 실제 쿼리문 확인
$ python manage.py sqlmigrate users 0001
-
-
db.sqlite3
활용-
sqlite3
실행$ ls db.sqlite3 manage.py ... $ sqlite3 db.sqlite3
-
csv 파일 data 로드
sqlite > .tables auth_group django_admin_log auth_group_permissions django_content_type auth_permission django_migrations auth_user django_session auth_user_groups auth_user_user_permissions users_user sqlite > .mode csv sqlite > .import users.csv users_user sqlite > SELECT COUNT(*) FROM user_users; 100
-
-
확인
-
sqlite3에서 스키마 확인
sqlite > .schema users_user CREATE TABLE IF NOT EXISTS "users_user" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "first_name" varchar(10) NOT NULL, "last_name" varchar(10) NOT NULL, "age" integer NOT NULL, "country" varchar(10) NOT NULL, "phone" varchar(15) NOT NULL, "balance" integer NOT NULL);
-
문제
아래의 문제들을 보면서 서로 대응되는 ORM문과 SQL문을 작성하시오.
vscode 터미널을 좌/우로 나누어 진행하시오. (sqlite / shell_plus)
.headers on
을 켜고 작성해주세요.
1. 기본 CRUD 로직
-
모든 user 레코드 조회
# orm User.objects.all()
-- sql sqlite> SELECT * FROM user_users
-
user 레코드 생성
# orm user = User(id=102, first_name='진영', last_name='박', age=28, country='대전', phone='010-1234-5678', balance=100000) user.save() ---------------------------------- User.objects.create(first_name='길동', last_name='홍', age=100, country='제주도', phone='010-1234-5678', balance=100000)
-- sql INSERT INTO users_user VALUES (101, '선잔', '박', '28', '대전', '010-6666-6666', 0);
- 하나의 레코드를 빼고 작성 후
NOT NULL
constraint 오류를 orm과 sql에서 모두 확인 해보세요.
- 하나의 레코드를 빼고 작성 후
-
해당 user 레코드 조회
101
번 id의 전체 레코드 조회
# orm User.objects.get(pk=101)
-- sql SELECT * FROM users_user WHERE id=101;
-
해당 user 레코드 수정
- ORM:
101
번 글의last_name
을 ‘김’ 으로 수정 - SQL:
101
번 글의first_name
을 ‘철수’ 로 수정
# orm user = User.objects.get(pk=101) user.last_name = '김' user.save()
-- sql UPDATE users_user SET first_name='성진' WHERE id=101;
- ORM:
-
해당 user 레코드 삭제
- ORM:
101
번 글 삭제 SQL
:101
번 글 삭제 (ORM에서 삭제가 되었기 때문에 아무런 응답이 없음)
# orm <<<<<<< HEAD
-- sql DELETE FROM users_user WHERE id=101; ======= User.objects.get(pk=102).delete()
-- sql DELETE FROM users_user WHERE id=101; >>>>>>> 22d4cdeece2af6662dace2373e6cf5f0a6867624
- ORM:
2. 조건에 따른 쿼리문
-
전체 인원 수
User
의 전체 인원수
# orm In [4]: User.objects.all().count() Out[4]: 101 ------------------------- len(User.objects.all()) # 되도록 사용 x, 성능차이있음 101
-- sql SELECT COUNT(*) FROM users_user;
-
나이가 30인 사람의 이름
ORM
:.values
활용- 예시:
User.objects.filter(조건).values(컬럼이름)
- 예시:
# orm User.objects.filter(age=30).values('first_name')
# orm print(User.objects.filter(age=30).values('first_name').query) SELECT "users_user"."first_name" FROM "users_user" WHERE "users_user"."age" = 30 -- sql SELECT first_name FROM users_user WHERE age=30;
-
나이가 30살 이상인 사람의 인원 수
- ORM:
__gte
,__lte
,__gt
,__lt
-> 대소관계 활용
# orm In [10]: User.objects.filter(age__gte=30).count() Out[10]: 44
-- sql SELECT COUNT(*) FROM users_user WHERE age>=30;
- ORM:
-
나이가 20살 이하인 사람의 인원 수
# orm In [18]: User.objects.filter(age__lte=20).count() Out[18]: 23
-- sql SELECT COUNT(*) FROM users_user WHERE age<=20;
-
나이가 30이면서 성이 김씨인 사람의 인원 수
# orm User.objects.filter(age=30, last_name='김').count() 1
-- sql SELECT COUNT(*) FROM users_user WHERE age=30 and last_name='김';
-
나이가 30이거나 성이 김씨인 사람?
# orm User.objects.filter(Q(age=30) | Q(last_name='김'))
-- sql SELECT COUNT(*) FROM users_user WHERE age=30 or last_name='김';
-
지역번호가 02인 사람의 인원 수
ORM
:__startswith
# orm User.objects.filter(phone__startswith='02-').count()
-- sql SELECT COUNT(*) FROM users_user WHERE phone LIKE '02-%';
-
거주 지역이 강원도이면서 성이 황씨인 사람의 이름
# orm In [25]: User.objects.filter(country='강원도', last_name='황').values('first_name') Out[25]: <QuerySet [{'first_name': '은정'}]> ------정답-------- User.objects.filter(country='강원도', last_name='황').values('first_name').first().get('first_name')
-- sql SELECT first_name FROM users_user WHERE country='강원도' and last_name='황';
3. 정렬 및 LIMIT, OFFSET
-
나이가 많은 사람순으로 10명
# orm User.objects.order_by('-age')[:10]
-- sql sqlite> SELECT * FROM users_user ...> ORDER BY age DESC LIMIT 10;
-
잔액이 적은 사람순으로 10명
# orm User.objects.order_by('balance')[:10] User.objects.order_by('balance')[:10].count()
-- sql SELECT * FROM users_user ORDER BY age LIMIT 10; # ASC 오름차순은 기본값
-
잔고는 오름차순, 나이는 내림차순으로 10명?
# orm User.objects.order_by('balance', '-age')[:10]
```sql -- sql SELECT * FROM users_user ORDER BY balance, age DESC LIMIT 10;
-
성, 이름 내림차순 순으로 5번째 있는 사람
# orm User.objects.order_by('-last_name', '-first_name')[4]
```sql -- sql SELECT * FROM users_user ORDER BY last_name DESC, first_name DESC LIMIT 1 OFFSET 4;
4. 표현식
ORM:
aggregate
사용https://docs.djangoproject.com/en/2.2/topics/db/aggregation/#aggregation
- ‘종합’, ‘합계’ 등의 사전적 의미
- 특정 필드 전체의 합, 평균 등을 계산할 때 사용
-
전체 평균 나이
# orm User.objects.aggregate(avg_age=Avg('age')) Out[40]: {'avg_age': 28.940594059405942}
-- sql SELECT AVG(age) FROM users_user; AVG(age) 28.9405940594059
-
김씨의 평균 나이
# orm User.objects.filter(last_name='김').aggregate(Avg('age')) Out[41]: {'age__avg': 28.782608695652176}
-- sql SELECT AVG(age) FROM users_user WHERE last_name='김'; AVG(age) 28.7826086956522
-
강원도에 사는 사람의 평균 계좌 잔고
# orm User.objects.filter(country='강원도').aggregate(Avg('balance')) Out[42]: {'balance__avg': 157895.0}
-- sql SELECT AVG(balance) FROM users_user WHERE country='강원도'; AVG(balance) 157895.0
-
계좌 잔액 중 가장 높은 값
# orm User.objects.aggregate(Max('balance')) {'balance__max': 1000000}
-- sql SELECT MAX(balance) FROM users_user; MAX(balance) 1000000
-
계좌 잔액 총액
# orm In [45]: User.objects.aggregate(Sum('balance')) Out[45]: {'balance__sum': 14525040}
-- sql SELECT SUM(balance) FROM users_user; SUM(balance) 14525040