postgres oracle sql difference functionality - ghdrako/doc_snipets GitHub Wiki

Comprare process

obraz

Compare memory

obraz

migration tools

  • ora2pg - schema migration data migration, sql and code conversion

  • code2pg https://github.com/societe‑generale/code2pg

  • oraMigrator - pyton based tool- conversion schema,data views tables, storage procedure ant other db objects

  • SQLAlchemy

  • Flyway

  • SQLines SQL Converter

  • ESF Database Migration Toolkit

  • Full Convert

  • Ispirer MnMTK

Transactions

  • Oracle ends with COMMIT
  • PostgreSQL requires a BEGIN statement before a transaction and ends with COMMIT
  • Different isolation level and behavior

Functins and sql syntax

oracle postgresql desc
to_number(col,'xxxxxxxxxxxxxxxx') SELECT ('x' || lpad(hex, 16, '0'))::bit(64)::bigint conv 16 znakow hex na number
len(col_str) lenght(col_str) dlugosc stringu
123 || 456 -> 123456 123 || 456 -> Error concatenation
SELECT 'A' NULL
SELECT 'A' NULL
SELECT 'A' NULL
nvl(MY_FIELD,'N/A') coalesce(MY_FIELD,'N/A') default value
is not equal to NULL is equal to NULL empty string
upper(description) like '%DISCUSS%' description ilike '%DISCUSS%' case-insensitive like query
substr(tag,20) substring(tag from 0 for 20) first 20 characters of the tag string
automonous transaction PRAGMA AUTONOMOUS_TRANSACTION unsupported unsupported ; https://blog.dalibo.com/2016/08/19/Support_des_transactions_autonomes_dans_PostgreSQL.html
alter table test add c4 varchar2(10) default 'd1' not null; alter table test add c4 varchar(10) not null default 'd1'; add defalut column not null
sysdate current_date current date
ROWID ctid physical address of a table row. ROWID w Oracle reprezentuje logiczny adres wiersza, kodowany w formie OOOOOO.FFF.BBBBBB.RRR, gdzie O oznacza numer obiektu, F plik, B numer bloku, a R wiersz w bloku. Daje to unikalnosc w ramach calej instancji. ctid w PostgreSQL, reprezentuje tylko parę (numer bloku, numer rekordu) i dlatego jest unikalna tylko w ramach tabeli. Z tego powodu zapytanie zwracające ctid wierszy w tabeli partycjonowanej może zwracać zduplikowane ctid. W takim przypadku można użyć ukrytej kolumny tableoid (unikalny identyfikator tabeli w katalogu) dla każdej tabeli, aby odróżnić duplikaty według partycji.
alter table t add column c char(1); alter table t add c char(1); add column to table
ALTER TABLE tbl_name ALTER COLUMN col_name TYPE integer USING (NULLIF(col_name, '')::integer); ALTER TABLE <table_name> MODIFY (<column_name> <new_Type>) modify column typ from text to integer
ALTER TABLE tbl_name ALTER COLUMN col_name TYPE varchar (11), ALTER COLUMN col_name2 TYPE varchar (11),ALTER COLUMN col_name3 TYPE varchar (11); ALTER TABLE place MODIFY (street_name VARCHAR2(20), county VARCHAR2(20), city VARCHAR2(20)) modify multiple column typ/size
create table t(id serial primary key); create sequence seq start with 1; create table t(id number primary key); insert into t(id) values(seq.NEXVAL); autoincrementacja
ALTER TABLE aci_imp_info ALTER COLUMN catalog_name DROP NOT NULL; ALTER TABLE imp_aci_info MODIFY catalog_name NULL; usuniecie warunku not null
STRING_AGG LISTAGG f. analityczna
:: or function CAST select '123':INTEGER; select cast('123' as number) from dual; rzutowanie typów
LIMIT/OFFSET select * from t limit 10 ofset 5; ROWNUM lub `FETCH FIRST N ROWS ONLY' limitowanie wyników zapytań
SELECT * FROM employees LIMIT 10 SELECT * FROM employees WHERE ROWNUM < 11;
ALTER TABLE table_name RENAME TO new_table_name; ALTER TABLE table_name RENAME TO new_table_name;' alter table ebk.jeden rename to temp_jeden;` rename table
SELECT ROWNUM, * FROM employees; SELECT ROW_NUMBER() OVER () AS rownum, * FROM employees; Klauzula WITH ORDINALITY w PostgreSQL 9.4 pozwala na numerowanie wierszy wyników wywołania funkcji
brak synonymes,hints
status_zadluzenia varchar(4) NOT NULL DEFAULT 'OK'::character varying status_zadluzenia varchar2(4) DEFAULT 'OK' NOT NULL w oracle najpierw musi być default a potem not null - jak odwrotnie to błąd
Minus, except except minus i except działają tak samo usuwają z wyniku jednego selecta wynik drugiego. Except jest szerzej wspierany więc lepiej go uzywac
INSTR(title,'Bright') POSITION('Bright' IN title) position substring in strin
DECODE("user_status",'active',"username",NULL) CASE WHEN user_status='active' THEN username ELSE NULL END komentarze między WHEN a THEN PostgreSQL nie obsługuje
SELECT emp_name,decode(trunc (( yrs_of_service + 3) / 4), 0, 0.04,1, 0.04,0.06) as perc_valueFROM employees; SELECT emp_name,CASE WHEN runc(yrs_of_service + 3) / 4 = 0 THEN 0.04 WHEN trunc(yrs_of_service + 3) / 4 = 1 THEN 0.04 ELSE 0.06 END FROM employees;
ALTER SESSION SET ISOLATION LEVEL ...; SET SESSION TRANSACTION ISOLATION LEVEL ...; ustawienie poziomu izolacji na poziomie sesji

Types conversion

Postgres Oracle
boolean NUMBER(1) 0/1 CHAR(1) T/F
bigint / int8 number(18,0) / int ,number(9,0)
character varying(s) , varchar2(s) ,character varying
bpchar(s),char(s) char(s)
character(s) char(s) character(s)
integer / int4 int, number(9,0)
numeric / decimal / number number
numeric(p,s) / decimal(p,s) / number(p,s) number(p,s)
numeric(p) / decimal(p) / number(p) number(p)
real float
xml xmltype
text clob
text long
  • Oracle używa zazwyczaj typu number dla liczb całkowitych. Ścisłym odpowiednikiem w PostgreSQL jest numeric, ale lepiej przejść na inne typy danych, takie jak int (czterobajtowa liczba całkowita) lub bigint (ośmiobajtowa liczba całkowita), które są zdecydowanie wydajniejsze.

  • w PostgreSQL typ danych char(n) jest w praktyce taki sam jak bpchar(n), ponieważ oba oznaczają ciąg znaków o stałej długości, który jest dopełniany spacjami z prawej strony. Różnica polega jedynie na wewnętrznej implementacji — bpchar to wewnętrzna nazwa typu używana w metadanych PostgreSQL.

  • Oracle ROWID format OOOOOO.FFF.BBBBBB.RRR ... - unikalny w skali bazy, określa fizyczna lokalizacje wiersza

  • ctid . unikalny tylko w tabeli - nie określa lokalizacji wiersza

  • Synonimy w Oracle nie mają odpowiednika w PostgreSQL.

  • parametr w tabeli oracle PCTFREE ma odpowiednik w postgresie fillfactor

CREATE TABLE distributors (
did integer,
name varchar(40),
UNIQUE(name) WITH (fillfactor=70)
)
WITH (fillfactor=70);

ALTER TABLE pgbench_accounts SET (fillfactor = 90);
CREATE INDEX idx_100 on t_static (id) WITH (FILFACTOR=100);

Virtual Column in Oracle

CREATE TABLE employees (
id NUMBER,
first_name VARCHAR2(10),
salary NUMBER(9,2),
commission NUMBER(3),
salary2 NUMBER GENERATED ALWAYS AS
(ROUND(salary*(1+commission/100),2)) VIRTUAL
);

Postgres 12

CREATE TABLE employees (
id bigint,
first_name varchar(10),
salary double precision,
commission integer,
salary2 double precision generated always as
(ROUND((salary*(1+commission/100))::numeric,2)) STORED
);

Tabele w Oraclu z defaulta przechowywane sa z duzej litery a w postgres z malej.

Oracle pozwala na odwrocenie kolejnosci klauzul GROUP BY i HAVING:

SELECT * FROM test HAVING count(*) > 3 GROUP BY i;

postgres jest bardziej restrykcyjny i wymusza poprawna kolejnosc klauzul.

SELECT * FROM test GROUP BY i HAVING count(*) > 3;

Wiele zapytań SQL w Oracle używa pseudo-tabeli DUAL do manipulowania wartościami pochodzącymi z funkcji lub zmiennych, bez potrzeby pobierania ich z konkretnej tabeli. Istnienie tej pseudotabeli wynika z tego ze w Oracle klauzule SELECT i FROM są nierozłączne. W PostgreSQL, następujące składnie są poprawne:

SELECT fonction();
SELECT current_timestamp;

Konwersje niejawne do i z pola typu tekstowego zostały usunięte w PostgreSQL od wersji 8.3.

CREATE TABLE depts ( numero CHAR(2), nom VARCHAR(25) );
SELECT * FROM depts WHERE numero BETWEEN 0 AND 42;
-- ERROR: operator does not exist: character >= integer
-- LINE 1 : SELECT * FROM depts WHERE numero BETWEEN 0 AND 42;
SELECT * FROM depts WHERE numero::int BETWEEN 0 AND 42;

W Oracle taki rodzaj konwersji jest domyślny.

Indexes

In Oracle indexes on column not contain null values but in Postgres contain. To simulate use for postgres partia index that exclude null values and for oracle function Index where function convert null to something other and indexing.

PostgreSQL does not create indexes on foreign keys automatically!!!

Update tables from another tables

In oracle corelate query

UPDATE table1 t1
   SET (name, desc) = (SELECT t2.name, t2.desc
                         FROM table2 t2
                        WHERE t1.id = t2.id)
 WHERE EXISTS (
    SELECT 1
      FROM table2 t2
     WHERE t1.id = t2.id )

or marge

MERGE INTO table1 t1
USING
(
-- For more complicated queries you can use WITH clause here
SELECT * FROM table2
)t2
ON(t1.id = t2.id)
WHEN MATCHED THEN UPDATE SET
t1.name = t2.name,
t1.desc = t2.desc;

In postgres and oracle 23 update from


update t1
set    t1.c2 = t2.c2
from   t2
where  t1.c1 = t2.c1;

Roznice w typach tekstowych

Typ / Funkcja PostgreSQL (bpchar(n) = CHAR(n)) Oracle (CHAR(n))
Sposób przechowywania Znakowy, blank-padded (dodaje spacje do długości n) Znakowy, blank-padded również
Zachowanie przy odczycie Przy odczycie PostgreSQL obcina spacje z prawej strony – traktuje wartość logicznie jako krótszą Oracle zachowuje spacje przy odczycie — więc wartość ma pełną długość n
LENGTH(kolumna) Zwraca długość po obcięciu spacji Zwraca rzeczywistą długość (łącznie ze spacjami)
Przykład (CHAR(10) z 'abc') length(a) → 3 length(a) → 10
  • Dla kolumny typu bpchar(n) (czyli aliasu dla CHAR(n)) funkcja length() zwraca długość po obcięciu spacji z prawej strony, a nie długość deklarowaną (n).
  • bpchar (od blank padded char) to wewnętrzna nazwa PostgreSQL dla CHAR(n).
  • W tym typie PostgreSQL automatycznie przycina spacje z prawej strony przy odczycie wartości.
  • Oracle przechowuje i zwraca dokładnie tyle znaków, ile wynosi deklarowany rozmiar typu CHAR(n) (czyli traktuje go dosłownie jako „stałą długość”).
  • PostgreSQL natomiast traktuje CHAR(n) jako tekst logiczny, w którym spacje są tylko paddingiem, więc przy odczycie od razu je obcina, żeby uniknąć nieintuicyjnych porównań i wyników.
    • przy porównaniach (=) ignoruje końcowe spacje,
    • przy odczycie obcina końcowe spacje,
    • ale w fizycznym zapisie przechowuje je w pełnej długości n.
CREATE TABLE test_bpchar (
    kod CHAR(10)
);
INSERT INTO test_bpchar VALUES ('ABC');

SELECT * FROM test_bpchar WHERE kod = 'ABC';
-- ✅ ZWRÓCI WIERSZ

SELECT * FROM test_bpchar WHERE kod = 'ABC       ';
-- ✅ TEŻ ZWRÓCI WIERSZ
SELECT length(kod) FROM test_bpchar;
-- → 3  (bo obcięto spacje przy odczycie)

SELECT octet_length(kod);
-- → 10 (bo fizycznie przechowano 10 znaków)
  • W PostgreSQL porównania dla CHAR(n) działają tak, jakby obie strony były najpierw prawo-przycięte (rtrim()), czyli:
col = 'ABC'
⟺
rtrim(col) = rtrim('ABC')

czyli przy porownywaniu z wartoscia nie trzeba dopisywać spacji, np. '1234567 '

varchar(n) w Postgresie

  • nie dopisuje spacji ale istniejace zachowuje
  • Nie przycina spacji przy odczycie.
  • length(kolumna) → zwraca długość dokładną (nie obcina spacjijak w bpchar/char).
  • Porównania (=) nie ignorują spacji. Czyli przeciwnie niz w char/bpchar
CREATE TABLE t_v (v VARCHAR(10));
INSERT INTO t_v VALUES ('ABC   ');
SELECT length(v), v = 'ABC' FROM t_v;
-- length = 6
-- porównanie = false

varchar2(n) w oracle

  • przy zapisie zachowuje spacje
  • przy porównaniu ignoruje końcowe spacje (VARCHAR2 zachowuje się jak CHAR przy porównaniu!).
  • Przy odczycie nie obcina spacji.

char(n) oracle

  • padding do n
  • nie obcina spacji przy odczycie
  • LENGTH() zwraca n.
  • Porównania ignorują spacje.

char(n) postgres

  • Przechowuje dane z paddingiem do n (spacjami)
  • Przy odczycie obcina końcowe spacje.
  • Porównania ignorują końcowe spacje.

Przyklad postgres

CREATE TABLE t (a VARCHAR(10), b CHAR(10));
INSERT INTO t VALUES ('abc   ', 'abc');

SELECT a = 'abc', b = 'abc' FROM t;
--wynik:
a = false   (bo 'abc   ' ≠ 'abc')
b = true    (bo CHAR ignoruje spacje)

Przykld Oracle

CREATE TABLE t (a VARCHAR2(10), b CHAR(10));
INSERT INTO t VALUES ('abc   ', 'abc');

SELECT (a = 'abc') AS a_eq, (b = 'abc') AS b_eq FROM t;
--wynik:
a_eq = true   (bo Oracle ignoruje końcowe spacje przy porównaniu VARCHAR2!)
b_eq = true
Cecha Oracle (domyślnie) Oracle (NLS_LENGTH_SEMANTICS=CHAR) PostgreSQL
Jednostka VARCHAR(n)/CHAR(n) bajty znaki znaki
LENGTH() zwraca liczbę znaków liczbę znaków

PostgreSQL — VARCHAR(n) ogranicza liczbę znaków

W PostgreSQL VARCHAR(n) (i CHAR(n)) oznacza maksymalnie n znaków, niezależnie od tego, ile bajtów ma każdy znak.

CREATE TABLE t (v VARCHAR(5));
INSERT INTO t VALUES ('ąęśćżź');
-- ✅ działa, bo to 5 znaków (choć zajmuje więcej niż 5 bajtów w UTF-8)

Oracle — VARCHAR2(n) ogranicza liczbę bajtów (domyślnie) - nie ma odpowiednika w Postgresie

CREATE TABLE t (v VARCHAR2(5));
INSERT INTO t VALUES ('ąęśćżź');
-- ❌ ORA-12899: value too large for column

Od nowszych wersji Oracle (11g, 12c i dalej) możesz jawnie ustawić, że długość jest w znakach, nie w bajtach:

CREATE TABLE t (v VARCHAR2(5 CHAR));

lub globalnie na bazie:

ALTER DATABASE CHARACTER SET AL32UTF8;
ALTER SYSTEM SET NLS_LENGTH_SEMANTICS=CHAR;

po tym

INSERT INTO t VALUES ('ąęśćżź'); -- dziala

Duża różnica między Oracle a PostgreSQL w przypadku łańcuchów znaków polega na tym, jak obsługiwane są puste łańcuchy: Oracle nie rozróżnia pustego łańcucha od wartości NULL. PostgreSQL robi to rozróżnienie. W związku z tym wszystkie testy pustych łańcuchów wykonywane za pomocą IS NULL i wszystkie testy wartości NULL wykonywane przez porównanie z pustym łańcuchem nie dadzą tego samego wyniku w PostgreSQL.

# SELECT cast('' AS varchar) IS NULL;
?column?
---------
f       -- false pusty tekst nie jest NULL-em w postgres
(1 row)

PostgreSQL akceptuje tylko jedno kodowanie na bazę danych. W oracle moze byc inne za pomoca nchar i nvarchar2.

Schema

Obszar Oracle PostgreSQL
Relacja user–schema 1:1 – użytkownik = schema (tworząc user, tworzysz schema) Brak powiązania – user i schema są niezależne
Tworzenie schematu Automatyczne przy CREATE USER Jawne: CREATE SCHEMA
Czym jest schema Również „namespace”, ale powiązany z userem Czysty namespace (kontener obiektów)
Właściciel obiektów Zawsze user odpowiadający schematowi No matter who created a schema object, its owner is determined by the object's schema. Niezależny od schematu (owner ≠ schema) So it is entirely possible for a table to have an owner that is different from the owner of the table's schema.
Uprawnienia Brak uprawnień per schema (głównie systemowe typu ANY) USAGE + CREATE na schema. So it could happen that you own an object, but you don't have permission to access it, because you are lacking the USAGE privilege on the containing schema
Dostęp bez nazwy schematu current_schema + synonimy search_path (lista schematów)
Domyślna przestrzeń nazw Schema = user "$user" + public
Synonimy Tak (public/private synonyms) Synonyms are objects that are only references to other objects allows you to access an object in a different schema without specifying the schema name. Nie (zastępuje to search_path)
System schemas Bardzo dużo (SYS, etc.) pg_catalog, information_schema itd.
Model koncepcyjny „Schema = użytkownik + obiekty” „Schema = folder / namespace”
namespace tables and views share a namespace, but constraints, indexes (which the standard doesn't know) and sequences live in different namespaces. That means that a table, a sequence and an index in the same schema can have the same name. all schema objects that have columns (“relations”) share the same namespace: tables (including foreign and partitioned tables), indexes, sequences, views, materialized views and composite data types. In principle, constraints have a different namespace, but all constraints that are backed by indexes (primary key, unique and exclusion constraints) always have the same name as their backing index. That means that these constraints effectively share the namespace of the relations.PostgreSQL doesn't follow the SQL standard in this respect
INFORMATION SCHEMA Oracle is lacking the INFORMATION_SCHEMA decreed by the SQL standard that provides a standardized view of the database metadata. EXIST
System schemas The schema SYS that belongs to the all-powerful “sysdba” User SYS contains the database metadata and system functions (in the SYS.STANDARD package). That schema also contains the huge collection of packages that provide tools for almost everything. In addition to that, there is an amazing number of system schemas that contain objects for additional features like full text search or XML support. The schema pg_catalog contains all the system tables, views, functions and data types. pg_toast contains the TOAST tables that provide external storage for large column values. Schemas named pg_temp_* and pg_toast_temp_* are an implementation detail of how PostgreSQL implements temporary tables. PostgreSQL has a standard conforming information_schema.
⚠️ **GitHub.com Fallback** ⚠️