-
Notifications
You must be signed in to change notification settings - Fork 0
/
04-relasi-data-model-sql.qmd
701 lines (523 loc) · 17.9 KB
/
04-relasi-data-model-sql.qmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
---
title: "SQL"
subtitle: "<br/>Every second of every day, our senses bring in way too much data than we can possibly process in our brains.<br/>- Peter Diamandis<br/><br/>"
block-headings: TRUE
author: "<br/><br/><br/>Alfa Nugraha Pradana"
institute: "Prodi Statistika dan Sains Data IPB University"
footer: "[rpubs.com/alfanugraha/sta1562-p04](https://rpubs.com/alfanugraha/sta1562-p04) "
format:
revealjs:
theme: [default, style.scss]
slide-number: c/t
code-copy: true
# center-title-slide: false
code-overflow: wrap
highlight-style: a11y
height: 1080
width: 1920
logo: assets/img/LogoIPBUni.png
preview-links: auto
editor: visual
---
## Outline
<br/>
- Structured Query Language (SQL)
- Definisi data
- Tipe data
- Batasan (constraint)
- Kueri dasar (SELECT)
- Perintah INSERT, DELETE, UPDATE
- RPostgreSQL
- ElephantSQL
- shinyapps.io
# Structured Query Language (SQL) {background="#43464B"}
## SQL
<br/>
> Awalnya SQL disebut SEQUEL (Structured English QUEry Language) yang dirancang dan diimplementasikan oleh IBM Research sebagai prototype sistem database relasional yang dikenal dengan SYSTEM R.
. . .
<br/>
Sekarang, SQL digunakan sebagai bahasa standard untuk DBMS relasional secara komersial.
. . .
<br/>
ANSI dan ISO membuat standard SQL pertama dengan nama SQL-86, kemudian berkembang menjadi SQL-92, SQL:1999, SQL:2003, SQL:2006, hingga saat ini SQL:2019 dengan konsep dan teknologi basis data yang mutakhir.
. . .
<br/>
SQL adalah bahasa database yang komprehensif, memiliki perintah dalam setiap mendefinisikan data, kueri, dan juga update terhadap data tersebut. Selain itu, terdapat juga fasilitas untuk menetapkan keamanan dan otorisasi dalam membuat batasan serta kendali terhadap transaksi data.
## Definisi data SQL
. . .
<br/>
Perintah utama untuk mendefinisikan data adalah `CREATE`.
. . .
<br/>
```{{sql}}
CREATE SCHEMA HOSPITAL;
CREATE TABLE PATIENTS;
CREATE DOMAIN SSN_TYPE AS CHAR(9);
CREATE VIEW ...
CREATE TYPE ...
```
. . .
<br/>
Perintah lain pada definisi data yaitu `DROP` dan `ALTER`.
<br/>
```{{sql}}
DROP SCHEMA HOSPITAL;
DROP TABLE PATIENTS;
ALTER TABLE ROOM OWNER to postgres;
```
## Tipe data {.scrollable}
::: {style="font-size: 0.7em;"}
+-------------------------+----------------------------------------+
| | |
+=========================+========================================+
| **Numeric** | - INTEGER/INT/SMALLINT |
| | - FLOAT/REAL/DOUBLE PRECISION |
| | - DECIMAL(i,j)/DEC(i,j)/NUMERIC(i,j) |
+-------------------------+----------------------------------------+
| **Character-string** | - CHAR(n)/CHARACTER(n) |
| | - VARCHAR(n)/CHAR VARYING(n) |
| | - CHARACTER VARYING(n) |
+-------------------------+----------------------------------------+
| **Bit-string** | - BIT(n) |
| | - BIT VARYING(n) |
+-------------------------+----------------------------------------+
| **Boolean** | TRUE/FALSE/NULL |
+-------------------------+----------------------------------------+
| **Date** | - YEAR(YYYY) |
| | - MONTH(MM) |
| | - DAY(DD) |
+-------------------------+----------------------------------------+
| **Time** | - HOUR(HH) |
| | - MINUTE(MM) |
| | - SECOND(SS) |
+-------------------------+----------------------------------------+
:::
## Domain
<br/>
Suatu domain dapat dideklarasikan dan digunakan sebagai spesifikasi suatu atribut
<br/>
. . .
```{{sql}}
CREATE DOMAIN SSN_TYPE AS CHAR(9);
```
<br/>
. . .
```{{sql}}
ALTER TABLE EMPLOYEE
MODIFY Ssn Ssn VARCHAR(9) NOT NULL;
```
## Batasan SQL
<br/>
::: {.incremental}
* `NOT NULL`: [nilai data pada suatu atribut tidak boleh kosong]{.fragment}
* `UNIQUE`: [nilai data pada suatu atribut tidak sama/berulang]{.fragment}
* `DEFAULT`: [memberi nilai bawaan terhadap data suatu atribut yang kosong]{.fragment}
* `CHECK`: [memastikan data suatu atribut sesuai aturan yang telah ditentukan]{.fragment}
* `PRIMARY KEY`: [identitas unik suatu entitas yang nilainya tidak boleh kosong dan berulang]{.fragment}
* `FOREIGN KEY`: [atribut suatu entitas yang mengacu pada primary key entitas lain]{.fragment}
:::
## Skema Diagram HOSPITAL {.scrollable}
<br/>
```{dot}
graph Hospital {
layout=neato
overlap=false
fontname="Helvetica,Arial,sans-serif"
node [fontname="Helvetica,Arial,sans-serif"]
edge [fontname="Helvetica,Arial,sans-serif"]
node [shape=box]; PASIEN; KAMAR; DOKTER;
node [shape=ellipse] id_kamar; kelas; ketersediaan; id_pasien; nama_pasien; alamat; umur_pasien; status; tinggi; berat; id_dokter; nama_dokter; umur_dokter; spesialis; upah;
node [shape=diamond,style=filled,color=lightgrey]; UNTUK; TINDAKAN;
id_kamar [label = <<u> id_kamar </u>>]
id_pasien [label = <<u> id_pasien </u>>]
id_dokter [label = <<u> id_dokter </u>>]
id_kamar -- KAMAR;
kelas -- KAMAR;
ketersediaan -- KAMAR;
KAMAR -- UNTUK [label="1",len=1.00];
UNTUK -- PASIEN [label="1",len=1.00];
id_pasien -- PASIEN;
nama_pasien -- PASIEN;
alamat -- PASIEN;
umur_pasien -- PASIEN;
status -- PASIEN;
tinggi -- PASIEN;
berat -- PASIEN;
PASIEN -- TINDAKAN [label="n",len=1.00];
TINDAKAN -- DOKTER [label="n",len=1.00];
id_dokter -- DOKTER;
nama_dokter -- DOKTER;
umur_dokter -- DOKTER;
spesialis -- DOKTER;
upah -- DOKTER;
fontsize=40;
}
```
. . .
<br/>
* *Satu pasien dapat menyewa fasilitas satu kamar, satu kamar dapat disewa dan digunakan oleh satu pasien*
* *Satu dokter dapat menangani banyak pasien, satu pasien dapat dilakukan tindakan oleh beberapa dokter*
## Merancang ERD dan membuat database HOSPITAL {.scrollable}
<br/>
::: columns
::: {.column width="50%"}
Tabel **kamar**
```{{sql}}
CREATE TABLE IF NOT EXISTS public.kamar (
id_kamar character varying(10) NOT NULL,
kelas character varying(20) NOT NULL,
ketersediaan character varying(20) NOT NULL,
PRIMARY KEY (id_kamar)
);
```
<br/>
Tabel **pasien**
```{{sql}}
CREATE TABLE IF NOT EXISTS public.pasien (
id_pasien character varying(20) NOT NULL,
nama text NOT NULL,
alamat text NOT NULL,
umur integer,
status character varying(15) NOT NULL,
tinggi integer NOT NULL,
berat integer NOT NULL,
PRIMARY KEY (id_pasien)
);
```
<br/>
Tabel **dokter**
```{{sql}}
CREATE TABLE IF NOT EXISTS public.dokter (
id_dokter character varying(20) NOT NULL,
nama_dokter text NOT NULL,
umur_dokter integer NOT NULL,
spesialis character varying(20) NOT NULL,
upah integer NOT NULL,
PRIMARY KEY (id_dokter)
);
```
<br/>
Tabel **kamar_untuk_pasien**
```{{sql}}
CREATE TABLE IF NOT EXISTS public.kamar_untuk_pasien(
id_kamar character varying(10) COLLATE pg_catalog."default" NOT NULL,
id_pasien character varying(20) COLLATE pg_catalog."default" NOT NULL,
CONSTRAINT kamar_untuk_pasien_pkey PRIMARY KEY (id_kamar, id_pasien),
CONSTRAINT kamar_untuk_pasien_id_kamar_fkey FOREIGN KEY (id_kamar)
REFERENCES public.kamar (id_kamar) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION,
CONSTRAINT kamar_untuk_pasien_id_pasien_fkey FOREIGN KEY (id_pasien)
REFERENCES public.pasien (id_pasien) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
);
```
<br/>
Tabel **tindakan**
```{{sql}}
CREATE TABLE IF NOT EXISTS public.tindakan (
id_pasien character varying(20) NOT NULL,
id_dokter character varying(20) NOT NULL,
CONSTRAINT tindakan_pkey PRIMARY KEY (id_pasien, id_dokter),
CONSTRAINT tindakan_id_dokter_fkey FOREIGN KEY (id_dokter)
REFERENCES public.dokter (id_dokter) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION,
CONSTRAINT tindakan_id_pasien_fkey FOREIGN KEY (id_pasien)
REFERENCES public.pasien (id_pasien) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
);
```
:::
::: {.column width="50%"}
```{mermaid}
%%| fig-width: 3
erDiagram
KAMAR ||--|{ KAMAR_UNTUK_PASIEN : ditempati
KAMAR {
int id_kamar PK
string kelas
string ketersediaan
}
KAMAR_UNTUK_PASIEN }|--|| PASIEN : menempati
KAMAR_UNTUK_PASIEN {
int id_kamar FK
int id_pasien FK
}
PASIEN ||--|{ TINDAKAN : dilakukan
PASIEN {
int id_pasien PK
string nama_pasien
int umur_pasien
int tinggi
int berat
string status
string alamat
}
TINDAKAN }|--|| DOKTER : melakukan
TINDAKAN {
int id_pasien FK
int id_dokter FK
}
DOKTER {
int id_dokter PK
string nama_dokter
string spesialis
int umur_dokter
int upah
}
```
:::
:::
## `INSERT` tuple {.scrollable}
<br/>
**dokter**
```{{sql}}
INSERT INTO dokter
VALUES ('DKV1509876','dr. Indah Risma Sp.BTKV ',45,'Kardiovaskular',6500000),
('DOT76896766','dr. Chairuddin Lubis Sp.OT',39,'Ortopedi',5650000),
('DOG5655123','dr. Amelia Rinta Sp.OG',38,'Kandungan',5500000),
('DKV1544569','dr. Wahyu Kusuma Sp.BTKV',49,'Kardiovaskular',7000000),
('DA76884560','dr. Muti Mulia Sp.A',36,'Anak',5300000),
('DU455434456','dr. Dyah Agustina',42,'Umum',5000000),
('DU453323565','dr. Mifthah Farhan',36,'Umum',4800000),
('DS34335980','dr. Ferdy Saragih Sp.S',50,'Saraf',7400000),
('DP00981287','dr. Joko Ahmad Sp.P',54,'Paru-paru',7400000);
```
<br/>
**pasien**
```{{sql}}
INSERT INTO pasien
VALUES ('ID0989096','Merlin Anindita','Jl. Majapahit No. 9',NULL,'SINGLE',156,53),
('ID7689009','Ilham Mubarok','Jl. Soekarno Hatta No. 21',32,'MENIKAH',168,70),
('ID9870034','Kislam','Jl. Merpati No.9',50,'MENIKAH',165,63),
('ID0966789','Nur Hakim','Jl. Kaliurang km 5',20,'SINGLE',153,65),
('ID1324564','Habibur Rifqi','Jl. Bunda no. 13',6,'SINGLE',135,35),
('ID1267864','Yulisman','Ujung Pandang',52,'MENIKAH',163,70),
('ID1254789','Ibrahim Mika','Jl. Ginting no. 6',4,'SINGLE',126,25),
('ID8764456','Agus Rahman','Jl. Merpati No.28',34,'MENIKAH',157,60),
('ID0987679','Putri Mayani','Jl. Anggur no. 7',28,'MENIKAH',156,55),
('ID0456989','Nur Kartika','Padang Raya No. 6',18,'SINGLE',150,60),
('ID0656554','Auliya Fikri','Jl. Lintas Angkasa No. 2',23,'SINGLE',170,75);
```
<br/>
**kamar**
```{{sql}}
INSERT INTO kamar
VALUES ('R101','Umum','Tersedia'),
('R102','Umum','Tersedia'),
('R103','Umum','Tersedia'),
('R104','Umum','Tersedia'),
('R201','VIP','Tersedia'),
('R202','VIP','Tersedia'),
('R203','VIP','Tersedia'),
('R204','VIP','Tersedia'),
('R301','VVIP','Tersedia'),
('R302','VVIP','Tersedia'),
('R303','VVIP','Tersedia'),
('R304','VVIP','Tersedia');
```
<br/>
**kamar_untuk_pasien**
```{{sql}}
INSERT INTO kamar_untuk_pasien
VALUES ('R102','ID0989096'),
('R201','ID7689009'),
('R203','ID0966789'),
('R104','ID1254789'),
('R301','ID8764456'),
('R304','ID0987679'),
('R302','ID1267864');
```
<br/>
**tindakan**
```{{sql}}
INSERT INTO tindakan
VALUES ('ID0989096','DOT76896766'),
('ID7689009','DKV1509876'),
('ID9870034','DKV1544569'),
('ID0966789','DOT76896766'),
('ID1324564','DA76884560'),
('ID1267864','DS34335980'),
('ID1254789','DA76884560'),
('ID8764456','DKV1544569'),
('ID0987679','DOG5655123'),
('ID0456989','DU453323565'),
('ID0656554','DU455434456');
```
## Kueri `SELECT` {.scrollable}
Seluruh perintah yang dapat digunakan di dalam PostgreSQL dapat dilihat di Glosarium [PostgreSQL Commands](https://www.postgresql.org/docs/current/sql-commands.html). Secara ringkas dan sering digunakan untuk perintah `SELECT`, dapat dilihat pada tabel di bawah ini
::: {style="font-size: 0.7em;"}
| Perintah | Keterangan |
|------------|------------------------------------------------------------------------|
| `SELECT` | Memilih data dari database |
| `FROM` | Memilih table darimana data diambil |
| `WHERE` | Menyaring kueri dengan mencocokkan suatu kondisi |
| `AS` | Mengubah nama kolom atau tabel dengan suatu alias |
| `JOIN` | Menggabungkan baris dari dua atau lebih tabel |
| `AND` | Kombinasi kondisi kueri dengan semua kondisi harus terpenuhi |
| `OR` | Kombinasi kondisi kueri dengan salah satu kondisi harus terpenuhi |
| `LIMIT` | Membatasi jumlah baris yang ditampilkan |
| `IN` | Spesifikasi beberapa nilai ketika menggunakan `WHERE` |
| `IS NULL` | Mengembalikan baris dengan nilai `NULL` |
| `LIKE` | Mencari pola tertentu di suatu kolom |
| `GROUP BY` | Mengelompokkan Data |
| `ORDER BY` | Mengurutkan data, secara default menaik (`ASC`), menurun (`DESC`) untuk sebaliknya |
| `HAVING` | Serupa dengan perintah `WHERE` tetapi digunakan untuk filter Groups |
| `COUNT` | Menghitung jumlah baris |
| `SUM` | Menghitung jumlah dari kolom |
| `AVG` | Menghitung rata-rata dari kolom |
| `MIN` | Menghitung nilai terkecil dari kolom |
| `MAX` | Menghitung nilai terbesar dari kolom |
:::
::: footer
Learn more: [SELECT Commands](https://www.postgresql.org/docs/current/sql-select.html)
:::
## Urutan eksekusi perintah
<br/>
1. `FROM`
2. `WHERE`
3. `GROUP BY`
4. `HAVING`
5. `SELECT`
6. `ORDER BY`
7. `LIMIT`
## DELETE
<br/>
menghapus tuple dari relasi dengan menggunakan tambahan perintah `WHERE`
<br/>
. . .
```{{sql}}
DELETE FROM tindakan
WHERE id_pasien = 'ID0989096';
DELETE FROM pasien
WHERE id_pasien = 'ID0989096';
DELETE FROM dokter
WHERE nama_dokter = 'dr. Indah Risma Sp.BTKV ';
```
## UPDATE
<br/>
memodifikasi satu atau lebih nilai atribut terpilih pada suatu tuple dengan juga menggunakan perintah `WHERE` dan `SET` sebagai nilai baru
<br/>
. . .
```{{sql}}
UPDATE pasien
SET nama_pasien = 'Alfa', tinggi = 173
WHERE id_pasien = 'ID0456989'
UPDATE dokter
SET nama_dokter = 'dr. Alfa', spesialis = 'Anak'
WHERE id_dokter = 'DP00981287'
UPDATE kamar
SET ketersediaan = 'Tidak tersedia'
WHERE id_kamar = 'R301'
```
<br/>
# PostgreSQL in R {background="#43464B"}
## RPostgreSQL
<br/>
. . .
> R Interface to the PostgreSQL Database System
<br/>
. . .
Untuk membangun koneksi ke database di dalam PostgreSQL dapat dilakukan dengan perintah:
<br/>
```{r}
#| eval: false
#| echo: true
library(RPostgreSQL)
driver <- dbDriver('PostgreSQL')
DB <- dbConnect(
driver,
dbname="rf-mds",
host="localhost",
port=5433,
user="postgres",
password="root"
)
```
. . .
<br/>
`CREATE` tabel pada PostgreSQL
<br/>
```{r}
#| eval: false
#| echo: true
dbWriteTable(DB, "tbl_iris", iris, row.names=F)
dbDisconnect(DB)
```
## Perintah pada RPostgreSQL
<br/>
```{r}
#| eval: true
#| echo: true
library(RPostgreSQL)
driver <- dbDriver('PostgreSQL')
DB <- dbConnect(
driver, dbname="employee", host="localhost",port=5433,user="postgres", password="root"
)
```
. . .
<br/>
```{r}
#| eval: true
#| echo: true
dbListTables(DB)
```
. . .
```{r}
#| eval: true
#| echo: true
dbListFields(DB, "department")
```
. . .
<br/>
```{r}
#| eval: true
#| echo: true
knitr::kable(dbReadTable(DB, "department"))
dbDisconnect(DB)
```
# ElephantSQL {background="#43464B"}
## ElephantSQL {.scrollable}
::: columns
::: {.column width="60%"}
![](assets/img/elephantsql.png)
:::
::: {.column width="40%"}
```{r}
#| eval: false
#| echo: true
con <- dbConnect(
dbDriver("PostgreSQL"),
dbname = Sys.getenv("ELEPHANT_SQL_DBNAME"),
host = Sys.getenv("ELEPHANT_SQL_HOST"),
port = 5432,
user = Sys.getenv("ELEPHANT_SQL_USER"),
password = Sys.getenv("ELEPHANT_SQL_PASSWORD")
)
```
:::
:::
::: footer
[ElephantSQL](https://www.elephantsql.com/)
:::
# shinyapps.io {background="#43464B"}
## {background-iframe="https://www.shinyapps.io/"}
## Tugas Kelompok {background="#43464B"}
::: {style="font-size: 0.7em; text-align: center"}
1. Pembagian peran dan task pada masing-masing anggota tim (pembagian tugas di bawah ini tetap membutuhkan kerja sama tim dalam penyelesainnya):
- **Data Manager**
* membuat akun dan berperan sebagai admin pada aplikasi DBMS as a Service (ElephantSQL, self-hosting, shared-hosting, etc.)
* memegang kendali penuh dalam pengelolaan database (CRUD) seefektif mungkin
* membuat sintaks SQL (part of **Data Engineer**)
- **Shiny Developer**, bertanggung jawab untuk membuat akun, menjadi admin pada [shinyapps.io](https://www.shinyapps.io), membangun antarmuka dan back-end process Shiny. Anggota tim yang berjumlah 4 orang dapat dibagi menjadi dua tugas yaitu:
* **Front-end ShinyApps**, mengerjakan rancangan layout antarmuka menggunakan Shiny
* **Back-end ShinyApps**, membangun perintah yang dapat menghubungkan antara data pada database dan penyajiannya pada Shiny, role ini akan banyak bekerja sama dengan **Data Manager**
- **Technical Writer**
* mendokumentasikan aplikasi database, deskripsi ShinyApps yang dibuat ke dalam Rmd pada situs GitHub secara lengkap, jelas, dan menyeluruh
* membuat skema dan ER diagram
* membuat *help guide* dan manual penggunaan ShinyApps
2. Merancang database minimal empat tabel berelasi. Pertemuan berikutnya masing-masing kelompok diharapkan dapat menunjukkan skema diagram, diagram Entity-Relationship, dan sintaks SQL pada Rmd GitHub masing-masing kelompok untuk direview terlebih dahulu sebelum dimasukkan ke dalam DBMS.
:::