Serial Data Type & Sequence
Sequence Control
One Sequence for Two Tables
Reset Sequence
Array Data Type
Array Functions and Operands
Extension hStore
XML data
XML2 - Transform XML to Presentable view
JSON & JSONB
JSON Data Retrieving
Domain and Citext Extension
Write functions on Perl, Python, JS, Ruby, PHP
2. Serial Data Type & Sequence
-- Create autoincrement
CREATE SEQUENCE example_seq
START WITH 3
INCREMENT BY 3
MINVALUE 3
NO MAXVALUE;
-- After table creation, the sequence entity_id_seq will be created
CREATE TABLE entity (
id SERIAL PRIMARY KEY,
value VARCHAR(255)
);
-- Check available sequences
SELECT * FROM pg_statio_user_sequences;
3. Sequence Control
-- Set next increment as current and return it
SELECT nextval('entity_id_seq'); -- 1
SELECT nextval('entity_id_seq'); -- 2
SELECT nextval('entity_id_seq'); -- 3
INSERT INTO entity(value) VALUES ('some foo') RETURNING id; -- 4
-- Update sequence and return updated value;
SELECT nextval('entity_id_seq');
-- Get current value
SELECT currval('entity_id_seq');
-- Get last inserted value
SELECT lastval();
-- Update sequence value
SELECT setval('entity_id_seq', 99);
4. One Sequence for Two Tables
CREATE SEQUENCE multi_entity_seq;
CREATE TABLE multi_entity_a(
id INTEGER DEFAULT nextval('multi_entity_seq') PRIMARY KEY,
value VARCHAR(255)
);
CREATE TABLE multi_entity_b(
id INTEGER DEFAULT nextval('multi_entity_seq') PRIMARY KEY,
value VARCHAR(255)
);
INSERT INTO multi_entity_a (value) VALUES ('some value of ' || currval('multi_entity_seq'))
RETURNING id; -- 1
INSERT INTO multi_entity_a (value) VALUES ('some value of ' || currval('multi_entity_seq'))
RETURNING id; -- 2
5. Reset Sequence
-- Truncate operation does not update the sequence
TRUNCATE TABLE entity;
-- Reset sequence
TRUNCATE TABLE entity RESTART IDENTITY;
-- Alter reset sequence
ALTER SEQUENCE entity_id_seq RESTART;
-- or
SELECT setval('entity_id_seq', 1, false);
6. Array Data Type
CREATE TABLE book (
id SERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
tags VARCHAR(255) [],
authors INT []
);
INSERT INTO book (title, tags, authors)
VALUES ( 'PostgreSQL 9.6 High Performance', '{PostgreSQL,9.6,High,Performance}', '{1, 2}'),
( 'Mastering PostgreSQL 9.6', '{PostgreSQL,9.6,Mastering}', '{10,12,3}'),
('PostgreSQL Administration Cookbook', 'Some info', '{9.5,Administration}', '{29,41,36}'),
( 'PostgreSQL High Performance Cookbook', '{PostgreSQL,High,Performance}','{18,35}');
7. Array Functions and Operands
-- in array
SELECT * FROM book WHERE '9.6' = ANY (tags);
-- not in array
SELECT * FROM book WHERE id != ALL (SELECT eq FROM (VALUES (1), (2)) AS t(eq));
-- select all rows with ‘high’ or 9.5 version
SELECT * FROM book WHERE '{9.5,High}' && tags;
-- select all rows with ‘high’ and 9.6 version
SELECT * FROM book WHERE '{9.6,High}' <@ tags;
-- Get books where title is like one of array title values
SELECT * FROM book WHERE book.title ~~* ANY (ARRAY ['%Perfor%', '%Admin%']);
-- Array to string conversion
SELECT array_to_string(tags, ',') FROM book;
-- Array to json conversion
SELECT array_to_json(tags) FROM book;
8. Extension hStore
CREATE EXTENSION hstore;
CREATE TABLE product (
id SERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
description TEXT,
price DECIMAL(12, 2) NOT NULL,
attributes HSTORE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT (CURRENT_TIMESTAMP AT TIME ZONE 'UTC'),
updated_at TIMESTAMP
);
10. Retrieving data from hStore
SELECT
title,
price :: MONEY,
attributes -> 'color' AS color,
attributes -> 'weight' AS weight,
attributes -> 'sku' AS sku
FROM product
WHERE (attributes -> 'weight') :: INT > 1500
ORDER BY replace(attributes -> 'sku', 'LPT', ' ');
11. hStore Data Manipulation
-- hstore key exists
SELECT * FROM product WHERE attributes ? 'is_something';
-- hstore contains all specified keys
SELECT * FROM product WHERE attributes ?& string_to_array('is_something,hidden', ',');
-- hstore to data records
SELECT
id,
(each(attributes)).key AS attribute,
(each(attributes)).value AS value
FROM product;
12. Creating XML data
-- Books to xml
CREATE TABLE book_as_xml (
id SERIAL PRIMARY KEY,
content XML NOT NULL
);
-- Transform all books to xml
INSERT INTO book_as_xml (content)
SELECT xmlroot(
xmlelement(NAME book, xmlforest(id, title, authors, tags)),
VERSION '1.1',
STANDALONE YES
) FROM book
RETURNING content;
13. XML2 - Transform XML to Presentable view
CREATE EXTENSION xml2;
CREATE OR REPLACE FUNCTION xml_pretty(TEXT)
RETURNS XML AS $body$
SELECT xslt_process($1,
'<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*" />
<xsl:output method="xml" indent="yes" />
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>' :: TEXT) :: XML
$body$ LANGUAGE SQL IMMUTABLE STRICT;
14. XML Manipulation
-- Show pretty xml
SELECT xml_pretty(content) FROM book_as_xml;
-- Xpath
SELECT array_to_string(xpath('//title/text()', content), '; ') FROM book_as_xml;
-- Get all tags values
SELECT array_to_string(xpath('//tags/element/text()', content), '; ') FROM book_as_xml;
-- Return all table content as xml
SELECT xmlroot(
xmlelement(name body, table_to_xml('book', TRUE, TRUE, '')),
VERSION '1.1',
STANDALONE YES
) FROM book;
15. JSON & JSONB
CREATE TABLE entity_as_jsonb (
id SERIAL PRIMARY KEY,
content JSONB
);
INSERT INTO entity_as_jsonb (type, content)
SELECT json_build_object(
'title', title,
id', id,
'description', description,
'price', price :: MONEY,
'attributes', attributes
) FROM product RETURNING * ;
16. JSON Data Retrieving
SELECT
content ->> 'id' AS id, -- like text
content ->> 'title' AS title, -- like text
content -> 'attributes' AS attributes, -- like json
content #>> '{attributes,sku}' AS sky -- by path
FROM entity_as_json
WHERE type = 'product' AND content #>> '{attributes,sku}' LIKE '%45';
-- Aggregate all table data
SELECT json_agg(content) FROM entity_as_json;
-- Array to json conversion
SELECT array_to_json(tags) FROM book;
17. JSON Append Function
CREATE OR REPLACE FUNCTION json_append(data JSON, insert_data JSON)
RETURNS JSON
IMMUTABLE LANGUAGE SQL AS $$
SELECT ('{' || string_agg(to_json(key) || ':' || value, ',') || '}') :: JSON
FROM (
SELECT * FROM json_each(data)
UNION ALL
SELECT * FROM json_each(insert_data)
) t;
$$;
18. JSON Merge Function
CREATE OR REPLACE FUNCTION json_merge(data JSON, merge_data JSON)
RETURNS JSON
IMMUTABLE LANGUAGE SQL AS $$
SELECT ('{' || string_agg(to_json(key) || ':' || value, ',') || '}') :: JSON
FROM (
WITH to_merge AS (
SELECT * FROM json_each(merge_data)
)
SELECT * FROM json_each(data) WHERE key NOT IN (SELECT key FROM to_merge)
UNION ALL
SELECT * FROM to_merge
) t;
$$;
19. Check Constraint
CREATE TABLE web_user (
id SERIAL PRIMARY KEY,
username VARCHAR(255) UNIQUE NOT NULL CHECK (trim(username) <> ''),
email VARCHAR(255) UNIQUE NOT NULL CHECK (valid_email(email)),
password CHARACTER(40) NOT NULL CHECK (char_length(password) = 40),
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated TIMESTAMP
);
CREATE EXTENSION pgcrypto;
INSERT INTO web_user VALUES (
'2', 'foo', 'abramchenkoa@bar.com', ENCODE(DIGEST('test', 'sha1'), 'hex')
);
20. Domain and Citext Extension
CREATE EXTENSION citext;
-- Create data type like email RFC5322
CREATE DOMAIN email AS citext
CHECK ( value ~ '^[a-zA-Z0-9.!#$%&''*+/=?^_`{|}~-]' ||
'+@[a-zA-Z0-9](?:[a-zA-Z0-9-]' ||
'{0,61}[a-zA-Z0-9])?(?:.[a-zA-Z0-9]' ||
'(?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$'
);
21. Write functions on Perl, Python, JS, Ruby, PHP
CREATE EXTENSION plperlu;
CREATE FUNCTION valid_email(text)
RETURNS boolean
LANGUAGE plperlu
IMMUTABLE LEAKPROOF STRICT AS
$$
use Email::Valid;
my $email = shift;
Email::Valid->address($email) or die "Invalid email address: $emailn";
return 'true';
$$;
22. Full Text Search
-- Add a new column
ALTER TABLE book ADD COLUMN search_fields TSVECTOR;
-- Fill the column for searching
UPDATE book
SET search_fields = to_tsvector(
'english',
book.title || ' ' || array_to_string(book.tags, ' ')
);
-- Add index
CREATE INDEX textsearch_idx ON book USING GIN (search_fields);
23. Search Queries
-- Get current text search config
SELECT get_current_ts_config(); -- english
-- Show all available text search configs
SELECT * FROM pg_ts_config;
-- Search examples
SELECT * FROM book
WHERE search_fields @@ to_tsquery('high & postgre:* & 9.6');
SELECT * FROM book
WHERE search_fields @@ plainto_tsquery(get_current_ts_config(), 'postgresql performance') ;
-- Displays query matching, how title matches the query
SELECT id, title, ts_headline(title, q) FROM book, to_tsquery('postgre:* & performance') AS q
WHERE setweight(to_tsvector('english', title),'A')
|| setweight(to_tsvector('english', content), 'B') @@ q;
24. Search By Trigrams
-- Enable extension
CREATE EXTENSION pg_trgm;
-- Add index
CREATE INDEX trgm_idx ON book USING GIST (title gist_trgm_ops);
-- How similar are the arguments
SELECT title, similarity(title, 'Postgre') AS sml
FROM book WHERE title % 'Postgre'
ORDER BY sml DESC;
-- How similar are the first string and the most similar word of the second string
SELECT title, word_similarity(title, 'Postgre') AS sml
FROM book WHERE title %> 'Postgre'
ORDER BY sml DESC;
25. Ltree Hierarchical Data Type
-- Enable extension
CREATE EXTENSION ltree;
-- Store branch like
CREATE TABLE comment (
id SERIAL PRIMARY KEY,
message TEXT,
branch LTREE NOT NULL,
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-- Add index
CREATE INDEX ON comment USING GIST (branch);
26. Ltree Data Manipulation
INSERT INTO comment (message, branch) VALUES ('Comment 1', '0');
INSERT INTO comment (message, branch) VALUES ('Comment 1.1', '0.1');
INSERT INTO comment (message, branch) VALUES ('Comment 2', '0');
INSERT INTO comment (message, branch) VALUES ('Comment 2.1', '0.3');
INSERT INTO comment (message, branch) VALUES ('Comment 2.2', '0.3');
INSERT INTO comment (message, branch) VALUES ('Comment 2.2.1', '0.3.4');
-- Сhildren of the third message
SELECT * FROM comment WHERE branch <@ '0.3';
-- Get by lquery
SELECT * FROM comment WHERE branch ~ '*.3.*'::lquery;