-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathpgsql-tutorial.xml
1246 lines (1193 loc) · 77.5 KB
/
pgsql-tutorial.xml
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
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="UTF-8"?>
<!-- ********************************************************************
apps/pgsql-tutorial.xml
******************************************************************** -->
<book xml:id="pgsql-tutorial" xmlns="http://docbook.org/ns/docbook"
xmlns:xl="http://www.w3.org/1999/xlink" version="5.0" xml:lang="tr"
userlevel="longtoc">
<?dbhtml dir="../uygulamalar/pgsql"?>
<info>
<title>PostgreSQL Eğitmeni</title>
<authorgroup>
<author role="translator">
<personname>
<firstname>Nilgün Belma Bugüner</firstname>
</personname>
<address>
<link xl:href="https://github.com/nilgun"/>
</address>
</author>
<author role="translator">
<personname>
<firstname>Volkan "knt" Yazıcı</firstname>
</personname>
<address>
<link xl:href="https://github.com/vy"/>
</address>
</author>
</authorgroup>
<pubdate>Kasım 2022</pubdate>
<!-- Most recent revision goes at the top; list in descending order -->
<revhistory>
<revision>
<revnumber>15.1</revnumber>
<date>Kasım 2022</date>
<authorinitials>NBB</authorinitials>
<revremark>
PostgreSQL 15.1 ile gelen belgelerden güncellendi.
</revremark>
</revision>
<revision>
<revnumber>8.0.1</revnumber>
<date>Mart 2005</date>
<authorinitials>NBB</authorinitials>
<revremark>
PostgreSQL 8.0.1 ile gelen belgelerden güncelleme yapıldı.
</revremark>
</revision>
<revision>
<revnumber>7.3.2</revnumber>
<date>Temmuz 2003</date>
<authorinitials>knt</authorinitials>
<revremark>
PostgreSQL 7.3.2 ile gelen belgelerden çevrildi.
</revremark>
</revision>
</revhistory>
<copyright>
<year>2005,2022</year>
<holder>Nilgün Belma Bugüner</holder>
</copyright>
<copyright>
<year>2003</year>
<holder>Volkan Yazıcı</holder>
</copyright>
<abstract>
<para>
Bu belgede PostgreSQL'e, ilişkisel veritabanı kavramlarına ve SQL dilinin kavramlarına yabancı olanlar için SQL diline basit bir giriş yapılacaktır.
</para>
</abstract>
<legalnotice>
<para>
Bu çeviriyi, çevirisinin yapıldığı özgün belgeye ilişkin aşağıdaki yasal uyarı, çeviriye ait yukarıdaki telif hakkı bilgileri ve aşağıdaki iki paragrafı tüm kopyalarının başlangıcında içermesi şartıyla, ücretsiz olarak kullanabilir, kopyalayabilir, değiştirebilir ve dağıtabilirsiniz.
</para>
¬ice.disc;
</legalnotice>
<copyright>
<year>1996-2022</year>
<holder>The PostgreSQL Global Development Group</holder>
</copyright>
<legalnotice xml:id="pgsql-legalnotice">
<title>Legal Notice</title>
<para>
<productname>PostgreSQL</productname> is Copyright © 1996-2022 by the PostgreSQL Global Development Group and is distributed under the terms of the license of the University of California below.
</para>
<para>
<productname>Postgres95</productname> is Copyright © 1994-5 by the Regents of the University of California.
</para>
<para>
Permission to use, copy, modify, and distribute this software and
its documentation for any purpose, without fee, and without a
written agreement is hereby granted, provided that the above
copyright notice and this paragraph and the following two paragraphs
appear in all copies.
</para>
<para>
IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY
PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS
SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA
HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</para>
<para>
THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
PROVIDED HEREUNDER IS ON AN <quote>AS-IS</quote> BASIS, AND THE UNIVERSITY OF
CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
</para>
</legalnotice>
</info>
<chapter xml:id="pgsql-tutorial-intro">
<title>Giriş</title>
<para>
<productname>PostgreSQL</productname> Eğitmenine hoşgeldiniz. Sonraki kısımlarda PostgreSQL'e, ilişkisel veritabanı kavramlarına ve SQL dilinin kavramlarına yabancı olanlar için SQL diline basit bir giriş yapılacaktır. Sadece nasıl bilgisayar kullanılacağı üzerine bilginizin olduğu varsayılacaktır. Belli bir Unix veya yazılım geliştirme deneyimi gerekmiyor. Bu belge size genel hatlarıyla <productname>PostgreSQL</productname> üzerinde denetim kurabileceğiniz kadar deneyim kazandırmayı amaçlamaktadır. Konuları ve kapsamı itibariyle kesinlikle tam bir rehber görevi görmeyecektir.
</para>
<para>
Bu belgeyi bitirdikten sonra SQL dili üzerine daha ayrıntılı bilgi için <productname>PostgreSQL</productname> belgelerindeki <link xl:href="http://www.postgresql.org/docs/current/sql.html">The SQL Language</link> belgesine ya da <productname>PostgreSQL</productname> yazılım geliştirme arayüzleri hakkında daha geniş bilgi için <productname>PostgreSQL</productname> belgelerindeki <link xl:href="http://www.postgresql.org/docs/current/client-interfaces.html">Client Interfaces</link> belgesine bakılabilir. Kendi sunucularını kurup yönetecek kişiler ayrıca <productname>PostgreSQL</productname> belgelerindeki <link xl:href="http://www.postgresql.org/docs/current/admin.html">Server Administration</link> bölümüne bakabilir.
</para>
</chapter>
<chapter xml:id="pgsql-tutorial-start">
<title>Başlangıç</title>
<bridgehead renderas="sect1">Kurulum</bridgehead>
<para>
<productname>PostgreSQL</productname> kullanmadan önce kurulumu gerçekleştirmeniz gerekmekte. <productname>PostgreSQL</productname>, dağıtımınızın kurulumu esnasında yüklenmiş olabileceği gibi, sistem yöneticisi tarafından da önceden kurulmuş olabilir. Böyle bir durumda dağıtımınızın belgelerinden ya da sistem yöneticinizden PostgreSQL'e nasıl ulaşabileceğinize dair bilgileri edinebilirsiniz.
</para>
<para>
PostgreSQL'in kurulu olduğu ya da onu kullanabileceğiniz konusunda emin değilseniz, PostgreSQL'i kendiniz kurabilirsiniz. Kurulum işlemi zor olmamakla birlikte sizin için de iyi bir alıştırma niteliği taşır. <productname>PostgreSQL</productname> her kullanıcı tarafından kurulabilir; ayrıcalıklı kullanıcı (<systemitem>root</systemitem>) hakları gerekmemektedir.
</para>
<para>
Eğer PostgreSQL'i kendiniz kuracaksanız bu konuda PostgreSQL kitabının <link xl:href="http://www.postgresql.org/docs/current/installation.html">Installation from Source Code</link> belgesinde açıklanan kurulumu tamamlayıp, kurulum tamamlandığında buraya dönebilirsiniz. Ortam değişkenlerinin belirlenmesinin anlatıldığı bölüme bakmayı unutmayın.
</para>
<para>
Eğer sistem yöneticiniz kurulum işlemlerini öntanımlı yoldan yapmadıysa biraz daha yapacak işiniz var demektir. Örneğin eğer sunucu makineniz uzakta bir sistem ise, <envar>PGHOST</envar> ortam değişkenine veritabanı sunucusunun ismini atamalısınız. Ayrıca, <envar>PGPORT</envar> ortam değişkenine de atama yapmanız gerekebilir. Son olarak, eğer çalıştırmayı denediğiniz bir uygulama veritabanına bağlanamadığını belirten bir hata iletisi veriyorsa; sistem yöneticiniz ile bağlantı kurmayı deneyin, eğer yönetici siz iseniz, belgeleri tekrar gözden geçirip çalışma ortamını doğru ayarlayıp ayarlamadığınıza bir kez daha bakın. Eğer bir önceki paragraf yararlı olmadıysa bir sonraki bölümü okuyun.
</para>
<sect1 xml:id="pgsql-tutorial-arch">
<title>Mimarinin Temelleri</title>
<para>
Daha ileri bölümleri okumadan önce, PostgreSQL'in temel sistem mimarisini anlamanızda yarar var. <productname>PostgreSQL</productname> bölümlerinin birbirleri ile nasıl ilişki içinde olduğunu anlamanız yönünde bu kısım bir derece de olsa yararlı olacaktır.
</para>
<para>
<productname>PostgreSQL</productname>, veritabanı dilinde sunucu/istemci temeline dayanan bir sistem kullanmaktadır. Bir <productname>PostgreSQL</productname> oturumu birbirleriyle ilişkili çalışan şu süreçlerden oluşur:
</para>
<itemizedlist>
<listitem>
<para>
Veritabanı dosyalarını yöneten bir sunucu süreci istemci uygulamalarından gelen bağlantıları kabul eder ve istenilen işlemleri onlar adına gerçekleştirir. Veritabanı sunucu uygulamasının ismi <userinput>postmaster</userinput>'dır.
</para>
</listitem>
<listitem>
<para>
Kullanıcının istemci uygulaması veritabanında sorgulamanın gerçekleşmesini isteyen uygulamadır. İstemci uygulamaları çok çeşitlidir: salt metin (text) tabanlı bir istemci aracı, grafiksel arayüzlü bir uygulama, veritabanına bağlanıp ilgili HTML sayfaları olarak göstercek bir HTTP sunucusu veya özelleşmiş bir veritabanı onarım aracı. Bazı istemci uygulamaları <productname>PostgreSQL</productname> dağıtımları ile sağlanmakta olup çoğu da kullanıcılar tarafından geliştirilmektedir.
</para>
</listitem>
</itemizedlist>
<para>
Genellikle, sunucu/istemci uygulamalarında, sunucu ve istemci ayrı makinelerde olur. Böyle bir durumda birbileri ile TCP/IP ağ bağlantısı üzerinden haberleşir. Bir istemci makinenin erişebildiği dosyaların veritabanı sunucusu olan makine üzerinde erişilebilir olamayabileceğini (ya da farklı bir dosya ismi ile erişilebilineceğini) aklınızdan çıkarmayın.
</para>
<para>
PostgreSQL sunucusu çoklu istemci bağlantılarına izin verebilmektedir. Bu amaçla her yeni bağlantı için yeni bir süreç başlatır. Bu noktada, istemci ve yeni sunucu süreci özgün <userinput>postmaster</userinput> süreciyle etkileşime girmeden haberleşebilir. Bu arada, <userinput>postmaster</userinput> istemci bağlantılarını bekler, istemcileri ilgili sunucu süreci ile ilişkilendirmeye çalışır. (Tabii ki, bunların hepsi kullanıcıdan habersiz olarak artalanda gerçekleşir. İşlemin nasıl gerçekleştiğini bilin istedik.)
</para>
</sect1>
<sect1 xml:id="pgsql-tutorial-createdb">
<title>Bir Veritabanının Oluşturulması</title>
<para>
Veritabanına sunucusuna erişiminiz olup olmadığını görmek için yapılacak ilk sınama bir veritabanı oluşturmaya çalışmaktır. Çalışan bir <productname>PostgreSQL</productname> sunucusu çok sayıda veritabanını yönetebilir. Genellikle, her proje ya da her kullanıcı için ayrı bir veritabanı kullanılır.
</para>
<para>
Muhtemelen, sistem yöneticiniz sizin için bir veritabanını zaten oluşturmuştur ve size oluşturduğu veritabanı ismini de söylemiştir. Böyle bir durumda bu adımı geçerek bir sonraki bölüme bakabilirsiniz.
</para>
<para>
Bu örnekte, yeni bir veritabanını <literal>mydb</literal> ismiyle şöyle oluşturabilirsiniz:
</para>
<screen><prompt>$</prompt> <userinput>createdb -e mydb</userinput>
</screen>
<para>
Çıktısının şöyle olması lazım:
</para>
<screen>SELECT pg_catalog.set_config('search_path', '', false);
CREATE DATABASE mydb;
</screen>
<para>
Bu çıktıyı alıyorsanız, bu adım tamamlanmış demektir.
</para>
<para>
Ama, <userinput>createdb</userinput> komutunun bulunamadığına ilişkin, şöyle bir çıktı alıyorsanız,
</para>
<screen>createdb: command not found
</screen>
<para>
<productname>PostgreSQL</productname> olması gerektiği gibi kurulmamış demektir. Ya hiç kurulum yapılmamıştır ya da dosya arama yolları (<envar>$PATH</envar>) doğru yapılandırılmamıştır. Komutu dosya yolunu belirterek kullanmayı deneyin:
</para>
<screen><prompt>$</prompt> <userinput>/usr/local/pgsql/bin/createdb mydb</userinput>
</screen>
<para>
Bu dosya yolu sisteminizde farklı olabilir. Böyle bir durumda sistem yöneticisi ile bağlantı kurmayı deneyin ya da kurulum adımlarını tekrar gözden geçirip sorunu tespit etmeye çalışın.
</para>
<para>
Çıktı şöyle de olabilirdi:
</para>
<screen>createdb: error: connection to server on socket "/tmp/.s.PGSQL.5432" failed: No such file or directory
Is the server running locally and accepting connections on that socket?
</screen>
<para>
Böyle bir hatanın anlamı ya sunucu başlatılmamıştır ya da <userinput>createdb</userinput> sunucunun aradığı yerde değildir. Kurulum adımlarını yeniden gözden geçirin ya da sistem yöneticisi ile temasa geçin.
</para>
<para>
Yanıt şöyle de olabilirdi:
</para>
<screen>createdb: hata: template1 veritabanına bağlanılamadı: ÖLÜMCÜL (FATAL): "nilgun" rolü mevcut değil
</screen>
<para>
Burada "nilgun" yerine sizin kullanıcı isminiz görünecektir. Bu, sistem yöneticinizin sizin için bir <productname>PostgreSQL</productname> kullanıcısı hesabı açmadığı anlamına gelir. (<productname>PostgreSQL</productname> kullanıcı hesapları, sistem kullanıcı hesaplarından ayrıdır.) Eğer sistem yöneticisi sizseniz, hesapların oluşturulması ile ilgili bilgi edinmek için PostgreSQL belgelerindeki <link xl:href="http://www.postgresql.org/docs/current/user-manag.html">Veritabanı Kullanıcıları ve Grupları</link> kısmına bakın. İlk kullanıcı hesabını oluşturmak için PostgreSQL'i kuran işletim sistemi kullanıcısı (genellikle bu kullanıcı <literal>postgres</literal>'dir) olmanız gerekecektir:<footnote><para/>
<screen>$ sudo su postgres
$ createuser --interactive <kullanıcı>
</screen>
</footnote></para>
<para>
İsterseniz, bu amaçla, bir sistem kullanıcı isminden farklı bir <productname>PostgreSQL</productname> kullanıcı ismini de kullanabilirsiniz; <productname>PostgreSQL</productname> kullanıcı isminini belirtmek için ya <option>-U</option> seçeneğini kullanmalı ya da bu ismi <envar>PGUSER</envar> ortam değişkenine atamalısınız.
</para>
<para>
Eğer bir kullanıcı hesabınız varsa, ama bir veritabanı oluşturma izniniz yoksa, şöyle bir çıktı alacaksınız:
</para>
<screen>SELECT pg_catalog.set_config('search_path', '', false);
CREATE DATABASE mydb;
createdb: hata: veritabanı yaratma başarısız oldu: HATA: veritabanı oluşturmaya izin verilmedi.
</screen>
<para>
Her kullanıcının yeni bir veritabanı oluşturma yetkisi yoktur. Eğer <productname>PostgreSQL</productname> sizin veritabanı oluşturma isteğinizi geri çeviriyorsa, sistem yöneticisinin size gerekli izinleri vermesi gerekmektedir. Böyle bir durumda sistem yöneticisi ile temasa geçin. Eğer sistem yöneticisi siz iseniz böyle bir izin işlemi için sunucuyu hangi kullanıcı ile başlatmışsanız onun ile sisteme giriş yapın ve bu eğiticiyi okuyup uygulamak isteyenlere gerekli hakları tanıyın.<footnote>
<para>
Bunun neden böyle çalıştığına dair açıklama: <productname>PostgreSQL</productname> kullanıcı isimleri sistem kullanıcı isimlerinden bağımsızdır. Eğer bir veritabanına bağlanıyorsanız, hangi <productname>PostgreSQL</productname> kullanıcı adı ile bağlanacağınızı belirtebilirsiniz; bunu yapmazsanız, sistem kullanıcısı isminiz öntanımlı <productname>PostgreSQL</productname> kullanıcı isminiz olarak kullanacaktır. Böyle bir durumda veritabanı sunucusunu başlatan kullanıcı ile aynı isme sahip bir <productname>PostgreSQL</productname> kullanıcısı olacaktır ve böyle bir durumda bu kullanıcı her zaman veritabanı oluşturma izinlerine sahip olacaktır. Her seferinde o kullanıcı ile sisteme girmektense <option>-U</option> seçeneği ile PostgreSQL'e bağlanmak istediğiniz kullanıcı adını belirtebilirsiniz.
</para>
</footnote>
</para>
<para>
İsterseniz başka isimler ile de veritabanları oluşturabilirsiniz. <productname>PostgreSQL</productname> istediğiniz sayıda veritabanı oluşturma imkanını sunmaktadır. Veritabanı isminin ilk karakteri bir harf olmalı ve isim 63 bayttan daha uzun olmamalıdır. Tercihen kullanıcı adınız ile aynı ismi taşıyan veritabanları oluşturulması tavsiye olunur. Çoğu araç, böyle bir veritabanı ismini öntanımlı olarak kabul eder ve bu sizi az da olsa yazmaktan kurtarır. Yeni bir veritabanı oluşturmak için, basitçe şunu yazın:
</para>
<screen><prompt>$</prompt> <userinput>createdb</userinput>
</screen>
<para>
Eğer veritabanınızı artık kullanmak istemiyorsanız onu kaldırabilirsiniz. Örnek olarak, eğer siz <literal>mydb</literal> adlı veritabanının sahibi iseniz, bunu şöyle silebilirsiniz:
</para>
<screen><prompt>$</prompt> <userinput>dropdb mydb</userinput>
</screen>
<para>
(Bu komut için, veritabanı ismi öntanımlı olarak kullanıcı ismi değildir. Daima bu ismi belirtmeniz gerekir.) Bu işlem sonucunda fiziksel olarak veritabanınız ile ilgili bütün dosyalar silinecektir ve veritabanınızı geri alamayacaksınız. Bu yüzden bu komutu uygulamadan önce kararınızı tekrar gözden geçirmeniz tavsiye olunur.
</para>
<para>
<userinput>createdb</userinput> ve <userinput>dropdb</userinput> hakkında daha fazla bilgi edinmek için PostgreSQL belgelerindeki <link xl:href="http://www.postgresql.org/docs/current/app-createdb.html">createdb</link> ve <link xl:href="http://www.postgresql.org/docs/current/app-dropdb.html">dropdb</link> komutlarının açıklamalarına bakınız.
</para>
</sect1>
<sect1 xml:id="pgsql-tutorial-accessdb">
<title>Bir Veritabanına Erişim</title>
<para>
Veritabanını oluşturduktan sonra, ona şöyle erişebilirsiniz:
</para>
<itemizedlist>
<listitem>
<para><userinput>psql</userinput> adlı etkileşimli <productname>PostgreSQL</productname> uçbirim uygulaması ile veritabanına giriş yapıp, istediğiniz işlemleri gerçekleştirir ve SQL komutlarınızı çalıştırabilirsiniz.
</para>
</listitem>
<listitem>
<para>
<application>pgAdmin</application> gibi çizgesel arayüzlü bir uygulama ya da <acronym>ODBC</acronym> veya <acronym>JDBC</acronym> destekli ofis yazılımlarını kullanarak veritabanı oluşturabilir ve üzerinde işlem yapabilirsiniz. Bu tür uygulamalar ve kullanımları bu eğitmenin kapsamı dışındadır.
</para>
</listitem>
<listitem>
<para>
Uygun yazılım geliştirme dilleri ile kendi uygulamalarınızı da yazabilirsiniz. Bu konu hakkında ayrıntılı bilgiyi <productname>PostgreSQL</productname> belgelerindeki <link xl:href="http://www.postgresql.org/docs/current/client-interfaces.html">Client Interfaces</link> belgesinde bulabilirsiniz.
</para>
</listitem>
</itemizedlist>
<para>
Bu belgedeki alıştırmaları denemek için muhtemelen <userinput>psql</userinput>'i kullanmak isteyeceksiniz. <userinput>psql</userinput>'i <literal>mydb</literal> adlı veritabanına erişmek için şu şekilde başlatabilirsiniz:
</para>
<screen><prompt>$</prompt> <userinput>psql mydb</userinput>
</screen>
<para>
Eğer bir veritabanı ismi belirtmezseniz öntanımlı olarak kullanıcı adınız ile aynı ismi taşıyan veritabanına erişilmeye çalışılacaktır. Bunu önceki bölümde <command>createdb</command> kullanarak keşfetmiştik.
</para>
<para>
<userinput>psql</userinput> sizi aşağıdaki gibi bir çıktı ile karşılayacaktır:
</para>
<screen>psql (15.1)
Yardım için "help" yazınız.
mydb=>
</screen>
<para>
Son satır şu şekilde de olabilir:
</para>
<screen>mydb=#
</screen>
<para>
Bunun anlamı, çoğunlukla olduğu gibi eğer PostgreSQL'i kendiniz kurduysanız, veritabanının en yetkili kullanıcısı olduğunuz anlamına gelir. En yetkili kullanıcı olmak, hiçbir izin işlemine tabi tutulmayacağınız anlamına gelir. Fakat bu konu bu eğitmenin kapsamında değildir.
</para>
<para>
Eğer <userinput>psql</userinput>'i çalıştırmakta sorun yaşarsanız önceki bölüme dönün. <userinput>psql</userinput> ile <userinput>createdb</userinput> arasında çalıştırma sorunlarına tanı konulması bakımından fark yoktur. Eğer <userinput>createdb</userinput> çalışıyorsa, <userinput>psql</userinput>'in de çalışması gerekir.
</para>
<para>
Son satırda yer alan <literal>mydb=></literal> komut satırı <userinput>psql</userinput>'in kendi çalışma alanı içine <acronym>SQL</acronym> sorguları yazmanızı beklediği anlamına gelir. Şu komutları deneyiniz:
</para>
<screen><prompt>mydb=></prompt><userinput>SELECT version();</userinput>
version
-------------------------------------------------------------------------------
PostgreSQL 15.1 on x86_64-pc-linux-gnu, compiled by gcc 10.2.1 20210110, 64-bit
(1 satır)
<prompt>mydb=></prompt> <userinput>SELECT current_date;</userinput>
current_date
--------------
2022-11-26
(1 satır)
<prompt>mydb=></prompt> <userinput>SELECT 2 + 2;</userinput>
?column?
----------
4
(1 satır)
</screen>
<para>
Bunun dışında <userinput>psql</userinput> kendine ait, standart <acronym>SQL</acronym> komutu olmayan, bir kaç dahili komuta daha sahiptir. Bu tür komutlar bir tersbölü karakteri (<userinput>\</userinput>) ile başlar. Örnek olarak, çeşitli <productname>PostgreSQL</productname> <acronym>SQL</acronym> komutları hakkında yardım almak için şunu yazabilirsiniz:
</para>
<screen><prompt>mydb=></prompt> <userinput>\h</userinput>
</screen>
<para>
<userinput>psql</userinput>'den çıkmak için şunu kullanabilirsiniz:
</para>
<screen><prompt>mydb=></prompt> <userinput>\q</userinput>
</screen>
<para>
Böylece <userinput>psql</userinput>'den çıkıp sistemin komut satırına geri döneceksiniz. (Daha fazla dahili komut için psql satırında <userinput>\?</userinput> komutunu kullanabilirsiniz.) <userinput>psql</userinput>'in tam olarak ne yapabildiği hakkında ayrıntılı bilgiyi <productname>PostgreSQL</productname> belgelerindeki <link xl:href="http://www.postgresql.org/docs/current/app-psql.html">psql kılavuz sayfasına</link> bulabilirsiniz. Bu eğitmende bu özelliklerin hepsine değinmeyeceğiz ama kendiniz hepsini deneyebilirsiniz.
</para>
</sect1>
</chapter>
<chapter xml:id="pgsql-tutorial-sql">
<title><acronym>SQL</acronym> Dili</title>
<para>
Bu kısımda basit işlemleri uygulamak için <acronym>SQL</acronym> kullanımına kısaca değineceğiz. Verilecek <acronym>SQL</acronym> bilgisi bir başlangıç niteliği taşımaktadır, kesinlikle tam bir <acronym>SQL</acronym> eğitmeni değildir. <acronym>SQL</acronym> dili üzerine sayısız kitap yazılmıştır, bunlar arasından <link xl:href="http://www.postgresql.org/docs/current/biblio.html#MELT93">Understanding the New SQL</link> ve <link xl:href="http://www.postgresql.org/docs/current/biblio.html#DATE97">A Guide to the SQL Standard</link> örnek gösterilebilir. Bazı PostgreSQL dil özelliklerinin <acronym>SQL</acronym> belirtiminden fazlasını içerdiğini bilmenizde yarar var.
</para>
<para>
Bu kısımdaki örneklerde, önceki bölümde <userinput>psql</userinput>'i başlatırken kullandığınız, <literal>mydb</literal> isimli veritabanını oluşturmuş olduğunuz varsayılmıştır.
</para>
<para>
Bu belgedeki örnekleri ayrıca PostgreSQL kaynak paketinde yer alan <filename>src/tutorial/</filename> dizininde de bulabilirsiniz. Bu dosyaları kullanmaya başlamadan önce dizine girip <userinput>make</userinput> komutunu vermelisiniz:
</para>
<screen><prompt>$</prompt> <userinput>cd <replaceable>...</replaceable>/src/tutorial</userinput>
<prompt>$</prompt> <userinput>make</userinput>
</screen>
<para>
Böylece, kullanıcı tanımlı işlevlerle türleri içeren C dosyaları derlenmiş ve betikler oluşturulmuş olur. (Bu işlem için GNU <userinput>make</userinput> kullanılmalıdır. Eğitmeni şöyle başlatabilirsiniz:
</para>
<screen><prompt>$</prompt> <userinput>psql -s mydb</userinput>
<computeroutput>
...
</computeroutput>
<prompt>mydb=></prompt> <userinput>\i basics.sql</userinput>
</screen>
<para>
Buradaki <userinput>\i</userinput> komutu, komutları belirtilen dosyadan okur. <command>psql</command>'in <literal>-s</literal> seçeneği sizi, her komutu sunucuya göndermeden önce bekleyen tek adımlık kipe sokar. Bu bölümde kullanılmış olan komutları <filename>basics.sql</filename> dosyasında bulabilirsiniz. (Komutları kolayca ayrımsamak için aşağıdaki örnekler kısmen türkçeye çevrilerek alıntılanmıştır.)
</para>
<sect1 xml:id="pgsql-tutorial-concepts">
<title>Kavramlar</title>
<para>
<productname>PostgreSQL</productname> bir ilişkisel veritabanı yönetim sistemidir (RDBMS - Relational Database Management System). Bunun anlamı, PostgreSQL'in veriler arasındaki ilişkileri yöneten bir sistem olduğudur. Burada bahsedilen <wordasword>ilişki</wordasword> (relation) aslında <wordasword>tablo</wordasword> karşılığı bir matematik terimidir. Verinin tablolarda saklanması olayı günümüzde gayet olağan gibi görünürse de veritabanlarının organize edilmesi için daha pek çok yol vardır. Unix türevi işletim sistemlerindeki dosya/dizin yapısı hiyerarşik veritabanlarına güzel bir örnektir. Günümüzde daha gelişmiş bir veritabanı türü de nesne yönelimli veritabanlarıdır.
</para>
<para>
Her tablo satırlardan oluşur. Ve her <wordasword>satır</wordasword> kendi içinde, belli veri türlerine özel <wordasword>sütun</wordasword>lara ayrılmıştır. Sütunlar her satırda aynı sayıda ve sırada olmasına karşın, SQL aynı şeyi satır sıralaması için garanti etmez (yine de çıktı alırken isteğe bağlı olarak sıralandırılabilir).
</para>
<para>
Tablolar veritabanları halinde gruplanır ve tek bir <productname>PostgreSQL</productname> sunucu süreci tarafından yönetilen veritabanları bir veritabanı <wordasword>küme</wordasword>si oluşturur.
</para>
</sect1>
<sect1 xml:id="pgsql-tutorial-table">
<title>Yeni bir Tablonun Oluşturulması</title>
<para>
Yeni bir tabloyu, tablo ismini ve içerdiği sütün isimlerini veri türleri ile birlikte belirterek oluşturabilirsiniz:
</para>
<screen>CREATE TABLE hava_durumu (
il varchar(80),
asg_sck int, -- en düşük sıcaklık
azm_sck int, -- en yüksek sıcaklık
yağış real, -- yağış miktarı
tarih date
);
</screen>
<para>
Bu komut listesini <userinput>psql</userinput> komut satırına aynen buradaki gibi girebilirsiniz (alt satıra geçmek için <enter>'a basmanız yeterli olacaktır). <userinput>psql</userinput> en sonda yer alan noktalı virgülü görene kadar komutun bitmediğini anlayacaktır.
</para>
<para>
SQL komutları içinde boşluklar (boşluk karakteri, sekme ve satırsonu karakteri) özgürce kullanılabilir. Yani, yukarıdaki komut listesini siz istediğiniz gibi yazabilirsiniz; hatta hepsini tek bir satıra dahi girebilirsiniz. Yanyana gelen iki tire ("<literal>--</literal>") açıklama satırları için kullanılır. Bu işaretten sonra yazılan her şey o satırın sonuna kadar ihmal edilecektir. SQL komutlarının normalde büyük-küçük harf duyarlılığı yoktur. Duruma bağlı olarak değişkenlerin çift tırnak içine alınması onların büyük-küçük harf duyarlı olduğunu gösterir (Yukarıda bu yöntem kullanılmamıştır).
</para>
<para>
<literal>varchar(80)</literal> 80 karakter uzunluğundaki bir dizgeyi tutabilecek bir veri türü belirtir. <literal>int</literal> normal bir tamsayıyı niteler. <literal>real</literal> tek hassasiyetli (single precision) gerçel sayılar için kullanılır. <literal>date</literal> alanı da adından anlaşılacağı üzere tarih saklamak için kullanılır.
</para>
<para>
<productname>PostgreSQL</productname> standart <acronym>SQL</acronym> veri türlerinden <literal>int, smallint, real, double, char(<replaceable>N</replaceable>), varchar(<replaceable>N</replaceable>), date, time, timestamp</literal> ve <literal>interval</literal> ile birlikte diğer genel araç türleriyle zengin bir geometrik tür ailesini destekler. <productname>PostgreSQL</productname> sınırsız sayıda kullanıcı tanımlı veri türü ile özelleştirilebilir. Dolayısla, tür isimleri <acronym>SQL</acronym> standardındaki özel durumların desteklenmesinin gerektiği yerler dışında sözdizimsel anahtar sözcükler değildir.
</para>
<para>
İkinci örnek, il isimlerini ve bulundukları coğrafik bölgeleri saklayacaktır:
</para>
<screen>CREATE TABLE iller (
ad varchar(80),
konum point
);
</screen>
<para>
Buradaki <literal>point</literal>, PostgreSQL'e özel veri türüne bir örnektir.
</para>
<para>
Son olarak, eğer bir tabloya artık ihtiyacınız kalmadıysa ya da onu baştan oluşturmak istiyorsanız şu komutu kullanabilirsiniz:
</para>
<para>
<command>DROP TABLE</command> <replaceable>tabloismi</replaceable>;
</para>
</sect1>
<sect1 xml:id="pgsql-tutorial-populate">
<title>Tablolara Satırların Girilmesi</title>
<para>
<literal>INSERT</literal> cümlesi tablolara veri girişi için kullanılır:
</para>
<screen>INSERT INTO hava_durumu VALUES ('San Francisco', 46, 50, 0.25, '1994-11-27');
</screen>
<para>
Veri giriş işlemlerinde tüm verilerin açıkça belirtilmesi gerekir. Sabitler sadece basit rakamsal değerler değildir, örnekte görüldüğü gibi tek tırnak içine alınıp belirtilmeleri şarttır. <literal>date</literal> türü esnek bir çeşit olduğundan neredeyse girilen tüm tarih çeşitlerini kabul eder. Fakat biz bu belgede belirsizlik yaratmaması açısından bu örnekteki biçimi kullanacağız.
</para>
<para>
<literal>point</literal> veri türü için bir koordinat çiftine ihtiyacımız olacak:
</para>
<screen>INSERT INTO iller VALUES ('San Francisco', '(-194.0, 53.0)');
</screen>
<para>
Çok sayıda sütun olduğunda bilginin hangi sırada girileceğini hatırlamanız zorlaşır. Sütun isimlerinin de belirtilebileceği bir sözdizimi bunu kolaylaştırır:
</para>
<screen>INSERT INTO hava_durumu (il, asg_sck, azm_sck, yağış, tarih)
VALUES ('San Francisco', 43, 57, 0.0, '1994-11-29');
</screen>
<para>
İsterseniz, yukarıda bahsedilen yöntemi kullanarak verileri gireceğiniz sütunların yerlerini değiştirebilir ya da hiç yokmuş gibi farzedebilirsiniz, örneğin yağış miktarını yoksayalım:
</para>
<screen>INSERT INTO hava_durumu (tarih, il, azm_sck, asg_sck)
VALUES ('1994-11-29', 'Hayward', 54, 37);
</screen>
<para>
Birçok geliştirici mevcut sütun sırasına göre veri girmektense sıralamayı açıkça belirtmeyi tercih eder.
</para>
<para>
Lütfen yukarıdaki komutların hepsini girin ki, ileride üzerinde alıştırma yapabileceğimiz bir kaç verimiz olsun.
</para>
<para>
Çok fazla komutu teker teker girmek yerine bunların hepsini tek bir metin dosyasından <literal>COPY</literal> cümlesi ile okutabilirsiniz. <literal>COPY</literal> cümlesi sırf bu amaç için tasarlandığından <literal>INSERT</literal> cümlesine göre daha hızlı çalışmasına karşın, onun kadar esnek değildir. Bir örnek:
</para>
<screen>COPY hava_durumu FROM '/home/user/hava_durumu.txt';
</screen>
<para>
Belirtilen dosya sunucunun erişebileceği bir yerde olmalıdır, istemcinin değil. <literal>COPY</literal> cümlesi hakkında daha fazla bilgi için <productname>PostgreSQL</productname> belgelerindeki <link xl:href="http://www.postgresql.org/docs/current/sql-copy.html"><literal>COPY</literal> cümlesinin açıklamasına</link> bakınız.
</para>
</sect1>
<sect1 xml:id="pgsql-tutorial-select">
<title>Bir Tablonun Sorgulanması</title>
<para>
Bir tablodan verileri almak için tablo <wordasword>sorgulanır</wordasword>. Bunun için bir <acronym>SQL</acronym> cümlesi olan <literal>SELECT</literal> kullanılır. Cümle, bir seçim listesi (istenen sütunları içeren bir liste), bir tablo listesi (verilerin alınacağı tabloların listesi) ve isteğe bağlı bir niteleme (sınırlamaların belirtildiği kısım) içerir. Örneğin, <literal>hava_durumu</literal> tablosundaki satırların tamamını almak için şunu yazın:
</para>
<screen>SELECT * FROM hava_durumu;
</screen>
<para>
Burada <literal>*</literal>, "tüm sütunlar" anlamına gelen bir kısayoldur.<footnote><para><literal>SELECT *</literal> kolay bir sorgulama olarak kullanışlı gibi görünse de, tabloya bir sütun eklemek sonuçları değiştireceğinden uygulamada çoğunlukla kötü bir tarz olarak kabul edilir. </para></footnote>
</para>
<para>
Yani, aynı sonuç böyle de alınacaktır:
</para>
<screen>SELECT il, asg_sck, azm_sck, yağış, tarih FROM hava_durumu;
</screen>
<para>
Çıktı şöyle olmalıdır:
</para>
<screen> il | asg_sck | azm_sck | yağış | tarih
---------------+---------+---------+-------+------------
San Francisco | 46 | 50 | 0.25 | 1994-11-27
San Francisco | 43 | 57 | 0 | 1994-11-29
Hayward | 37 | 54 | | 1994-11-29
(3 satır)
</screen>
<para>
Seçim listesinde sadece sütun isimlerini değil, ifadeleri de kullanabilirsiniz. Örnek:
</para>
<screen>SELECT il, (asg_sck+azm_sck)/2 AS ort_sck, tarih FROM hava_durumu;
</screen>
<para>
Bunun çıktısı şöyle olacaktır:
</para>
<screen> il | ort_sck | tarih
---------------+---------+------------
San Francisco | 48 | 1994-11-27
San Francisco | 50 | 1994-11-29
Hayward | 45 | 1994-11-29
(3 satır)
</screen>
<para>
<literal>AS</literal> deyiminin çıktılanacak sütunu yeniden isimlendirmekte nasıl kullanıldığına dikkat edin. (<literal>AS</literal> deyimi isteğe bağlıdır.)
</para>
<para>
Bir sorgu, istenen satırların yerini belirtmek üzere bir <literal>WHERE</literal> deyimi eklenerek nitelikli yapılabilir. <literal>WHERE</literal> deyimi bir mantıksal ifade içerir ve sadece mantıksal ifadeyi doğrulayan satırlar döndürülür. Niteleme amacıyla mantıksal işleçlere (<literal>AND</literal>, <literal>OR</literal> ve <literal>NOT</literal>) izin verilir. Örneğin, San Francisco'nun yağışlı olduğu günleri bulalım:
</para>
<screen>SELECT * FROM hava_durumu
WHERE il = 'San Francisco' AND yağış > 0.0;
</screen>
<para>
Sonuç:
</para>
<screen> il | asg_sck | azm_sck | yağış | tarih
---------------+---------+---------+-------+------------
San Francisco | 46 | 50 | 0.25 | 1994-11-27
(1 satır)
</screen>
<para>
Sorgu sonucunun sıralanmış olmasını da isteyebilirsiniz:
</para>
<screen>SELECT * FROM hava_durumu
ORDER BY il;
</screen>
<para>Sonuç:</para>
<screen> il | asg_sck | azm_sck | yağış | tarih
---------------+---------+---------+-------+------------
Hayward | 37 | 54 | | 1994-11-29
San Francisco | 46 | 50 | 0.25 | 1994-11-27
San Francisco | 43 | 57 | 0 | 1994-11-29
(3 satır)
</screen>
<para>
Bu örnekte, sıralamanın nasıl yapılacağı tam olarak belirtilmemiştir, dolayısıyla hangi San Fransisco satırının önce geleceği belli olmaz. Fakat aşağıdaki sorgu daima bu sıralamayla dönecektir.
</para>
<screen>SELECT * FROM hava_durumu
ORDER BY il, asg_sck;
</screen>
<para>
Bir sorgunun sonucundan yinelenmiş satırların kaldırılmasını isteyebilirsiniz:
</para>
<screen>mydb=> SELECT DISTINCT il
FROM hava_durumu;
</screen>
<para>Sonuç:</para>
<screen> il
---------------
Hayward
San Francisco
(2 satır)
</screen>
<para>
Burada da yine satırların sırası her sorguda farklı olabilir. Sonucun istediğimiz sırada olmasını <literal>DISTINCT</literal> ve <literal>ORDER BY</literal> deyimlerini birlikte kullanarak sağlayabilirsiniz<footnote>
<para>
Bazı veritabanı sistemlerinde ve PostgreSQL'in eski sürümlerinde <literal>DISTINCT</literal> gerçeklenimi sıralamayı özdevimli yaptığından <literal>ORDER BY</literal> gereksizdir. Fakat bunun böyle olması SQL standardının bir zorlaması değildir ve şimdiki <productname>PostgreSQL</productname> <literal>DISTINCT</literal> deyiminin satırları sıralayacağını garanti etmemektedir.
</para></footnote>:
</para>
<screen>SELECT DISTINCT il
FROM hava_durumu
ORDER BY il;
</screen>
</sect1>
<sect1 xml:id="pgsql-tutorial-join">
<title>Tablolar Arası Katılım</title>
<para>
Buraya kadar, yaptığımız sorgulamalarda her seferinde sadece bir tabloya erişildi. Oysa sorgulamalar aynı andan birden çok tabloya erişebildiği gibi, aynı tabloya birden fazla kez erişerek satırlara daha çeşitli yaptırımlar uygulayabilir. Aynı anda birden fazla satır ya da birden fazla tabloya erişen sorgulara <wordasword>katılımlı sorgu</wordasword> denir. Sözgelimi (daha önce oluşturduğumuz tablolardaki) tüm illerin hava durumlarını ve konumlarını aynı anda listelemek istiyoruz. Bunun için <literal>hava_durumu</literal> tablosundaki tüm <literal>il</literal> sütunları ile <literal>iller</literal> tablosundaki tüm <literal>ad</literal> sütunlarını karşılaştırıp, aynı olan satır çiftlerini seçmek gerekir.
</para>
<note>
<para>
Bu sadece kavramsal bir modeldir. Katılımlı sorgular, aslında, her olası satır çiftini karşılaştırmaktan biraz daha verimli bir anlamda uygulanır ama bu işlemi kullanıcı görmez.
</para>
</note>
<para>
Yukarıda bahsedilen işlemi şu sorgu ile elde edebiliriz:
</para>
<screen>SELECT * FROM hava_durumu JOIN iller ON il = ad;
</screen>
<para>Sonuç:</para>
<screen> il | asg_sck | azm_sck | yağış | tarih | ad | konum
---------------+---------+---------+-------+------------+---------------+-----------
San Francisco | 46 | 50 | 0.25 | 1994-11-27 | San Francisco | (-194,53)
San Francisco | 43 | 57 | 0 | 1994-11-29 | San Francisco | (-194,53)
(2 satır)
</screen>
<para>
Çıktıda dikkat edilmesi gereken iki nokta bulunmakta:
</para>
<itemizedlist>
<listitem>
<para>
Haywrad şehri için hiçbir çıktı alınmadı dikkat edildiyse. Bunun nedeni ise <literal>iller</literal> tablosunda Hayward adlı bir il olmaması ve dolayısıyla <literal>JOIN</literal> bu şehri eledi. İleride bunun nasıl düzeltilebileceği üzerinde durulacak.
</para>
</listitem>
<listitem>
<para>
Bir diğer dikkat çeken nokta ise, illerin adını yazan iki tane sütun olması. Bunun sebebi <literal>hava_durumu</literal> ve <literal>iller</literal> tablosunun birleştirilmesidir. Pratikte bu istenmeyen bir sonuçtur. Böyle bir durumda buna neden olan <literal>*</literal> ifadesi yerine açıkça listelenmesini istediğimiz sütunları yazarak bu işi halledebiliriz:
</para>
<screen>SELECT il, asg_sck, azm_sck, yağış, tarih, konum
FROM hava_durumu JOIN iller ON il = ad;
</screen>
</listitem>
</itemizedlist>
<para>
Tablolardaki tüm sütun isimleri farklı olduğundan çözümleyici hangi ismin hangi tabloya ait olduğunu bulur. Ama bunu daha da açıkça belirtmek isimler aynı olduğunda dahi sorun çıkmasını önler ve tavsiye edilen de budur:
</para>
<screen>SELECT hava_durumu.il, hava_durumu.asg_sck, hava_durumu.azm_sck,
hava_durumu.yağış, hava_durumu.tarih, iller.konum
FROM hava_durumu JOIN iller ON hava_durumu.il = iller.ad;
</screen>
<para>
Birleştirme sorgusundaki tüm sütun adlarını nitelemek yaygın olarak iyi bir uygulama olarak kabul edilir, böylece daha sonra tablolardan birine yinelenen sütun adlarından biri eklenirse sorgu başarısız olmaz.
</para>
<para>
Şimdiye kadar gördüğümüz katılım sorguları ayrıca şu şekilde de yazılabilir:
</para>
<screen>SELECT *
FROM hava_durumu, iller
WHERE il = ad;
</screen>
<para>
Bu sözdizimi, SQL-92'de tanıtılan <literal>JOIN</literal>/<literal>ON</literal> sözdizimine dayanır. Tablolar basitçe <literal>FROM</literal> deyiminde listelenir ve karşılaştırma ifadesi <literal>WHERE</literal> deyimine eklenir. Bu eski örtük sözdiziminden ve daha yeni açık <literal>JOIN</literal>/<literal>ON</literal> sözdiziminden elde edilen sonuçlar aynıdır. Ancak sorgunun okuyucusu için, açık sözdizimi anlamını anlamayı kolaylaştırır: Daha önce koşul, diğer koşullarla birlikte <literal>WHERE</literal> deyimine karıştırılmışken, birleştirme koşulu kendi anahtar sözcüğüyle tanıtılır.
</para>
<para>
Şimdi Hayward kayıtlarına nasıl kavuşacağımızı işleyeceğiz. İstediğimiz şey <literal>hava_durumu</literal> tablosu üzerinde tarama yapıp, <literal>iller</literal> tablosunda bunlarla eşleşen satırları bulmak. Eğer <literal>iller</literal> tablosunda herhangi bir eşleşme bulamazsak, o sütun <literal>iller</literal> tablosu alanında boş gözükecek. Bu tür sorgulama işlemleri <wordasword>haricen katılım</wordasword> (outer join) olarak bilinir. (Şimdiye kadar gördüğümüz katılım sorgularında ise hep <wordasword>dahilen katılım</wordasword> (inner join) kullanmıştık.) Komut şöyle görünür:
</para>
<screen>SELECT *
FROM hava_durumu LEFT OUTER JOIN iller ON hava_durumu.il = iller.ad;
</screen>
<para>Sonuç:</para>
<screen> il | asg_sck | azm_sck | yağış | tarih | ad | konum
---------------+---------+---------+-------+------------+---------------+-----------
San Francisco | 46 | 50 | 0.25 | 1994-11-27 | San Francisco | (-194,53)
San Francisco | 43 | 57 | 0 | 1994-11-29 | San Francisco | (-194,53)
Hayward | 37 | 54 | | 1994-11-29 | |
(3 satır)
</screen>
<para>
Bu sorguya <wordasword>sola haricen katılımlı</wordasword> (left outer join) sorgu denir. Böyle adlandırılmasının sebebi soldaki tablonun tüm satırları en az bir kere listelenirken, sağda yer alan tablonun sadece soldaki tablonun satırlarıyla eşleşen satırlarının listelenmesidir. Bir sol-tablo satırı çıktılanırken sağ-tabloda bu satırla eşleşen bir satır yoksa, sağ-tablonun sütunları boş kalır.
</para>
<formalpara><title>Alıştırma:</title>
<para>
Ayrıca, <wordasword>sağa haricen katılımlı</wordasword> (right outer join) ve <wordasword>iki yönlü haricen katılımlı</wordasword> (full outer join) sorgu türleri de var. Bunların ne yaptığını da siz bulmayı deneyin.
</para>
</formalpara>
<para>
Ayrıca, bir tabloyu kendine katılımlı olarak da sorgulayabiliriz ve buna <wordasword>kendine katılımlı</wordasword> sorgu denir. Bir örnek olarak, diğer hava durumu kayıtlarının sıcaklık aralığı içinde kalan hava durumu kayıtlarını bulmak isteyelim. Yani, her <literal>hava_durumu</literal> satırının <literal>asg_sck</literal> ve <literal>azm_sck</literal> sütununu diğer <literal>hava_durumu</literal> satırlarının <literal>asg_sck</literal> ve <literal>azm_sck</literal> sütunu ile karşılaştıracağız. Bunu şu sorgu ile yapabiliriz:
</para>
<screen>SELECT w1.il, w1.asg_sck AS low, w1.azm_sck AS high,
w2.il, w2.asg_sck AS düşük, w2.azm_sck AS yüksek
FROM hava_durumu w1 JOIN hava_durumu w2
ON w1.asg_sck < w2.asg_sck AND w1.azm_sck > w2.azm_sck;
</screen>
<para>Sonuç:</para>
<screen> il | low | high | il | düşük | yüksek
---------------+-----+------+---------------+-------+--------
San Francisco | 43 | 57 | San Francisco | 46 | 50
Hayward | 37 | 54 | San Francisco | 46 | 50
(2 satır)
</screen>
<para>
Burada katılımın sol ve sağ taraflarını ayırabilmek için <literal>hava_durumu</literal> tablosunu <literal>W1</literal> ve <literal>W2</literal> olarak yeniden isimlendirdik. Ayrıca, bu çeşit isimlendirmeleri aynı şeyleri uzun uzadıya yazmaktan kaçınmak için diğer sorgularda da kullanabilirsiniz. Örnek:
</para>
<screen>SELECT *
FROM hava_durumu w JOIN iller c ON w.il = c.name;
</screen>
<para>
Bu tarz kısaltmalarla sıkça karşılaşacaksınız.
</para>
</sect1>
<sect1 xml:id="pgsql-tutorial-agg">
<title>Ortak Değer İşlevleri</title>
<para>
Çoğu ilişkisel veritabanı ürünü gibi PostgreSQL'de ortak değer işlevlerini destekler. Bir ortak değer işlevi çok sayıda satırı girdi olarak alır ve bunlardan tek bir sonuç elde eder. Belli bir satır grubu üzerinde işlem yaparak, bunların sayısını bulan <function>count</function>, değerlerin toplamını bulan <function>sum</function>, değerlerin ortalamasını hesaplayan <function>avg</function>, en büyük ve en küçük değerleri bulan <function>max</function> ve <function>min</function> işlevleri bunlara birer örnektir.
</para>
<para>
Örnek olarak, düşük sıcaklık değerlerinin en yükseğini bulalım:
</para>
<screen>SELECT max(asg_sck) FROM hava_durumu;
</screen>
<para>Sonuç:</para>
<screen> max
-----
46
(1 satır)
</screen>
<para>
Eğer bu sıcaklığın hangi il (veya illerde) ortaya çıktığını bulmak istersek,
</para>
<screen>SELECT il FROM hava_durumu WHERE asg_sck = max(asg_sck); <lineannotation>YANLIŞ</lineannotation>
</screen>
<para>
bu çalışmaz, çünkü <function>max</function> işlevi <literal>WHERE</literal> deyiminde kullanılamaz. (Böyle bir sınırlamanın olmasının sebebi, <literal>WHERE</literal> deyiminin ortak değeri bulunacak satırların belirlenmesinde kullanılmak zorunda olmasıdır; yani, deyim, işlevden önce değerlendirilmiş olmalıdır.) Bu durumda böyle bir sorunu gidermek için sorgunun yeniden durumlanabilmesini sağlayan aşağıdaki gibi bir <wordasword>altsorgu</wordasword> (subquery) kullanılır:
</para>
<screen>SELECT il FROM hava_durumu
WHERE asg_sck = (SELECT max(asg_sck) FROM hava_durumu);
</screen>
<para>Sonuç:</para>
<screen> il
---------------
San Francisco
(1 satır)
</screen>
<para>
Şimdi her şey yolunda. Çünkü ortak değer bulma bir altsorgu ile yapıldıktan sonra sonuç dış sorguda karşılaştırma değeri olarak kullanıldı.
</para>
<para>
Ortak değer işlevleri <literal>GROUP BY</literal> deyimi ile kullanıldığında oldukça yararlıdır. Örneğin her şehrin en yüksek düşük sıcaklığını bulmak için şunu yazabiliriz:
</para>
<screen>SELECT il, max(asg_sck)
FROM hava_durumu
GROUP BY il;
</screen>
<para>Bu bize her il için bir değer verecektir:</para>
<screen> il | max
---------------+-----
Hayward | 37
San Francisco | 46
(2 satır)
</screen>
<para>
Burada, satırlar illere göre gruplanmakta, her gruptaki satırlar üzerinde <literal>max</literal> işlevi hesaplanmakta ve sonuçlar listelenmektedir. Hesaplamaya dahil olacak satırları <literal>HAVING</literal> deyimini kullanarak gruplayabiliriz:
</para>
<screen>SELECT il, max(asg_sck), count(*) FILTER (WHERE asg_sck < 30)
FROM hava_durumu
GROUP BY il
HAVING max(asg_sck) < 40;
</screen>
<para>
Çıktısı:
</para>
<screen> il | max | count
---------+-----+-------
Hayward | 37 | 0
(1 satır)
</screen>
<para>
Sadece <literal>asg_sck</literal> değeri 40'ın altında olan illeri listelemesi dışında bu cümle de aynı sonucu verir. Eğer bir de bu işi abartıp sadece "S" ile başlayan il isimlerini istersek:
</para>
<screen>
SELECT il, max(asg_sck), count(*) FILTER (WHERE asg_sck < 30)
FROM hava_durumu
WHERE il LIKE 'S%' -- <co xml:id="pgsql-co.tutorial-agg-like"/>
GROUP BY il
HAVING max(asg_sck) < 40;
</screen>
<calloutlist>
<callout arearefs="pgsql-co.tutorial-agg-like">
<para>
<literal>LIKE</literal> işleci kalıp eşleştirmesi yapar ve <productname>PostgreSQL</productname> belgelerindeki <link xl:href="http://www.postgresql.org/docs/current/functions-matching.html">Kalıp Eşleme</link> bölümünde açıklanmıştır.
</para>
</callout>
</calloutlist>
<para>
<acronym>SQL</acronym> dilinde <literal>WHERE</literal> ve <literal>HAVING</literal> deyimlerinin ortak değer işlevleri ile nasıl etkileşime girdiğinin anlaşılması önemlidir. <literal>WHERE</literal> ve <literal>HAVING</literal> deyimleri arasındaki temel fark şudur: <literal>WHERE</literal> satırları, gruplar ve ortak değerler hesaplanmadan önce seçer (ortak değer hesaplamasında kullanılacak satırları seçer), <literal>HAVING</literal> deyimi ise ortak değerler hesaplandıktan ve gruplamalar yapıldıktan sonra işleme sokulur. Sonuç olarak, <literal>WHERE</literal> ifadelerinde (altsorgu dışında) ortak değer bulma işlemleri kullanılmazken, <literal>HAVING</literal> deyimlerinde kaçınılmazdır. (Aslında <literal>HAVING</literal> deyimleri içinde ortak değer işlevleri dışında ifadeler de kullanmanıza izin verilmiştir ama, bu biraz savurganlık olur; böyle bir koşulu <literal>WHERE</literal> deyiminde kullanmak daha verimlidir.)
</para>
<para>
Önceki örnekte, <literal>WHERE</literal> deyiminde bir ortak değer bulma işlemine ihtiyaç duyulmadığından, il isimlerine kısıtlama uygulamıştık. Bu, kısıtlamanın <literal>HAVING</literal> ile sağlanmasından daha uygundur; çünkü gruplamanın ve ortak değer hesaplamasının <literal>WHERE</literal> sınamasından geçemeyen satırlar için yapılması gereksizdir.
</para>
</sect1>
<sect1 xml:id="pgsql-tutorial-update">
<title>Verilerin Güncellenmesi</title>
<para>
Mevcut satırları <literal>UPDATE</literal> cümlesini kullanarak güncelleyebilirsiniz. Farzedelim ki, ayın 28'inden sonraki tüm sıcaklıkların 2 derece daha az olması gerektiğini fark ettiniz. Bu güncelleme işlemini şöyle yapabilirsiniz:
</para>
<screen>UPDATE hava_durumu
SET azm_sck = azm_sck - 2, asg_sck = asg_sck - 2
WHERE tarih > '1994-11-28';
</screen>
<para>
Verinin yeni durumuna bakalım:
</para>
<screen>SELECT * FROM hava_durumu;
</screen>
<para>Sonuç:</para>
<screen> il | asg_sck | azm_sck | yağış | tarih
---------------+---------+---------+-------+------------
San Francisco | 46 | 50 | 0.25 | 1994-11-27
San Francisco | 41 | 55 | 0 | 1994-11-29
Hayward | 35 | 52 | | 1994-11-29
(3 satır)
</screen>
</sect1>
<sect1 xml:id="pgsql-tutorial-delete">
<title>Veri Silme</title>
<para>
Bir tablodan satırları silmek için <literal>DELETE</literal> cümlesini kullanabilirsiniz. Hayward'ın hava durumuyla artık ilgilenmediğinizi varsayalım. Tablodan bu satırları silmek için şunu yazabilirsiniz:
</para>
<screen>DELETE FROM hava_durumu WHERE il = 'Hayward';
</screen>
<para>
Böylece, <literal>hava_durumu</literal> tablosundan Hayward ile ilgili kayıtlar silinir.
</para>
<screen>SELECT * FROM hava_durumu;
</screen>
<para>Sonuç:</para>
<screen> il | asg_sck | azm_sck | yağış | tarih
---------------+---------+---------+-------+------------
San Francisco | 46 | 50 | 0.25 | 1994-11-27
San Francisco | 41 | 55 | 0 | 1994-11-29
(2 satır)
</screen>
<para>
Özellikle sakınılması gereken şöyle bir sorgulama da var:
</para>
<para>
<command>DELETE FROM</command> <replaceable>tabloismi</replaceable>;
</para>
<para>
Bir niteleme olmaksızın, <literal>DELETE</literal> cümlesi belirtilen tablodaki <emphasis>bütün</emphasis> satırları silecek, tabloyu boşaltacaktır. Üstelik, sistem bunu yapmadan önce sizden bir doğrulama da istemeyecektir!
</para>
</sect1>
</chapter>
<chapter xml:id="pgsql-tutorial-advanced">
<title>Gelişmiş Özellikler</title>
<para>
Bundan önceki bölümlerde bir <productname>PostgreSQL</productname> veritabanına nasıl veri girilip, onlara nasıl erişileceğini işledik. Bu bölümde ise PostgreSQL'in daha gelişmiş özellikleri olan verileri nasıl daha kolay idare edilebileceği ve veri kaybına ya da bozulma riskine karşı alınacak önlemlerden bahsedeceğiz. En sonunda, PostgreSQL'in bir kaç ek özelliğine göz atma şansımız olacak.
</para>
<para>
Bu kısımda <xref linkend="pgsql-tutorial-sql"/> kısmında gördüğünüz örnekleri çoğaltma ve geliştirme şansınız olacak, ki bu yüzden bu kısmın da dikkatle okunması sizin lehinize olur. Bu bölümden sonraki alıştırmaları ise <filename>tutorial/advanced.sql</filename> dosyasında bulabilirsiniz. Bu dosya ek olarak burada tekrar belirtmeyeceğimiz ama yüklenmesi gereken örnek veriler içermektedir. (<xref linkend="pgsql-tutorial-sql"/> sayfasında dosya kullanımı açıklanmıştır.)
</para>
<sect1 xml:id="pgsql-tutorial-views">
<title>Sanal Tablolar</title>
<para>
Bu bölümü okumadan önce <xref linkend="pgsql-tutorial-join"/> bölümünü okumanızı öneririz. Diyelim ki, uygulamanızda hava durumu kayıtları ile illerin yerlerinin birarada listelenmesi ile çok ilgileniyorsunuz. Bunun için bir sorgu oluşturup bu sorguya isim verebilir ve bu sorguya herhangi bir tabloya erişir gibi erişebilirsiniz.
</para>
<screen>CREATE VIEW myview AS
SELECT ad, asg_sck, azm_sck, yağış, tarih, konum
FROM hava_durumu, iller
WHERE il = ad;
SELECT * FROM myview;
</screen>
<para>Sonuç:</para>
<screen>CREATE VIEW
ad | asg_sck | azm_sck | yağış | tarih | konum
---------------+---------+---------+-------+------------+-----------
San Francisco | 46 | 50 | 0.25 | 1994-11-27 | (-194,53)
San Francisco | 41 | 55 | 0 | 1994-11-29 | (-194,53)
(2 satır)
</screen>
<para>
Sanal tablo kullanımı iyi SQL veritabanı tasarımında önemli bir rol oynar. Sanal tablolar, tablolarınızdaki yapının ayrıntılarını toparlamanızı mümkün kılarak, arkasında kararlı bir arayüz olarak uygulamanızın gelişimini değiştirebilir.
</para>
<para>
Sanal tablolar, gerçek bir tablonun kullanılabildiği hemen her yerde kullanılabilir. Fakat, sanal tabloları başka sanal tablolar oluşturmak için kullanmak pek iyi bir yöntem değildir.
</para>
</sect1>
<sect1 xml:id="pgsql-tutorial-fk">
<title>Anahtarlar</title>
<para>
<xref linkend="pgsql-tutorial-sql"/> kısmındaki <literal>hava_durumu</literal> ve <literal>iller</literal> tablolarını tekrar ele alalım ve <literal>hava_durumu</literal> tablosuna girilecek kayıtlardan <literal>iller</literal> tablosundaki kayıtlarla eşleşmeyecek olanlarının tabloya girilmeyeceğinden emin olmak istediğinizi varsayalım. Buna <wordasword>verilerin göreli bütünlüğünün sağlanaması</wordasword> diyoruz. Basitleştirmeli veritabanı sistemlerinde bu şöyle gerçeklenir: Önce <literal>iller</literal> tablosunda eşleşen bir kaydın olup olmadığına bakılır ve yeni <literal>hava_durumu</literal> kaydının tabloya girilip girilmeyeceğine karar verilir. Bu yaklaşım çok sakıncalı sorunlar içerir, ancak <productname>PostgreSQL</productname> bunu sizin için yapabilir.
</para>
<para>
Tabloların yeni bildirimleri şöyle olurdu:
</para>
<screen>CREATE TABLE iller (
ad varchar(80) primary key,
konum point
);
CREATE TABLE hava_durumu (
il varchar(80) references iller(ad),
asg_sck int,
azm_sck int,
yağış real,
tarih date
);
</screen>
<para>
Şimdi geçersiz bir kaydı girmeye çalışalım:
</para>
<screen>INSERT INTO hava_durumu VALUES ('Berkeley', 45, 53, 0.0, '1994-11-28');
</screen>
<para>Çıktısı:</para>
<screen>HATA: "hava_durumu" tablosu üzerindeki ekleme veya güncelleme işlemi "hava_durumu_il_fkey" foreign key kısıtlamasını ihlal ediyor
AYRINTI: "iller" tablosunda (il)=(Berkeley) anahtarı mevcut değildir.
</screen>
<para>
Anahtarların davranışları uygulamanıza en iyi şekilde uyarlanabilir. Bu eğitmende bu basit örnekten daha ileri gitmeyeceğiz, fakat daha fazla bilgi edinmek isterseniz, <productname>PostgreSQL</productname> belgelerindeki <link xl:href="http://www.postgresql.org/docs/current/ddl.html">Data Definition</link> kısmına bakabilirsiniz. Anahtarları doğru şekilde kullanarak veritabanı uygulamalarınızın kalitesini oldukça arttırabilirsiniz, dolayısıyla anahtar kullanımını iyi öğrenmenizi öneririz.
</para>
</sect1>
<sect1 xml:id="pgsql-tutorial-transactions">
<title>Hareketler</title>
<para>
<wordasword>Hareketler</wordasword> tüm veritabanı sistemlerinin en temel konularından biridir. Bir hareketin başlıca özelliği ya hep ya hiç şeklinde uygulanmak üzere çok sayıda adımın tek bir adım haline getirilmesidir. Hareketi oluşturan adımlar arasındaki işlemler onunla işbirliği yapan diğer hareketlere görünür değildir ve hareketin tamamlanmasını engelleyen bazı olumsuzluklar olduğunda hareketi oluşturan adımların hiçbiri veritabanını etkilemez.
</para>
<para>
Örneğin, bir bankanın şube hesapları (şubeler) olsun ve bu hesaplarda çeşitli müşteri hesapları (hesaplar) ve bu hesaplarda da bir miktar nakit bulunsun. Ayşe'nin hesabından 100.00 lirayı Ali'ın hesabına geçirmek istediğimizi kabul edelim. Son derece basitleştirerek, SQL komutları şöyle olurdu:
</para>
<screen>UPDATE hesaplar SET nakit = nakit - 100.00
WHERE ad = 'Ayşe';
UPDATE şubeler SET nakit = nakit - 100.00
WHERE ad = (SELECT şube_adı FROM hesaplar WHERE ad = 'Ayşe');
UPDATE hesaplar SET nakit = nakit + 100.00
WHERE ad = 'Ali';
UPDATE şubeler SET nakit = nakit + 100.00
WHERE ad = (SELECT şube_adı FROM hesaplar WHERE ad = 'Ali');
</screen>
<para>
Bu komutların ayrıntılarının burada bir önemi yoktur; önemli olan bunun basit işlemler olarak değil, ayrı ayrı güncellemelerin hepsinin birden yapılmasıdır. Bankamızın memurları bu işlemlerin ya hepsinin yapılmasını ya da hiçbirinin yapılmamasını ister. Eğer Ali, Ayşe'nin hesabından yeterli miktarı alamazsa ya da Ayşe'nin hesabından gerekli miktar alındığı halde Ali'nin hesabına geçmezse sistemin hata vermesinden başka her iki müşteri de memnun olmayacaktır. Yani, eğer işlemlerden biri gerçekleşmezse bu adımların hiçbirinin veritabanını etkilemeyeceğini garantilemeliyiz. Yapılacak işlemlerin bir <wordasword>hareket</wordasword> içinde gruplanması bize bu garantiyi sağlar. Bir hareket <wordasword>atomik</wordasword> olmalıdır, denir: diğer hareketler açısından ya tüm adımların hepsi gerçekleşmeli ya da hiçbiri gerçekleşmemelidir.
</para>
<para>
Kesinlikle emin olmamız gereken bir nokta ise bir hareket başarı ile işlemi yürütmüş olsa bile, bilginin tamam olarak veritabanına geçip geçmediğidir, son anda bir sistem kaynaklı hata olsa bile. Örneğin, Ali'nin hesabından para çekmeye çalıştığımızda, o daha bankanın kapısından çıkmadan, paranın bir hata sonucu onun hesabından çekilmiş olarak gözükmemesi gibi bir şansı göze alamayız. Tam bu noktada bir veritabanı, bir hareketle ilgili tüm işlemler yapılıp kayıtlar sabit disk gibi bir saklama alanına aktarılmadan 'tamam' sonucunu göndermez.
</para>
<para>
Bir diğer önemli nokta ise çok sayıda hareket aynı anda çalışırken birbirlerinin tamamlanmamış sonuçlarını görmemesi gerektiğidir. Örneğin bir hareket tüm şubelerdeki (şubeler) hesap miktarlarını toplarken başka bir hareket Ayşe ya da Ali'nin hesabı üzerinde işlem yapamayacaktır. Kısaca bir hareket tamam benim işim bitti demeden, diğer bir hareket bir işlem başlatamayacaktır.
</para>
<para>
PostgreSQL'de bir hareket, <userinput>BEGIN</userinput> ve <userinput>COMMIT</userinput> SQL komutları ile sarmalanmış adımlardan oluşur. Bu durumda, banka işlemlerimiz aslında şöyle görünecektir:
</para>
<screen>BEGIN;
UPDATE hesaplar SET nakit = nakit - 100.00
WHERE ad = 'Ayşe';
-- vesaire vesaire
COMMIT;
</screen>
<para>
Hareketin de belli bir noktasında işlemin iptal edilmesi gerekebilir (Mesela Ayşe'nin hesabı aktarılacak miktar için yetmeyip negatife düşerse), bunun için <userinput>COMMIT</userinput> yerine <userinput>ROLLBACK</userinput> kullanabiliriz ve böyle bir durumda tüm güncellemeler iptal edilir.
</para>
<para>
<productname>PostgreSQL</productname> aslında her SQL cümlesini sanki bir hareket gerçekleştiriyormuş gibi ele alır. Bir <userinput>BEGIN</userinput> komutu kullanmazsanız, her cümlenin başına örtük bir <userinput>BEGIN</userinput> ve cümle başarılı ise sonuna da örtük bir <userinput>COMMIT</userinput> getirilir. Bu nedenle, <userinput>BEGIN</userinput> ve <userinput>COMMIT</userinput> komutları ile sarmalanmış cümlelere bazan <wordasword>hareket kümesi</wordasword> de dendiği olur.
</para>
<note>
<para>
Bazı istemci kütüphaneleri <userinput>BEGIN</userinput> ve <userinput>COMMIT</userinput> komutlarını kendiliğinden koyar, böylece istemeden hareket kümelerinin etkileriyle karşılaşırsınız. Bu bakımdan kullandığınız arayüzün belgelerine bakmayı unutmayın.
</para>
</note>
<para>
Bir hareketi içinde kayıt noktaları belirterek cümle cümle denetlemek de mümkündür. Kayıt noktaları bir hareketin belli parçalarını seçerek iptal etmeyi mümkün kılar. Bir kayıt noktasını <userinput>SAVEPOINT</userinput> ile tanımladıktan sonra ihtiyaç duyarsanız, <userinput>ROLLBACK TO</userinput> ile bu kayıt noktasına kadar olan kısmı geri sarabilirsiniz. Bir hareketin bu iki komut arasında kalan veritabanı değişiklikleri iptal edilir, fakat, bu bölümden önce yapılanlar veritabanında kalır.
</para>
<para>
Bir kayıt noktasına kadar geri sarıldıktan sonra, işlem bu noktadan devam eder, öyle ki, bu defalarca yapılabilir. Tersine, belli bir kayıt noktasına geri sarmaya artık ihtiyaç duymayacağınızdan emin olduğunuzda, onu serbest bırakabilirsiniz, böylece sistem bazı özkaynakları serbest bırakabilir. Serbest bırakmanın da, bir kayıt noktasına geri dönmenin de tanımlanmasının ardından tüm kayıt noktalarının özdevimli olarak serbest bırakılacağını unutmayın.
</para>
<para>
Bunların hepsi hareket kümesinin içinde gerçekleşir, dolayısıyla, bu işlemlerin hiçbiri diğer veritabanı oturumlarına görünür değildir. Bir hareket kümesini işleme sokulduğunda, geriye sarma işlemleri diğer oturumlara asla görünür olmazken, işleme sokulan diğer eylemler bir birim olarak diğer oturumlara görünür hale gelir.
</para>
<para>
Bankanın veritabanını hatırlarsanız, Ayşe'nin hesabından Ali'nin hesabına 100 lira aktarmıştık ama daha sonra baktığımızda, paranın Veli'nin hesabına geçmesi gerektiğini keşfetmiş olalım. Bunun için kayıt noktalarını şöyle kullanabiliriz:
</para>
<screen>BEGIN;
UPDATE hesaplar SET nakit = nakit - 100.00
WHERE ad = 'Ayşe';
SAVEPOINT kayıt_noktası;
UPDATE hesaplar SET nakit = nakit + 100.00
WHERE ad = 'Ali';
-- dur bakalım ... Veli'nin hesabını kullanacağız
ROLLBACK TO kayıt_noktası;
UPDATE hesaplar SET nakit = nakit + 100.00
WHERE ad = 'Veli';
COMMIT;
</screen>
<para>
Bu örnek, şüphesiz fazla basit, fakat bir hareket bloğu üzerinde kayıt noktalarınını kullanımı ile ilgili yeterince denetim var. Dahası, sistem tarafından bir hatadan dolayı çıkış istendiğinde, <userinput>ROLLBACK TO</userinput> bir hareket kümesinin denetimini yeniden kazanmanın tek yoludur, tamamen gerisarma yapılıp tekrar başlanabilir.
</para>
</sect1>
<sect1 xml:id="pgsql-tutorial-window">
<title>Pencere İşlevleri</title>
<para>
Bir <firstterm>pencere işlevi</firstterm>, geçerli satırla bir şekilde ilişkili olan bir dizi tablo satırında bir hesaplama gerçekleştirir. Bu hesaplama türü, toplama işlevleriyle yapılabilecek hesaplamayla karşılaştırılabilir. Ancak, pencere işlevleri, penceresiz toplama çağrıların yaptığı gibi satırların tek bir çıktı satırında gruplandırılmasını sağlamaz. Bunun yerine, satırlar kendi kimliklerini korur. Perde arkasında, pencere işlevi, sorgu sonucunun geçerli tek bir satırından çok daha fazlasına erişebilir.
</para>
<para>
Her çalışanın (employee) maaşını (salary) kendi bölümündeki (depname) ortalama maaşla nasıl karşılaştıracağını gösteren bir örnek:
</para>
<screen>
SELECT depname, empno, salary, avg(salary) OVER (PARTITION BY depname) FROM empsalary;
</screen>
<para>Çıktısı:</para>
<screen>
depname | empno | salary | avg
-----------+-------+--------+-----------------------
develop | 11 | 5200 | 5020.0000000000000000
develop | 7 | 4200 | 5020.0000000000000000
develop | 9 | 4500 | 5020.0000000000000000
develop | 8 | 6000 | 5020.0000000000000000
develop | 10 | 5200 | 5020.0000000000000000
personnel | 5 | 3500 | 3700.0000000000000000
personnel | 2 | 3900 | 3700.0000000000000000
sales | 3 | 4800 | 4866.6666666666666667
sales | 1 | 5000 | 4866.6666666666666667