পোস্টগ্রেএসকিউএল-এর জন্য উপস্থিত না থাকলে ডেটাবেস তৈরি করুন সিমুলেট করুন?


115

আমি এমন একটি ডাটাবেস তৈরি করতে চাই যা জেডিবিসি-র মাধ্যমে নেই। মাইএসকিউএল থেকে আলাদা, পোস্টগ্রিসকিউএল create if not existsসিনট্যাক্স সমর্থন করে না । এটি সম্পাদন করার সর্বোত্তম উপায় কী?

অ্যাপ্লিকেশনটি ডাটাবেসের উপস্থিতি আছে কিনা তা জানে না। এটি যাচাই করা উচিত এবং ডাটাবেস উপস্থিত থাকলে এটি ব্যবহার করা উচিত। সুতরাং কাঙ্ক্ষিত ডাটাবেসের সাথে সংযোগ স্থাপনটি বোধগম্য এবং যদি ডাটাবেসের অস্তিত্বের কারণে সংযোগ ব্যর্থ হয় তবে এটি নতুন ডাটাবেস তৈরি করতে হবে (ডিফল্ট postgresডাটাবেসের সাথে সংযুক্ত হয়ে )। আমি পোস্টগ্রিসের দ্বারা ফিরে আসা ত্রুটি কোডটি যাচাই করেছিলাম তবে প্রজাতির মতো কোনও প্রাসঙ্গিক কোড খুঁজে পেলাম না।

এটি অর্জনের জন্য আরেকটি পদ্ধতি হ'ল postgresডাটাবেসের সাথে সংযোগ স্থাপন করা এবং পছন্দসই ডাটাবেস রয়েছে কিনা তা পরীক্ষা করে সেই অনুযায়ী ব্যবস্থা নেওয়া। দ্বিতীয়টি কাজটি করতে কিছুটা ক্লান্তিকর।

পোস্টগ্রিসে এই কার্যকারিতাটি অর্জন করার কোনও উপায় আছে কি?

উত্তর:


111

বিধিনিষেধ

আপনি সিস্টেম ক্যাটালগ জিজ্ঞাসা করতে পারেন pg_database- একই ডাটাবেস ক্লাস্টারের যে কোনও ডাটাবেস থেকে অ্যাক্সেসযোগ্য। জটিল অংশটি হ'ল CREATE DATABASEকেবলমাত্র একটি বিবৃতি হিসাবে কার্যকর করা যেতে পারে। ম্যানুয়াল:

CREATE DATABASE লেনদেনের ব্লকের ভিতরে কার্যকর করা যায় না।

সুতরাং এটি সরাসরি কোনও ফাংশন বা DOবিবৃতিতে চালানো যায় না , যেখানে এটি স্পষ্টভাবে কোনও লেনদেনের ব্লকের ভিতরে থাকবে।

(পোস্টগ্রিস ১১-এর সাথে প্রবর্তিত এসকিউএল পদ্ধতিগুলি এটির সাথে কোনওভাবেই সহায়তা করতে পারে না ))

পিএসএইচএল এর মধ্যে থেকে কার্যবিধির

শর্তসাপেক্ষে ডিডিএল বিবৃতি কার্যকর করে আপনি পিএসকিএল এর মধ্যে থেকে এটিকে ঘিরে কাজ করতে পারেন:

SELECT 'CREATE DATABASE mydb'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec

ম্যানুয়াল:

\gexec

সার্ভারে বর্তমান ক্যোয়ারী বাফার প্রেরণ করে, তারপরে কোয়েরির আউটপুট (প্রতিটি যদি থাকে) এর প্রতিটি সারিটির প্রতিটি কলামকে এসকিউএল স্টেটমেন্ট হিসাবে কার্যকর করা হয়।

শেল থেকে কার্যকরী

আপনার সাথে \gexecকেবল একবার পিএসকিএল কল করা দরকার :

echo "SELECT 'CREATE DATABASE mydb' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mydb')\gexec" | psql

আপনার সংযোগের জন্য আপনার আরও পিএসকিএল বিকল্পের প্রয়োজন হতে পারে; ভূমিকা, বন্দর, পাসওয়ার্ড, ... দেখুন:

একই সঙ্গে বলা যায় না psql -c "SELECT ...\gexec"যেহেতু \gexecএকটি psql মেটা-কমান্ড এবং -cবিকল্প একটি একক আশা কমান্ড , যার জন্য ম্যানুয়াল পদ বলে:

commandহয় অবশ্যই একটি কমান্ড স্ট্রিং হতে হবে যা সার্ভার দ্বারা সম্পূর্ণরূপে পার্সযোগ্য (যেমন, এটিতে কোনও পিএসকিএল-নির্দিষ্ট বৈশিষ্ট্য নেই), বা একক ব্যাকস্ল্যাশ কমান্ড। সুতরাং আপনি কোনও -cবিকল্পের মধ্যে এসকিউএল এবং পিএসকিএল মেটা-কমান্ডগুলি মিশ্রিত করতে পারবেন না ।

পোস্টগ্রিস লেনদেনের মধ্যে থেকেই কার্যবিধির

আপনি dblinkবর্তমান ডাটাবেসে ফিরে সংযোগ ব্যবহার করতে পারেন যা লেনদেনের ব্লকের বাইরে চলে। এর ফলে প্রভাবগুলিও আবার ঘোরানো যায় না।

এটির জন্য অতিরিক্ত মডিউল dblink ইনস্টল করুন (প্রতি ডাটাবেস একবার):

তারপর:

DO
$do$
BEGIN
   IF EXISTS (SELECT FROM pg_database WHERE datname = 'mydb') THEN
      RAISE NOTICE 'Database already exists';  -- optional
   ELSE
      PERFORM dblink_exec('dbname=' || current_database()  -- current db
                        , 'CREATE DATABASE mydb');
   END IF;
END
$do$;

আবার, আপনার সংযোগের জন্য আরও বেশি পিএসকিএল বিকল্পের প্রয়োজন হতে পারে। অর্টউইনের যুক্ত উত্তর দেখুন:

ডিবিলিংকের বিশদ ব্যাখ্যা:

আপনি এটি বারবার ব্যবহারের জন্য একটি ফাংশন করতে পারেন।


দূরবর্তী থেকে এডাব্লুএস আরডিএস পোস্টগ্র্রেসে একটি ডাটাবেস তৈরি করার সময় আমি এ নিয়ে সমস্যায় পড়েছি। আরডিএস মাস্টার ব্যবহারকারী কোনও সুপার ব্যবহারকারী নয় এবং তাই এটি ব্যবহারের অনুমতি নেই dblink_connect
ওন্দ্রেজ বার্কার্ট

যদি আপনার কাছে সুপারস সুবিধা না থাকে তবে আপনি সংযোগের জন্য একটি পাসওয়ার্ড ব্যবহার করতে পারেন। বিশদ: dba.stackexchange.com/a/105186/3684
এরউইন ব্র্যান্ডস্টেটার

কৌতুকের মতো কাজ করেছে, ডকারের ধারকের ভিতরে একটি init.sql স্ক্রিপ্টের মধ্যে ব্যবহৃত। ধন্যবাদ!
মিশেল জে রবার্টস

\gexecশেল থেকে প্রথম ক্যোয়ারী চালানোর সময় আমাকে ফেলে দিতে হয়েছিল , তবে এটি কার্যকর হয়েছিল।
ফিলবট 3

117

অন্য একটি বিকল্প, কেবলমাত্র যদি আপনি শেল স্ক্রিপ্ট রাখতে চান যা ডেটাবেস তৈরি করে না যদি এটি উপস্থিত না থাকে এবং অন্যথায় কেবল যেমন হয় তেমন রাখে:

psql -U postgres -tc "SELECT 1 FROM pg_database WHERE datname = 'my_db'" | grep -q 1 || psql -U postgres -c "CREATE DATABASE my_db"

আমি এটি ডিওপস বিধানের স্ক্রিপ্টগুলিতে সহায়ক বলে মনে করেছি, যা আপনি একই উদাহরণে একাধিকবার চালাতে চাইতে পারেন।


এটি আমার পক্ষে কাজ করে না। c:\Program Files\PostgreSQL\9.6\bin $ psql.exe -U admin -tc "SELECT 1 FROM pg_database WHERE datname = 'my_db'" | grep -q 1 || psql -U admin -c "CREATE DATABASE my_db" 'grep' is not recognized as an internal or external command, operable program or batch file.আমি কি ভুল করছি ?
আন্তন অনিকিভ

2
আপনি না grepআপনার পাথ হবে। উইন্ডোজে, grepডিফল্টরূপে ইনস্টল করা হয় না। gnu grep windowsউইন্ডোজে কাজ করতে পারে এমন কোনও সংস্করণ খুঁজতে আপনি অনুসন্ধান করতে পারেন ।
রোড

থেক্স @ রড আমি গ্রেপ ইনস্টল করার পরে এই স্ক্রিপ্টটি আমার পক্ষে কাজ করেছিল।
আন্তন অনিকিভ

@ অ্যান্টোনিকিকেভ: গ্রেপ ছাড়াই একটি সিএসকিএল কল দিয়ে করা যেতে পারে। আমি আমার উত্তরের সমাধান যুক্ত করেছি।
এরউইন ব্র্যান্ডস্টেটার

1
সংযোগ সম্ভব কিনা তা যাচাই করার জন্য আমি প্রথমে আমাদের পিজি_সেট্রি দরকারী মনে করি; যদি কোনও সংযোগ উপলব্ধ না হয় (ভুল হোস্টনাম, নেটওয়ার্ক ডাউন ইত্যাদি), স্ক্রিপ্টটি ডাটাবেস তৈরি করার চেষ্টা করবে এবং সম্ভবত বিভ্রান্তিকর ত্রুটি বার্তাটি দিয়ে ব্যর্থ হবে
অলিভার

8

আমাকে কিছুটা বর্ধিত সংস্করণ ব্যবহার করা উচিত ছিল: ইরভিন ব্র্যান্ডসেট্টার ব্যবহৃত:

DO
$do$
DECLARE
  _db TEXT := 'some_db';
  _user TEXT := 'postgres_user';
  _password TEXT := 'password';
BEGIN
  CREATE EXTENSION IF NOT EXISTS dblink; -- enable extension 
  IF EXISTS (SELECT 1 FROM pg_database WHERE datname = _db) THEN
    RAISE NOTICE 'Database already exists';
  ELSE
    PERFORM dblink_connect('host=localhost user=' || _user || ' password=' || _password || ' dbname=' || current_database());
    PERFORM dblink_exec('CREATE DATABASE ' || _db);
  END IF;
END
$do$

আমাকে dblinkএক্সটেনশন সক্ষম করতে হয়েছিল , আমাকে dblink এর শংসাপত্রও সরবরাহ করতে হয়েছিল। Postgres 9.4 সঙ্গে কাজ করে।


7

আপনি যদি ডেটাটির বিষয়ে চিন্তা না করেন তবে আপনি প্রথমে ডাটাবেসটি ফেলে দিতে পারেন এবং তারপরে এটি পুনরায় তৈরি করতে পারেন:

DROP DATABASE IF EXISTS dbname;
CREATE DATABASE dbname;

খুব মার্জিত সমাধান। শুধু ডাটাবেসের ব্যাক আপ করতে প্রথমে আপনি ভুলবেন না না তথ্য সম্পর্কে যত্ন। পরিস্থিতি পরীক্ষার জন্য যদিও এটি আমার পছন্দসই সমাধান।
ল্যারিক্স ডিসিদুয়া

6

পোস্টগ্রি সমর্থন করে না IF NOT EXISTSজন্য CREATE DATABASEবিবৃতি। এটি কেবল সমর্থিত CREATE SCHEMA। তদুপরি CREATE DATABASEলেনদেনে জারী করা যায় না তাই এটি DOব্যতিক্রম ধরা ব্যতীত হতে পারে না ।

যখন CREATE SCHEMA IF NOT EXISTSজারি করা হয় এবং স্কিমা ইতিমধ্যে উপস্থিত থাকে তখন নকল বস্তুর তথ্যের সাথে বিজ্ঞপ্তিটি (ত্রুটি নয়) উত্থাপিত হয়।

এই সমস্যাগুলি সমাধান করার জন্য আপনাকে dblinkএক্সটেনশন ব্যবহার করতে হবে যা ডেটাবেস সার্ভারের সাথে একটি নতুন সংযোগ খোলে এবং লেনদেন না করেই কোয়েরি চালায়। আপনি খালি স্ট্রিং সরবরাহের সাথে সংযোগের প্যারামিটারগুলি পুনরায় ব্যবহার করতে পারেন।

নীচে এমন PL/pgSQLকোড রয়েছে যা সম্পূর্ণরূপে CREATE DATABASE IF NOT EXISTSএকই আচরণের সাথে অনুকরণ করে CREATE SCHEMA IF NOT EXISTS। এটি CREATE DATABASEমাধ্যমে কল করে dblink, ধরুন duplicate_databaseব্যতিক্রম (যা জারি করা হয় যখন ডাটাবেস ইতিমধ্যে উপস্থিত থাকে) এবং প্রচারের সাথে নোটিশে রূপান্তর করে errcode। স্ট্রিং মেসেজটি , skippingএকইভাবে সংযুক্ত হয়েছে যেভাবে এটি হয় CREATE SCHEMA IF NOT EXISTS

CREATE EXTENSION IF NOT EXISTS dblink;

DO $$
BEGIN
PERFORM dblink_exec('', 'CREATE DATABASE testdb');
EXCEPTION WHEN duplicate_database THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
END
$$;

এই সমাধানটি অন্য জবাবগুলির মতো কোনও বর্ণের শর্ত ছাড়াই, যেখানে ডাটাবেসটি উপস্থিত রয়েছে এবং তার নিজস্ব তৈরি কিনা তা যাচাই করার মধ্যে বহিরাগত প্রক্রিয়া (বা একই স্ক্রিপ্টের অন্য উদাহরণ) দ্বারা তৈরি করা যেতে পারে।

তদ্ব্যতীত যখন CREATE DATABASEডাটাবেসের চেয়ে অন্য ত্রুটিটি ব্যর্থ হয় তবে এই ত্রুটিটি ত্রুটি হিসাবে প্রচারিত হয় এবং নীরবে বাদ দেওয়া হয় না। শুধুমাত্র duplicate_databaseত্রুটির জন্য ধরা আছে । সুতরাং এটি সত্যিই IF NOT EXISTSউচিত হিসাবে আচরণ করে ।

আপনি এই কোডটিকে নিজের ফাংশনে রাখতে পারেন, এটিকে সরাসরি বা লেনদেন থেকে কল করতে পারেন। কেবল রোলব্যাক (পুনরুদ্ধার করা ডাটাবেস) কাজ করবে না।

আউটপুট পরীক্ষা করা (ডিও এর মাধ্যমে দু'বার বলা হয় এবং তারপরে সরাসরি):

$ sudo -u postgres psql
psql (9.6.12)
Type "help" for help.

postgres=# \set ON_ERROR_STOP on
postgres=# \set VERBOSITY verbose
postgres=# 
postgres=# CREATE EXTENSION IF NOT EXISTS dblink;
CREATE EXTENSION
postgres=# DO $$
postgres$# BEGIN
postgres$# PERFORM dblink_exec('', 'CREATE DATABASE testdb');
postgres$# EXCEPTION WHEN duplicate_database THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
postgres$# END
postgres$# $$;
DO
postgres=# 
postgres=# CREATE EXTENSION IF NOT EXISTS dblink;
NOTICE:  42710: extension "dblink" already exists, skipping
LOCATION:  CreateExtension, extension.c:1539
CREATE EXTENSION
postgres=# DO $$
postgres$# BEGIN
postgres$# PERFORM dblink_exec('', 'CREATE DATABASE testdb');
postgres$# EXCEPTION WHEN duplicate_database THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
postgres$# END
postgres$# $$;
NOTICE:  42P04: database "testdb" already exists, skipping
LOCATION:  exec_stmt_raise, pl_exec.c:3165
DO
postgres=# 
postgres=# CREATE DATABASE testdb;
ERROR:  42P04: database "testdb" already exists
LOCATION:  createdb, dbcommands.c:467

1
এটি বর্তমানে এখানে একমাত্র সঠিক উত্তর, যা জাতিদের শর্তে ভুগছে না এবং প্রয়োজনীয় নির্বাচনী ত্রুটি পরিচালনা পরিচালনা করে। এটি সত্যই দুঃখের বিষয় যে এই উত্তরটি (সম্পূর্ণ সঠিক নয়) শীর্ষ উত্তর সত্ত্বেও আরও 70 পয়েন্ট সংগ্রহ করার পরে উপস্থিত হয়েছিল।
vog

2
ঠিক আছে, অন্যান্য উত্তরগুলি ঘটতে পারে এমন সমস্ত সম্ভাব্য কোণার কেস পরিচালনা করার জন্য যথাযথ নয়। আপনি আমার পিএল / পিজিএসকিউএল কোডটিকে সমান্তরালে আরও বার কল করতে পারেন এবং এটি ব্যর্থ হয় না।
পালি

1

আপনি যদি শেল ব্যবহার করতে পারেন তবে চেষ্টা করুন

psql -U postgres -c 'select 1' -d $DB &>dev/null || psql -U postgres -tc 'create database $DB'

আমি মনে করি এর psql -U postgres -c "select 1" -d $DBচেয়ে সহজ SELECT 1 FROM pg_database WHERE datname = 'my_db'এবং কেবল এক প্রকারের উদ্ধৃতি প্রয়োজন, এর সাথে একত্রিত করা সহজ sh -c

আমি আমার জবাবদিহি কাজে এটি ব্যবহার করি

- name: create service database
  shell: docker exec postgres sh -c '{ psql -U postgres -tc "SELECT 1" -d {{service_name}} &> /dev/null && echo -n 1; } || { psql -U postgres -c "CREATE DATABASE {{service_name}}"}'
  register: shell_result
  changed_when: "shell_result.stdout != '1'"

0

কেবল createdbসিএলআই সরঞ্জাম ব্যবহার করে ডাটাবেস তৈরি করুন :

PGHOST="my.database.domain.com"
PGUSER="postgres"
PGDB="mydb"
createdb -h $PGHOST -p $PGPORT -U $PGUSER $PGDB

ডাটাবেস উপস্থিত থাকলে, এটি একটি ত্রুটি ফিরিয়ে দেবে:

createdb: database creation failed: ERROR:  database "mydb" already exists

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.