5 Temmuz 2022 Salı

PostGIS ST_MaximumInscribedCircle

Giriş
Açıklaması şöyle. 3 çıktısı olan bir sonuç döner. Bunlar radius, center ve center'a en yakın nokta
Finds the largest circle that is fully contained within a geometry. Returns a record with the center point of the circle, a point on the geometry that is nearest to the center, and the radius of the circle.
Örnek
Şöyle yaparız
SELECT
  mic.radius,
  mic.center,   --already a GEOMETRY(POINT) type
  mic.nearest   --already a GEOMETRY(POINT) type
FROM
  <table> AS t,
  LATERAL ST_MaximumInscribedCircle(t.geom) AS mic
;

17 Haziran 2022 Cuma

patronictl komutu - Patroni Replication Monitoring İçindir

Giriş
Açıklaması şöyle
Patroni provide all functionality to setup, monitor and fix the replica DB using reinit command.


Zalando Operator ile kullanılıyor

patronictl komutu

list seçeneği
Örnek
Şöyle yaparız
$ kubectl exec -it rlwy-postgres-1 -n rlwy02-pgo -- /bin/bash
Defaulted container "postgres" out of: postgres, exporter

 ____        _ _
/ ___| _ __ (_) | ___
\___ \| '_ \| | |/ _ \
 ___) | |_) | | | (_) |
|____/| .__/|_|_|\___/
      |_|

This container is managed by runit, when stopping/starting services use sv

Examples:

sv stop cron
sv restart patroni

Current status: (sv status /etc/service/*)

root@rlwy-postgres-1:/home/postgres# patronictl list
2022-06-17 07:10:35,333 - WARNING - Listing members: No cluster names were provided

16 Haziran 2022 Perşembe

9 Haziran 2022 Perşembe

Sütun Tipleri - IDENTITY (Otomatik Sayı Üretir)

Giriş
Açıklaması şöyle
It is recommended to use IDENTITY instead since SERIAL has some weird behaviors.
Bu sütunlara NOT NULL + PRIMARY KEY + UNIQUE gibi özellikler de atanabilir.

Örnek
Şöyle yaparız
CREATE TABLE IF NOT EXISTS entity (
    id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    ...
)

# To see the sequence
SELECT * FROM pg_sequence WHERE seqrelid = 'entity_id_seq'::regclass;
IDENTITY Kullanımının Bazı Dezavantajları
Not : Bazıları IDENTITY yerine UUID kullanılması öneriyor. 
1. İki tane tablonun birleştirilmesinde problem oluyor. Bir açıklama şöyle
I’ve seen this over and over for the last 30 years, people let the database set the ID or Primary Key of a table from the database, at first glance this sounds simple and everyone knows you should let the database do the heavy lifting, with a numeric “Sequence” number you need to let the database do the work since there may be multiple applications or threads creating new records in the table. DON”T DO IT!

First, if and when you need to merge two databases that now have the same Primary Key ID values for the same table, your screwed. You have to come up with a scheme to change the ID’s, maybe adding 10,000 to each ID, what if you have more than 10,000 rows? The you also have to update all children records, maybe not that easy if you have constraints defined in the database.
2. Güvenlik Açıkları
Eğer bir Primary Key değerinin 100 olduğunu biliyorsam bir sonrakinin de 101 olacağını biliyorum. Bunu sorgulayarak bir güvenlik açığından faydalanabilirim. 

9 Mayıs 2022 Pazartesi

UPSERT - INSERT ON CONFLICT - Postgres 9.5 İle Geliyor

Giriş
Açıklaması şöyle. UPSERT sanırım SQL:2003 ile geliyor. UPSERT işleminin ORACLE, SQL Server, PostgreSQL ve MySQL tarafından nasıl yapıldığına dair bir yazı burada
PostgreSQL doesn't have a dedicated UPSERT command, but upserts can be accomplished using INSERT ON CONFLICT
Açıklaması şöyle
Postgres 9.5 and above FINALLY supports UPSERT (otherwise known as: INSERT ... ON CONFLICT DO ).
Söz dizimi şöyle
INSERT INTO table (col1, col2, col3) 
VALUES (val1, val2, val3) 
ON CONFLICT conflict_target conflict_action;
Açıklaması şöyle
As we can see in the above command, PostgreSQL allows us to specify two things:
  • conflict_target, i.e. where it should look to detect a conflict.
  • conflict_action, i.e. how the command should be handled if a conflict is detected.
1. conflict_target
Sütun isimlerini belirtir

2. conflict_action
DO NOTHING veya DO UPDATE SET olabilir

2.1 DO NOTHING
Örnek
Şöyle yaparız
INSERT INTO "public"."post_details" (
    "id",
    "created_by",
    "created_on")
VALUES (
    1,
    'Alice',
    TIMESTAMP '2017-11-06 16:42:37.692')
ON CONFLICT DO NOTHING
2.2 DO UPDATE SET
Burada DO UPDATE SET ten sonra tüm sütunları belirtmek lazım. Açıklaması şöyle
It can be either DO NOTHING, or a DO UPDATE clause specifying the exact details of the UPDATE action to be performed in case of a conflict.
Örnek
Docker'ı çalıştır
docker run --name pg -e POSTGRES_PASSWORD=docker -e POSTGRES_DB=sampledb -p 5432:5432 \
  postgres
Şöyle yap
CREATE TABLE customer (
  id NUMERIC, 
  name VARCHAR(20), 
  age NUMERIC, 
  address VARCHAR(20), 
  salary NUMERIC,
  PRIMARY KEY (id)
);

INSERT INTO customer (id,name,age,address,salary)
VALUES (1, 'orcun', 47, 'ankara', 2000);

INSERT INTO customer (id,name,age,address,salary) 
VALUES (1, 'colak', 46,  'istanbul', 3000)
ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name; 
Örnek
Şöyle yaparız. Burada SQL cümlesi tam değil. 
INSERT INTO employees (id, name, email) 
VALUES (2, ‘Dennis’, ‘dennisp@weyland.corp’)
ON CONFLICT (id) DO UPDATE SET ...;
Açıklaması şöyle
PostgreSQL detects a conflict - we're trying to insert a row with an id value of 2, but a row with that id already exists in employees - so it runs UPDATE on that row using the new values.

If we were to run this command with values that did not generate a conflict (for example, (5, 'Kane', 'kane@weyland.corp'), it would insert a new row into employees with those values.
Örnek - Composite Key
Composite Key varsa ON CONFLICT() içinde virgül ile ayrılarak belirtilir. Şöyle yaparız. Burada PRIMARY KEY (person_id, question_id) 
INSERT INTO answer VALUES (1,1,'q1') 
ON CONFLICT (person_id,question_id) 
DO UPDATE SET answer = EXCLUDED.answer;             

SELECT * FROM answer;
 person_id | question_id | answer 
-----------+-------------+--------
         1 |           1 | q1
(1 Zeile)

INSERT INTO answer VALUES (1,1,'q1-UPDATED') 
ON CONFLICT (person_id,question_id) 
DO UPDATE SET answer = EXCLUDED.answer;             

SELECT * FROM answer;
 person_id | question_id |   answer   
-----------+-------------+------------
         1 |           1 | q1-UPDATED
Örnek 
Şöyle yaparız
INSERT INTO customers (name, email)
VALUES('Microsoft','hotline@microsoft.com') 
ON CONFLICT (name) 
DO UPDATE SET email = EXCLUDED.email || ';' || customers.email;
EXCLUDED.email ile yeni veri kastediliyor. Satırdaki email değeri şöyle olur hotline@microsoft.com;contact@microsoft.com

Örnek
Şöyle yaparız. Burada birden fazla satır var, EXCLUDED.value ile belirttiğimiz veriye erişiriz. Ayrıca t.value ile mevcut değere de erişiriz
INSERT INTO t (id, value) VALUES ('A',3),('B',5),('C',7) 
ON CONFLICT (id) DO UPDATE SET value = t.value + EXCLUDED.value
Örnek - Where
Şöyle yaparız.
INSERT INTO temp_table
  (source_id, target_id, active) VALUES
  ($1, $2, false)
ON CONFLICT (source_id, target_id) DO UPDATE SET
  active = true
  WHERE similar_channels.source_id = $1
  AND similar_channels.target_id = $2
returning *

















27 Nisan 2022 Çarşamba

ILIKE Operator

Giriş
Açıklaması şöyle
ILIKE, a specific operator for PostgreSQL, has the same features as the LIKE operator but is case-insensitive. If special characters defined for the LIKE operator (% and _) are not found within the search text, ILIKE can be used as a case-insensitive equality operator. Although using it for equality checks is incorrect, ILIKE is the most suitable solution when case-insensitive pattern matching is desired. 
ILIKE için Trigram Index lazım
Açıklaması şöyle
If we must support ILIKE substring search, the best immediate fix is a trigram index:
Şöyle yaparız
CREATE EXTENSION IF NOT EXISTS pg_trgm;

CREATE INDEX idx_users_username_trgm
ON users
USING GIN (username gin_trgm_ops);
Açıklaması şöyle
Why this works

Trigram indexes break strings into 3-character chunks

They allow PostgreSQL to index LIKE, ILIKE, and fuzzy searches

They drastically reduce scan time for substring queries
Örnek
Şöyle yaparız.
SELECT
  DISTINCT(event_type)
FROM
  storm_events
WHERE
  event_type ILIKE '%winter%'
Örnek
Şöyle yaparız. İ
SELECT DISTINCT x.address ->> 'long_name' AS country_name
FROM  (
    SELECT jsonb_array_elements(b.address) AS address
    FROM   brand b
    WHERE  jsonb_typeof(b.address) = 'array'            -- !!!
   ) x
WHERE  x.address ->> 'types' ILIKE ANY (ARRAY['%country%'::text]);

JSON Processing Functions

Giriş
Açıklaması şöyle
There’s a very long list of JSON Processing Functions, including functions (for example) to:
- expand a json array into different data types
- count elements
- extract objects (similar to “#>” and “#>>” operators)
- return the json keys
- set and insert (which replaces or adds path elements)
- path checking (exists, match, query)
- pretty and
- Typeof!
jsonb_typeof metodu
Verinin tipinin  örneğin array olup olmadığını anlamak için kullanılır

Örnek
address sütunu JSONB tipinden olsun ve içindeki veri şöyle olsun
{
"address":[ { "types":["route"], "long_name":"20203 113B Ave", "short_name":"20203 113B Ave" }, { "types":["locality","political"], "long_name":"Maple Ridge", "short_name":"Maple Ridge" }, ... ] }
Şöyle yaparız. İçteki sorguda b.address alanındaki dizi çekiliyor. Ancak dizi olması gerek bazı veri json array değil de jsonb. Bu yüzden önce array olmayan veri eleniyor. Daha sonra dış sorguda address nesnesinin long_name alanının değerine text olarak erişiliyor.
SELECT DISTINCT x.address ->> 'long_name' AS country_name
FROM  (
    SELECT jsonb_array_elements(b.address) AS address
    FROM   brand b
    WHERE  jsonb_typeof(b.address) = 'array'            -- !!!
   ) x
WHERE  x.address ->> 'types' ILIKE ANY (ARRAY['%country%'::text]);