क्या आप दैनिक आधार पर Postgres के साथ काम करते हैं? पोस्टग्रेज से बात करने वाला एप्लिकेशन कोड लिखें? फिर नीचे दिए गए छोटे आकार के SQL स्निपेट देखें जो आपको तेज़ी से काम करने में मदद कर सकते हैं!
एक स्टेटमेंट में कई पंक्तियां डालें
INSERT कथन एक कथन में एक से अधिक पंक्तियाँ सम्मिलित कर सकता है:
INSERT INTO planets (name, gravity)
VALUES ('earth', 9.8),
('mars', 3.7),
('jupiter', 23.1);
INSERT यहां क्या कर सकता है, इसके बारे में और पढ़ें।
एक पंक्ति डालें और स्वचालित रूप से असाइन किए गए मान लौटाएं
डिफ़ॉल्ट/धारावाहिक/पहचान संरचनाओं के साथ स्वत:उत्पन्न मान रिटर्निंग क्लॉज का उपयोग करके INSERT कथन द्वारा वापस किया जा सकता है। एप्लिकेशन कोड के दृष्टिकोण से, इस तरह के INSERT को एक SELECT की तरह निष्पादित किया जाता है जो एक कॉर्डसेट लौटाता है।
-- table with 2 column values auto-generated on INSERT
CREATE TABLE items (
slno serial PRIMARY KEY,
name text NOT NULL,
created_at timestamptz DEFAULT now()
);
INSERT INTO items (name)
VALUES ('wooden axe'),
('loom'),
('eye of ender')
RETURNING name, slno, created_at;
-- returns:
-- name | slno | created_at
-- --------------+------+-------------------------------
-- wooden axe | 1 | 2020-08-17 05:35:45.962725+00
-- loom | 2 | 2020-08-17 05:35:45.962725+00
-- eye of ender | 3 | 2020-08-17 05:35:45.962725+00
ऑटोजेनरेटेड UUID प्राथमिक कुंजी
यूयूआईडी का उपयोग कभी-कभी विभिन्न कारणों से प्राथमिक कुंजी के बजाय किया जाता है। यहां बताया गया है कि आप सीरियल या पहचान के बजाय यूयूआईडी का उपयोग कर सकते हैं:
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE TABLE items (
id uuid DEFAULT uuid_generate_v4(),
name text NOT NULL
);
INSERT INTO items (name)
VALUES ('wooden axe'),
('loom'),
('eye of ender')
RETURNING id, name;
-- returns:
-- id | name
-- --------------------------------------+--------------
-- 1cfaae8c-61ff-4e82-a656-99263b7dd0ae | wooden axe
-- be043a89-a51b-4d8b-8378-699847113d46 | loom
-- 927d52eb-c175-4a97-a0b2-7b7e81d9bc8e | eye of ender
सम्मिलित करें यदि मौजूद नहीं है, तो अपडेट करें अन्यथा
Postgres 9.5 और बाद के संस्करण में, आप ऊपर कर सकते हैं सीधे ON CONFLICTconstruct का उपयोग करके:
CREATE TABLE parameters (
key TEXT PRIMARY KEY,
value TEXT
);
-- when "key" causes a constraint violation, update the "value"
INSERT INTO parameters (key, value)
VALUES ('port', '5432')
ON CONFLICT (key) DO
UPDATE SET value=EXCLUDED.value;
पंक्तियों को एक टेबल से दूसरी टेबल में कॉपी करें
INSERT स्टेटमेंट में एक फॉर्म होता है, जहां एक SELECTstatement द्वारा मूल्यों की आपूर्ति की जा सकती है। पंक्तियों को एक तालिका से दूसरी तालिका में कॉपी करने के लिए इसका उपयोग करें:
-- copy between tables with similar columns
INSERT INTO pending_quests
SELECT * FROM quests
WHERE progress < 100;
-- supply some values from another table, some directly
INSERT INTO archived_quests
SELECT now() AS archival_date, *
FROM quests
WHERE completed;
यदि आप तालिकाओं को बल्क-लोड करना चाहते हैं, तो COPY कमांड भी देखें, जिसका उपयोग किसी टेक्स्ट या CSV फ़ाइल से पंक्तियों को सम्मिलित करने के लिए किया जा सकता है।
हटाएं और हटाई गई जानकारी लौटाएं
आप RETURNING
का उपयोग कर सकते हैं बल्क-डिलीट स्टेटमेंट का उपयोग करके हटाए गए पंक्तियों से मान वापस करने के लिए क्लॉज:
-- return the list of customers whose licenses were deleted after expiry
DELETE FROM licenses
WHERE now() > expiry_date
RETURNING customer_name;
पंक्तियों को एक टेबल से दूसरी टेबल में ले जाएं
CTEswith DELETE .. RETURNING का उपयोग करके आप एक ही स्टेटमेंट में पंक्तियों को एक टेबल से दूसरी टेबल पर ले जा सकते हैं। :
-- move yet-to-start todo items from 2020 to 2021
WITH ah_well AS (
DELETE FROM todos_2020
WHERE NOT started
RETURNING *
)
INSERT INTO todos_2021
SELECT * FROM ah_well;
पंक्तियों को अपडेट करें और अपडेट किए गए मान लौटाएं
RETURNING क्लॉज का उपयोग UPDATEs में भी किया जा सकता है। ध्यान दें कि इस तरह से केवल अपडेट किए गए कॉलम के नए मान लौटाए जा सकते हैं।
-- grant random amounts of coins to eligible players
UPDATE players
SET coins = coins + (100 * random())::integer
WHERE eligible
RETURNING id, coins;
यदि आपको अद्यतन कॉलम के मूल मूल्य की आवश्यकता है:यह स्वयं-जुड़ने के माध्यम से संभव है, लेकिन परमाणुता की कोई गारंटी नहीं है। एक SELECT .. FOR
UPDATE
. का उपयोग करके देखें इसके बजाय।
कुछ रैंडम पंक्तियों को अपडेट करें और अपडेट की गई पंक्तियों को वापस करें
यहां बताया गया है कि आप किसी तालिका से कुछ यादृच्छिक पंक्तियों को कैसे चुन सकते हैं, उन्हें अपडेट कर सकते हैं और अपडेट की गई पंक्तियों को एक बार में वापस कर सकते हैं:
WITH lucky_few AS (
SELECT id
FROM players
ORDER BY random()
LIMIT 5
)
UPDATE players
SET bonus = bonus + 100
WHERE id IN (SELECT id FROM lucky_few)
RETURNING id;
किसी अन्य तालिका की तरह तालिका बनाएं
तालिका बनाएं का उपयोग करें .. समान कॉलम वाली तालिका बनाने के लिए निर्माण की तरह निर्माण करें:
CREATE TABLE to_be_audited (LIKE purchases);
डिफ़ॉल्ट रूप से यह समान अनुक्रमणिका, बाधाएं, डिफ़ॉल्ट इत्यादि नहीं बनाता है। ऐसा करने के लिए, पोस्टग्रेस से स्पष्ट रूप से पूछें:
CREATE TABLE to_be_audited (LIKE purchases INCLUDING ALL);
पूरा वाक्य-विन्यास यहां देखें।
पंक्तियों के रैंडम सेट को दूसरी तालिका में निकालें
पोस्टग्रेज 9.5 के बाद से, तालिका से पंक्तियों का एक नमूना निकालने के लिए TABLESAMPLE सुविधा उपलब्ध है। वर्तमान में दो नमूनाकरण विधियां हैं, और बर्नौली आमतौर पर वही होता है जो आप चाहते हैं:
-- copy 10% of today's purchases into another table
INSERT INTO to_be_audited
SELECT *
FROM purchases
TABLESAMPLE bernoulli(10)
WHERE transaction_date = CURRENT_DATE;
सिस्टम टेबलसैंपलिंग विधि तेज है, लेकिन एक समान वितरण नहीं लौटाती है। अधिक जानकारी के लिए दस्तावेज़ देखें।
चुनिंदा क्वेरी से तालिका बनाएं
आप तालिका बनाएं का उपयोग कर सकते हैं .. तालिका बनाने के लिए निर्माण के रूप में और एक चयन क्वेरी से इसे पॉप्युलेट करें, सभी एक बार में:
CREATE TABLE to_be_audited AS
SELECT *
FROM purchases
TABLESAMPLE bernoulli(10)
WHERE transaction_date = CURRENT_DATE;
परिणामी तालिका बिना किसी प्रश्न के एक भौतिक दृश्य की तरह है। CREATE TABLE के बारे में और पढ़ें .. यहाँ के रूप में।
अनलॉग टेबल बनाएं
अनलॉग किया गया टेबल WAL रिकॉर्ड्स द्वारा समर्थित नहीं हैं। इसका मतलब है कि ऐसी तालिकाओं के अपडेट और डिलीट तेजी से होते हैं, लेकिन वे क्रैश-सहनशील नहीं होते हैं और उन्हें दोहराया नहीं जा सकता है।
CREATE UNLOGGED TABLE report_20200817 (LIKE report_v3);
अस्थायी टेबल बनाएं
अस्थायी टेबल्स पूरी तरह से अनलॉग टेबल हैं, जिनका जीवनकाल छोटा होता है। वे सत्र के अंत में (डिफ़ॉल्ट) या लेन-देन के अंत में अपने आप नष्ट हो जाते हैं।
अस्थायी तालिकाओं में डेटा सभी सत्रों में साझा नहीं किया जा सकता है। एकाधिक सत्र एक ही नाम से अस्थायी तालिकाएँ बना सकते हैं।
-- temp table for duration of the session
CREATE TEMPORARY TABLE scratch_20200817_run_12 (LIKE report_v3);
-- temp table that will self-destruct after current transaction
CREATE TEMPORARY TABLE scratch_20200817_run_12
(LIKE report_v3)
ON COMMIT DROP;
-- temp table that will TRUNCATE itself after current transaction
CREATE TEMPORARY TABLE scratch_20200817_run_12
(LIKE report_v3)
ON COMMIT DELETE ROWS;
टिप्पणियां जोड़ें
डेटाबेस में किसी भी ऑब्जेक्ट में टिप्पणियाँ जोड़ी जा सकती हैं। pg_dump सहित कई उपकरण इन्हें समझते हैं। सफाई के दौरान एक उपयोगी टिप्पणी बस एक टन परेशानी से बच सकती है!
COMMENT ON INDEX idx_report_last_updated
IS 'needed for the nightly report app running in dc-03';
COMMENT ON TRIGGER tgr_fix_column_foo
IS 'mitigates the effect of bug #4857';
सलाहकार ताले
एडवाइजरी लॉक का उपयोग समान . से जुड़े दो ऐप्स के बीच क्रियाओं को समन्वयित करने के लिए किया जा सकता है डेटाबेस। उदाहरण के लिए, आप एक निश्चित ऑपरेशन के लिए वैश्विक, डिस्ट्रिब्यूटेडम्यूटेक्स को लागू करने के लिए इस सुविधा का उपयोग कर सकते हैं। इसके बारे में यहाँ thedocs में पढ़ें।
-- client 1: acquire a lock
SELECT pg_advisory_lock(130);
-- ... do work ...
SELECT pg_advisory_unlock(130);
-- client 2: tries to do the same thing, but mutually exclusive
-- with client 1
SELECT pg_advisory_lock(130); -- blocks if anyone else has held lock with id 130
-- can also do it without blocking:
SELECT pg_try_advisory_lock(130);
-- returns false if lock is being held by another client
-- otherwise acquires the lock then returns true
एरेज़, JSON एरेज़ या स्ट्रिंग्स में एग्रीगेट करें
Postgres समग्र कार्य प्रदान करता है जो मानों को GROUP . में संयोजित करता है टॉयल्ड सरणियाँ, JSON सरणियाँ या तार:
-- get names of each guild, with an array of ids of players that
-- belong to that guild
SELECT guilds.name AS guild_name, array_agg(players.id) AS players
FROM guilds
JOIN players ON players.guild_id = guilds.id
GROUP BY guilds.id;
-- same but the player list is a CSV string
SELECT guilds.name, string_agg(players.id, ',') -- ...
-- same but the player list is a JSONB array
SELECT guilds.name, jsonb_agg(players.id) -- ...
-- same but returns a nice JSONB object like so:
-- { guild1: [ playerid1, playerid2, .. ], .. }
SELECT jsonb_object_agg(guild_name, players) FROM (
SELECT guilds.name AS guild_name, array_agg(players.id) AS players
FROM guilds
JOIN players ON players.guild_id = guilds.id
GROUP BY guilds.id
) AS q;
आदेश के साथ समुच्चय
जब हम इस विषय पर होते हैं, तो यहां उन मानों के क्रम को सेट करने का तरीका बताया गया है जो कुल फ़ंक्शन को प्रत्येक समूह के भीतर पास किए जाते हैं। :
-- each state with a list of counties sorted alphabetically
SELECT states.name, string_agg(counties.name, ',' ORDER BY counties.name)
FROM states JOIN counties
JOIN states.name = counties.state_name
GROUP BY states.name;
हां, फंक्शन कॉल पैरांथेसिस के अंदर एक अनुगामी ORDER BY क्लॉज है। हां, सिंटैक्स अजीब है।
ऐरे और अननेस्ट
पंक्तियों के एक सेट को बदलने के लिए ARRAY कंस्ट्रक्टर का उपयोग करें, प्रत्येक एक कॉलम के साथ, एक सरणी में। डेटाबेस ड्राइवर (जैसे JDBC) को Postgres arrays को मूल सरणियों में मैप करने में सक्षम होना चाहिए और इसके साथ काम करना आसान हो सकता है।
-- convert rows (with 1 column each) into a 1-dimensional array
SELECT ARRAY(SELECT id FROM players WHERE lifetime_spend > 10000);
unnest फ़ंक्शन उल्टा करता है - यह प्रत्येक आइटम को एक सरणी में तीर में परिवर्तित करता है। वे मूल्यों की सूची के साथ क्रॉस जॉइनिंग में सबसे अधिक उपयोगी होते हैं:
SELECT materials.name || ' ' || weapons.name
FROM weapons
CROSS JOIN UNNEST('{"wood","gold","stone","iron","diamond"}'::text[])
AS materials(name);
-- returns:
-- ?column?
-- -----------------
-- wood sword
-- wood axe
-- wood pickaxe
-- wood shovel
-- gold sword
-- gold axe
-- (..snip..)
चुनिंदा स्टेटमेंट को यूनियन के साथ मिलाएं
आप कई समान चयनों के परिणामों को संयोजित करने के लिए UNION निर्माण का उपयोग कर सकते हैं:
SELECT name FROM weapons
UNION
SELECT name FROM tools
UNION
SELECT name FROM materials;
संयुक्त परिणाम को आगे संसाधित करने के लिए सीटीई का उपयोग करें:
WITH fight_equipment AS (
SELECT name, damage FROM weapons
UNION
SELECT name, damage FROM tools
)
SELECT name, damage
FROM fight_equipment
ORDER BY damage DESC
LIMIT 5;
UNION के समान ही INTERSECT और EXCEPT कंस्ट्रक्शन भी हैं। इन खंडों के बारे में thedocs में पढ़ें।
चयन में त्वरित सुधार:केस, कोलेस और नलिफ़
CASE, COALESCE और NULLIF चयनित डेटा के लिए छोटे-छोटे त्वरित "समाधान" करते हैं। CASE स्विच जैसा है सी-जैसी भाषाओं में:
SELECT id,
CASE WHEN name='typ0' THEN 'typo' ELSE name END
FROM items;
SELECT CASE WHEN rating='G' THEN 'General Audiences'
WHEN rating='PG' THEN 'Parental Guidance'
ELSE 'Other'
END
FROM movies;
COALESCE का उपयोग NULL के बजाय एक निश्चित मान को बदलने के लिए किया जा सकता है।
-- use an empty string if ip is not available
SELECT nodename, COALESCE(ip, '') FROM nodes;
-- try to use the first available, else use '?'
SELECT nodename, COALESCE(ipv4, ipv6, hostname, '?') FROM nodes;
NULLIF दूसरे तरीके से काम करता है, जिससे आप एक निश्चित मान के बजाय NULL का उपयोग कर सकते हैं:
-- use NULL instead of '0.0.0.0'
SELECT nodename, NULLIF(ipv4, '0.0.0.0') FROM nodes;
यादृच्छिक और अनुक्रमिक परीक्षण डेटा जेनरेट करें
यादृच्छिक डेटा उत्पन्न करने के विभिन्न तरीके:
-- 100 random dice rolls
SELECT 1+(5 * random())::int FROM generate_series(1, 100);
-- 100 random text strings (each 32 chars long)
SELECT md5(random()::text) FROM generate_series(1, 100);
-- 100 random text strings (each 36 chars long)
SELECT uuid_generate_v4()::text FROM generate_series(1, 100);
-- 100 random small text strings of varying lengths
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
SELECT gen_random_bytes(1+(9*random())::int)::text
FROM generate_series(1, 100);
-- 100 random dates in 2019
SELECT DATE(
DATE '2019-01-01' + ((random()*365)::int || ' days')::interval
)
FROM generate_series(1, 100);
-- 100 random 2-column data: 1st column integer and 2nd column string
WITH a AS (
SELECT ARRAY(SELECT random() FROM generate_series(1,100))
),
b AS (
SELECT ARRAY(SELECT md5(random()::text) FROM generate_series(1,100))
)
SELECT unnest(i), unnest(j)
FROM a a(i), b b(j);
-- a daily count for 2020, generally increasing over time
SELECT i, ( (5+random()) * (row_number() over()) )::int
FROM generate_series(DATE '2020-01-01', DATE '2020-12-31', INTERVAL '1 day')
AS s(i);
बर्नौली का उपयोग करें तालिका से पंक्तियों की यादृच्छिक संख्या का चयन करने के लिए तालिका नमूनाकरण:
-- select 15% of rows from the table, chosen randomly
SELECT *
FROM purchases
TABLESAMPLE bernoulli(15)
generate_series
Use का उपयोग करें पूर्णांकों, तिथियों और अन्य वृद्धिशील अंतर्निर्मित प्रकारों के अनुक्रमिक मान उत्पन्न करने के लिए:
-- generate integers from 1 to 100
SELECT generate_series(1, 100);
-- call the generated values table as "s" with a column "i", to use in
-- CTEs and JOINs
SELECT i FROM generate_series(1, 100) AS s(i);
-- generate multiples of 3 in different ways
SELECT 3*i FROM generate_series(1, 100) AS s(i);
SELECT generate_series(1, 100, 3);
-- works with dates too: here are all the Mondays in 2020:
SELECT generate_series(DATE '2020-01-06', DATE '2020-12-31', INTERVAL '1 week');
अनुमानित पंक्ति गणना प्राप्त करें
COUNT(*)
. का भयानक प्रदर्शन पोस्टग्रेज की वास्तुकला का शायद सबसे कुरूप उपोत्पाद है। यदि आपको विशाल तालिका के लिए केवल अनुमानित पंक्ति गणना की आवश्यकता है, तो आप सांख्यिकी संग्राहक से पूछताछ करके पूर्ण COUNT से बच सकते हैं:
SELECT relname, n_live_tup FROM pg_stat_user_tables;
विश्लेषण के बाद परिणाम सटीक होता है, और पंक्तियों को संशोधित करने पर उत्तरोत्तर गलत होगा। यदि आप सटीक गणना चाहते हैं तो इसका उपयोग न करें।
अंतराल प्रकार
अंतराल प्रकार का उपयोग न केवल कॉलम डेटाटाइप के रूप में किया जा सकता है, बल्कि तारीख से जोड़ा और घटाया जा सकता है और टाइमस्टैम्प मान:
-- get licenses that expire within the next 7 days
SELECT id
FROM licenses
WHERE expiry_date BETWEEN now() - INTERVAL '7 days' AND now();
-- extend expiry date
UPDATE licenses
SET expiry_date = expiry_date + INTERVAL '1 year'
WHERE id = 42;
बल्क इंसर्ट के लिए बाधा सत्यापन बंद करें
-- add a constraint, set as "not valid"
ALTER TABLE players
ADD CONSTRAINT fk__players_guilds
FOREIGN KEY (guild_id)
REFERENCES guilds(id)
NOT VALID;
-- insert lots of rows into the table
COPY players FROM '/data/players.csv' (FORMAT CSV);
-- now validate the entire table
ALTER TABLE players
VALIDATE CONSTRAINT fk__players_guilds;
किसी तालिका या क्वेरी को CSV फ़ाइल में डंप करें
-- dump the contents of a table to a CSV format file on the server
COPY players TO '/tmp/players.csv' (FORMAT CSV);
-- "header" adds a heading with column names
COPY players TO '/tmp/players.csv' (FORMAT CSV, HEADER);
-- use the psql command to save to your local machine
\copy players TO '~/players.csv' (FORMAT CSV);
-- can use a query instead of a table name
\copy ( SELECT id, name, score FROM players )
TO '~/players.csv'
( FORMAT CSV );
अपनी स्कीमा डिज़ाइन में अधिक मूल डेटा प्रकारों का उपयोग करें
Postgres कई बिल्ट-इन डेटा प्रकारों के साथ आता है। इनमें से किसी एक प्रकार का उपयोग करके आपके एप्लिकेशन को आवश्यक डेटा का प्रतिनिधित्व करने से बहुत सारे एप्लिकेशन कोड सहेजे जा सकते हैं, आपका विकास तेज़ हो सकता है और परिणामस्वरूप कम त्रुटियां हो सकती हैं।
उदाहरण के लिए, यदि आप डेटा प्रकार का उपयोग करके किसी व्यक्ति के स्थान का प्रतिनिधित्व कर रहे हैंpoint
और एक polygon
. के रूप में रुचि का क्षेत्र , आप जांच सकते हैं कि क्या व्यक्ति इस क्षेत्र में है:
-- the @> operator checks if the region of interest (a "polygon") contains
-- the person's location (a "point")
SELECT roi @> person_location FROM live_tracking;
यहां कुछ दिलचस्प पोस्टग्रेज डेटा प्रकार और लिंक दिए गए हैं जहां से आप उनके बारे में अधिक जानकारी प्राप्त कर सकते हैं:
- सी-लाइक एनम प्रकार
- ज्यामितीय प्रकार - बिंदु, बॉक्स, रेखा खंड, रेखा, पथ, बहुभुज, वृत्त
- आईपीवी4, आईपीवी6 और मैक पते
- श्रेणी प्रकार - पूर्णांक, दिनांक और टाइमस्टैम्प श्रेणी
- ऐरे जिनमें किसी भी प्रकार के मान हो सकते हैं
- UUID - यदि आप UUIDs का उपयोग करना चाहते हैं, या केवल 129-बाइट यादृच्छिक पूर्णांकों के साथ काम करना चाहते हैं, तो
uuid
का उपयोग करने पर विचार करें। टाइप करें औरuuid-oscp
यूयूआईडी को स्टोर करने, जेनरेट करने और फ़ॉर्मेट करने का एक्सटेंशन - अंतराल प्रकार का उपयोग करके दिनांक और समय अंतराल
- और निश्चित रूप से हमेशा लोकप्रिय JSON और JSONB
बंडल किए गए एक्सटेंशन
अधिकांश पोस्टग्रेज इंस्टाल में मानक "एक्सटेंशन" का एक गुच्छा शामिल है। एक्सटेंशन इंस्टॉल करने योग्य (और स्वच्छ रूप से अनइंस्टॉल करने योग्य) घटक हैं जो कार्यक्षमता प्रदान करते हैं जो कोर में शामिल नहीं हैं। उन्हें प्रति-डेटाबेस के आधार पर स्थापित किया जा सकता है।
इनमें से कुछ काफी उपयोगी हैं, और उन्हें जानने के लिए कुछ समय बिताना उचित है:
- pg_stat_statements - प्रत्येक SQL क्वेरी के निष्पादन से संबंधित आंकड़े
- auto_explain - (धीमी) क्वेरी की क्वेरी निष्पादन योजना को लॉग करें
- postgres_fdw,dblink andfile_fdw - नियमित तालिकाओं की तरह अन्य डेटा स्रोतों (जैसे दूरस्थ पोस्टग्रेज सर्वर, MySQL सर्वर, सर्वर के फाइल सिस्टम पर फ़ाइलें) तक पहुंचने के तरीके
- citext - एक "केस-असंवेदनशील टेक्स्ट" डेटा प्रकार, जो पूरे स्थान पर निचले () से अधिक कुशल है
- hstore - एक कुंजी-मान डेटा प्रकार
- pgcrypto –SHA हैशिंग फ़ंक्शन, एन्क्रिप्शन