এসকিউএল কোয়েরি কোড পুনরাবৃত্তি রোধ করার জন্য স্ট্রিংগুলি সংঘবদ্ধকরণ বা পদ্ধতিগত পদ্ধতিতে যাওয়ার বিকল্প?


19

অস্বীকৃতি: দয়া করে এমন কেউ হিসাবে আমার সহ্য করুন যিনি কেবল ডাটাবেসগুলি তার কাজের সময়ের একটি ক্ষুদ্র ভগ্নাংশ ব্যবহার করেন। (বেশিরভাগ সময় আমি আমার চাকরিতে সি ++ প্রোগ্রামিং করি তবে প্রতি বিজোড় মাসে আমাকে ওরাকল ডাটাবেসে অনুসন্ধান / ফিক্স / কিছু যুক্ত করতে হবে))

আমার বারবার জটিল এসকিউএল কোয়েরি লিখতে হবে, উভয়ই অ্যাড-হক জিজ্ঞাসার জন্য এবং অ্যাপ্লিকেশনগুলিতে তৈরি প্রশ্নের জন্য, যেখানে প্রশ্নের বড় অংশ যেখানে "কোড" পুনরাবৃত্তি হয়েছিল।

Traditionalতিহ্যবাহী প্রোগ্রামিং ভাষায় এ জাতীয় জঘন্য রচনাগুলি আপনাকে গভীর সমস্যায় ফেলতে পারে, তবুও আমি ( আমি ) এসকিউএল কোয়েরি কোড পুনরাবৃত্তি রোধ করার জন্য কোনও শালীন কৌশল খুঁজে পেতে সক্ষম হয়েছি


সম্পাদনা: 1 ম, আমি উত্তরগুলি যারা আমার মূল উদাহরণে দুর্দান্ত উন্নতি করেছে তা ধন্যবাদ জানাতে চাই । যাইহোক, এই প্রশ্নটি আমার উদাহরণ সম্পর্কে নয়। এটি এসকিউএল কোয়েরিতে পুনরাবৃত্তি সম্পর্কে। এই হিসাবে, উত্তরগুলি ( জ্যাকপি , লেইই ) এখনও পর্যন্ত দেখানোর দুর্দান্ত কাজ করে যে আপনি আরও ভাল প্রশ্ন লিখে পুনরাবৃত্তিকে হ্রাস করতে পারেন । তবে তারপরেও আপনি কিছু পুনরাবৃত্তির মুখোমুখি হন যা আপাতদৃষ্টিতে অপসারণ করা যায় না: এটি আমাকে সর্বদা এসকিউএল দিয়ে ঠাট্টা করে। "Traditionalতিহ্যবাহী" প্রোগ্রামিং ভাষাগুলিতে আমি কোডে পুনরাবৃত্তি হ্রাস করার জন্য যথেষ্ট পরিমাণে রিফ্যাক্টর করতে পারি, তবে এসকিউএল দিয়ে মনে হয় এমন কোনও (?) সরঞ্জাম নেই যা কম পুনরাবৃত্তি বিবরণী শুরু করা ব্যতীত।

মনে রাখবেন যে আমি আবার ওরাকল ট্যাগটি সরিয়ে নিয়েছি, কারণ ডেটাবেস বা স্ক্রিপ্টিং ভাষা নেই যা আরও কিছু পাওয়ার অনুমতি দেয় কিনা তা আমি সত্যই আগ্রহী।


আজ এমন এক রত্ন যা আমি একসাথে আবদ্ধ হয়েছি। এটি মূলত একটি একক টেবিলের কলামগুলির মধ্যে একটি পার্থক্যের প্রতিবেদন করে। নীচের কোডটি দিয়ে স্কিম করুন, esp। শেষে বড় প্রশ্ন। আমি নীচে চালিয়ে যাব।

--
-- Create Table to test queries
--
CREATE TABLE TEST_ATTRIBS (
id NUMBER PRIMARY KEY,
name  VARCHAR2(300) UNIQUE,
attr1 VARCHAR2(2000),
attr2 VARCHAR2(2000),
attr3 INTEGER,
attr4 NUMBER,
attr5 VARCHAR2(2000)
);

--
-- insert some test data
--
insert into TEST_ATTRIBS values ( 1, 'Alfred',   'a', 'Foobar', 33, 44, 'e');
insert into TEST_ATTRIBS values ( 2, 'Batman',   'b', 'Foobar', 66, 44, 'e');
insert into TEST_ATTRIBS values ( 3, 'Chris',    'c', 'Foobar', 99, 44, 'e');
insert into TEST_ATTRIBS values ( 4, 'Dorothee', 'd', 'Foobar', 33, 44, 'e');
insert into TEST_ATTRIBS values ( 5, 'Emilia',   'e', 'Barfoo', 66, 44, 'e');
insert into TEST_ATTRIBS values ( 6, 'Francis',  'f', 'Barfoo', 99, 44, 'e');
insert into TEST_ATTRIBS values ( 7, 'Gustav',   'g', 'Foobar', 33, 44, 'e');
insert into TEST_ATTRIBS values ( 8, 'Homer',    'h', 'Foobar', 66, 44, 'e');
insert into TEST_ATTRIBS values ( 9, 'Ingrid',   'i', 'Foobar', 99, 44, 'e');
insert into TEST_ATTRIBS values (10, 'Jason',    'j', 'Bob',    33, 44, 'e');
insert into TEST_ATTRIBS values (12, 'Konrad',   'k', 'Bob',    66, 44, 'e');
insert into TEST_ATTRIBS values (13, 'Lucas',    'l', 'Foobar', 99, 44, 'e');

insert into TEST_ATTRIBS values (14, 'DUP_Alfred',   'a', 'FOOBAR', 33, 44, 'e');
insert into TEST_ATTRIBS values (15, 'DUP_Chris',    'c', 'Foobar', 66, 44, 'e');
insert into TEST_ATTRIBS values (16, 'DUP_Dorothee', 'd', 'Foobar', 99, 44, 'e');
insert into TEST_ATTRIBS values (17, 'DUP_Gustav',   'X', 'Foobar', 33, 44, 'e');
insert into TEST_ATTRIBS values (18, 'DUP_Homer',    'h', 'Foobar', 66, 44, 'e');
insert into TEST_ATTRIBS values (19, 'DUP_Ingrid',   'Y', 'foo',    99, 44, 'e');

insert into TEST_ATTRIBS values (20, 'Martha',   'm', 'Bob',    33, 88, 'f');

-- Create comparison view
CREATE OR REPLACE VIEW TA_SELFCMP as
select 
t1.id as id_1, t2.id as id_2, t1.name as name, t2.name as name_dup,
t1.attr1 as attr1_1, t1.attr2 as attr2_1, t1.attr3 as attr3_1, t1.attr4 as attr4_1, t1.attr5 as attr5_1,
t2.attr1 as attr1_2, t2.attr2 as attr2_2, t2.attr3 as attr3_2, t2.attr4 as attr4_2, t2.attr5 as attr5_2
from TEST_ATTRIBS t1, TEST_ATTRIBS t2
where t1.id <> t2.id
and t1.name <> t2.name
and t1.name = REPLACE(t2.name, 'DUP_', '')
;

-- NOTE THIS PIECE OF HORRIBLE CODE REPETITION --
-- Create comparison report
-- compare 1st attribute
select 'attr1' as Different,
id_1, id_2, name, name_dup,
CAST(attr1_1 AS VARCHAR2(2000)) as Val1, CAST(attr1_2 AS VARCHAR2(2000)) as Val2
from TA_SELFCMP
where attr1_1 <> attr1_2
or (attr1_1 is null and attr1_2 is not null)
or (attr1_1 is not null and attr1_2 is null)
union
-- compare 2nd attribute
select 'attr2' as Different,
id_1, id_2, name, name_dup,
CAST(attr2_1 AS VARCHAR2(2000)) as Val1, CAST(attr2_2 AS VARCHAR2(2000)) as Val2
from TA_SELFCMP
where attr2_1 <> attr2_2
or (attr2_1 is null and attr2_2 is not null)
or (attr2_1 is not null and attr2_2 is null)
union
-- compare 3rd attribute
select 'attr3' as Different,
id_1, id_2, name, name_dup,
CAST(attr3_1 AS VARCHAR2(2000)) as Val1, CAST(attr3_2 AS VARCHAR2(2000)) as Val2
from TA_SELFCMP
where attr3_1 <> attr3_2
or (attr3_1 is null and attr3_2 is not null)
or (attr3_1 is not null and attr3_2 is null)
union
-- compare 4th attribute
select 'attr4' as Different,
id_1, id_2, name, name_dup,
CAST(attr4_1 AS VARCHAR2(2000)) as Val1, CAST(attr4_2 AS VARCHAR2(2000)) as Val2
from TA_SELFCMP
where attr4_1 <> attr4_2
or (attr4_1 is null and attr4_2 is not null)
or (attr4_1 is not null and attr4_2 is null)
union
-- compare 5th attribute
select 'attr5' as Different,
id_1, id_2, name, name_dup,
CAST(attr5_1 AS VARCHAR2(2000)) as Val1, CAST(attr5_2 AS VARCHAR2(2000)) as Val2
from TA_SELFCMP
where attr5_1 <> attr5_2
or (attr5_1 is null and attr5_2 is not null)
or (attr5_1 is not null and attr5_2 is null)
;

আপনি দেখতে পাচ্ছেন যে, "পার্থক্য প্রতিবেদন" তৈরি করার ক্যোয়ারী একই এসকিউএল নির্বাচন ব্লকটি 5 বার ব্যবহার করে (সহজেই 42 বার হতে পারে!)। এটি আমাকে একেবারে মস্তিষ্কের মৃত হিসাবে আঘাত করেছে (আমি কোডটি লিখার পরেও এটি বলতে পেরেছি), তবে আমি এর কোনও ভাল সমাধান খুঁজে পাইনি।

  • যদি এটি কোনও আসল অ্যাপ্লিকেশন কোডে একটি কোয়েরি হয় তবে আমি একটি ফাংশন লিখতে পারতাম যা এই ক্যোয়ারিকে স্ট্রিং হিসাবে একসাথে আবদ্ধ করে এবং তারপরে আমি স্ট্রিং হিসাবে ক্যোয়ারী চালিয়ে দেব।

    • -> পরীক্ষার এবং রক্ষণাবেক্ষণের জন্য বিল্ডিং স্ট্রিংগুলি ভয়ঙ্কর এবং ভয়ঙ্কর। যদি "অ্যাপ্লিকেশন কোড" PL / SQL এর মতো কোনও ভাষায় লিখিত হয় তবে তা খুব খারাপ লাগে তা ব্যথা করে।
  • বিকল্পভাবে, যদি পিএল / এসকিউএল বা এর মতো থেকে ব্যবহৃত হয়, তবে আমি অনুমান করব যে এই প্রশ্নটি আরও রক্ষণাবেক্ষণের জন্য কিছু পদ্ধতিগত উপায় রয়েছে।

    • -> কোড পুনরাবৃত্তি রোধ করতে কেবল এমন প্রক্রিয়াজাত পদক্ষেপে কোনও একক ক্যোয়ারিতে প্রকাশ করা যেতে পারে এমন কোনও কিছুকে তালিকাভুক্ত করাও ভুল অনুভব করে।
  • যদি এই কোয়েরিটি ডাটাবেসে একটি ভিউ হিসাবে প্রয়োজন হয়, তবে - যতদূর আমি বুঝতে পারি - উপরে বর্ণিত ভিউ সংজ্ঞাটি বজায় রাখা ছাড়া অন্য কোনও উপায় থাকতে পারে না। (!!?)

    • -> আমাকে আসলে 2-পৃষ্ঠার ভিউ সংজ্ঞায় কিছুক্ষণ রক্ষণাবেক্ষণ করতে হয়েছিল যা উপরের বিবৃতিটি খুব বেশি দূরে ছিল না। স্পষ্টতই, এই দৃশ্যে যে কোনও কিছু পরিবর্তনের জন্য একই সাব-স্টেটমেন্টটি অন্য কোনও লাইনে ব্যবহৃত হয়েছিল এবং সেখানে পরিবর্তনের প্রয়োজন ছিল কিনা তা দেখার জন্য দর্শন সংজ্ঞাটির উপরে একটি রিজেক্সএক্স পাঠ্য অনুসন্ধান প্রয়োজন।

সুতরাং, শিরোনামটি যেমন যায় - এ জাতীয় জঘন্য রচনাগুলি রোধ করতে কী কী কৌশল রয়েছে?

উত্তর:


13

আপনি খুব বিনয়ী - আপনার এসকিউএল ভাল এবং সংক্ষিপ্তভাবে লেখা আছে আপনি যে কাজটি হাতে নিয়েছেন তা দিয়ে। কয়েকটি পয়েন্টার:

  • t1.name <> t2.nameসবসময় সত্য হলে t1.name = REPLACE(t2.name, 'DUP_', '')- আপনি প্রাক্তন ড্রপ করতে পারেন
  • সাধারণত আপনি চান union allunionমানে union allতারপর সদৃশ ড্রপ। এটি এই ক্ষেত্রে কোনও union allতাত্পর্যপূর্ণ হতে পারে তবে আপনি স্পষ্টভাবে কোনও সদৃশ বাদ দিতে না চাইলে সর্বদা ব্যবহার করা ভাল অভ্যাস।
  • আপনি যদি ভারচারে কাস্টিংয়ের পরে সংখ্যাসূচক তুলনাগুলি করতে ইচ্ছুক হন তবে নিম্নলিখিতটি বিবেচনা করার মতো হতে পারে:

    create view test_attribs_cast as 
    select id, name, attr1, attr2, cast(attr3 as varchar(2000)) as attr3, 
           cast(attr4 as varchar(2000)) as attr4, attr5
    from test_attribs;
    
    create view test_attribs_unpivot as 
    select id, name, 1 as attr#, attr1 as attr from test_attribs_cast union all
    select id, name, 2, attr2 from test_attribs_cast union all
    select id, name, 3, attr3 from test_attribs_cast union all
    select id, name, 4, attr4 from test_attribs_cast union all
    select id, name, 5, attr5 from test_attribs_cast;
    
    select 'attr'||t1.attr# as different, t1.id as id_1, t2.id as id_2, t1.name, 
           t2.name as name_dup, t1.attr as val1, t2.attr as val2
    from test_attribs_unpivot t1 join test_attribs_unpivot t2 on(
           t1.id<>t2.id and 
           t1.name = replace(t2.name, 'DUP_', '') and 
           t1.attr#=t2.attr# )
    where t1.attr<>t2.attr or (t1.attr is null and t2.attr is not null)
          or (t1.attr is not null and t2.attr is null);

    দ্বিতীয় দৃশ্যটি এক ধরণের unpivotঅপারেশন - আপনি যদি কমপক্ষে 11 গ্রামে থাকেন তবে আপনি ক্লজটি দিয়ে আরও স্পষ্টভাবে এটি করতে পারেন unpivot- উদাহরণের জন্য এখানে দেখুন

  • আমি বলছি যদি আপনি এসকিউএল এ করতে পারেন তবে পদ্ধতিগত পথে নামবেন না, তবে ...
  • আপনি পরীক্ষা এবং রক্ষণাবেক্ষণের সাথে উল্লেখ করেছেন এমন সমস্যা থাকা সত্ত্বেও ডায়নামিক এসকিউএল সম্ভবত বিবেচ্য

--EDIT--

প্রশ্নের আরও সাধারণ দিকটির উত্তর দিতে, এসকিউএলটিতে পুনরাবৃত্তি হ্রাস করার কৌশল রয়েছে, যার মধ্যে রয়েছে:

তবে আপনি সরাসরি এসকিউএল জগতে ওও ধারণা আনতে পারবেন না - অনেক ক্ষেত্রে পুনরাবৃত্তি ঠিক আছে যদি কোয়েরিটি পাঠযোগ্য এবং ভালভাবে লেখা থাকে এবং কেবল পুনরাবৃত্তি এড়ানোর জন্য গতিশীল এসকিউএল (উদাহরণস্বরূপ) অবলম্বন করা বুদ্ধিমানের কাজ নয়।

লেইয়ের প্রস্তাবিত পরিবর্তন এবং একটি ভিটির পরিবর্তে একটি সিটিই সহ চূড়ান্ত ক্যোয়ারী এটির মতো দেখতে পারে:

with t as ( select id, name, attr#, 
                   decode(attr#,1,attr1,2,attr2,3,attr3,4,attr4,attr5) attr
            from test_attribs
                 cross join (select rownum attr# from dual connect by rownum<=5))
select 'attr'||t1.attr# as different, t1.id as id_1, t2.id as id_2, t1.name, 
       t2.name as name_dup, t1.attr as val1, t2.attr as val2
from t t1 join test_attribs_unpivot t2 
               on( t1.id<>t2.id and 
                   t1.name = replace(t2.name, 'DUP_', '') and 
                   t1.attr#=t2.attr# )
where t1.attr<>t2.attr or (t1.attr is null and t2.attr is not null)
      or (t1.attr is not null and t2.attr is null);

1
+1 টি আংশিক জন্য UNION ALL। প্রায়শই UNIONছাড়া ALLসাধারণত প্রয়োজন সাজানোর অপারেশন জন্য অস্থায়ী স্টোরেজ করার জন্য একটি নাটাই ফলাফল (যেমন 'ইউনিয়ন' কার্যকরভাবে করা হয় UNION ALLঅনুসৃত দ্বারা DISTINCTযা সাজানোর বোঝা) যাতে কিছু ক্ষেত্রে কর্মক্ষমতা পার্থক্য বিশাল হতে পারে।
ডেভিড Spillett

7

এখানে জ্যাকপিডুগ্লাস (+1) দ্বারা সরবরাহিত টেস্ট_ট্রিবিস_পুনোভিট দর্শনের বিকল্প রয়েছে যা 11 জি এর আগে সংস্করণগুলিতে কাজ করে এবং পূর্ণ টেবিলের কম স্ক্যান করে:

CREATE OR REPLACE VIEW test_attribs_unpivot AS
   SELECT ID, Name, MyRow Attr#, CAST(
      DECODE(MyRow,1,attr1,2,attr2,3,attr3,4,attr4,attr5) AS VARCHAR2(2000)) attr
   FROM TEST_ATTRIBS 
   CROSS JOIN (SELECT level MyRow FROM dual connect by level<=5);

তাঁর চূড়ান্ত ক্যোয়ারী এই দৃশ্য সঙ্গে অপরিবর্তিত ব্যবহার করা যাবে।


অনেক ভাল! আমার মনে হয় আপনি এমনকি কাস্ট ফেলে দিতে পারবেন?
জ্যাক ডগলাস

পরিবর্তে SELECT rownum MyRow FROM test_attribs where rownum<=5ব্যবহার select level MyRow from dual connect by level <= 5। আপনি চান না যে এই 5 টি লজিকাল কেবল 5 টি সারি তৈরির জন্য পেয়ে যায়।
fতেফান ওরাভেক

@ আলেফান ওরাভেক - আমার কাছে এটি এমন ছিল তবে আমি এটি পরিবর্তন করেছি কারণ কোন সংস্করণগুলির শ্রেণিবদ্ধ জিজ্ঞাসাগুলির জন্য উপলব্ধ ছিল তা নিশ্চিত ছিলাম না। যেহেতু এটি সর্বনিম্ন সংস্করণ 8 থেকে পাওয়া যায়, তাই আমি এটি পরিবর্তন করব।
লেইফ রিফেল

4

নতুন, মুছে ফেলা বা পরিবর্তিত সারিগুলির জন্য একটি টেবিলের দুটি সংস্করণ তুলনা করতে আমি প্রায়শই একই সমস্যার মুখোমুখি হই। কিছু মাস আগে আমি এসকিউএল সার্ভারের জন্য এখানে পাওয়ারশেল ব্যবহার করে একটি সমাধান প্রকাশ করেছি ।

এটি আপনার সমস্যার সাথে খাপ খাইয়ে নিতে, আমি প্রথমে সদৃশ সারি থেকে মূল আলাদা করতে দুটি দর্শন তৈরি করেছি

CREATE OR REPLACE VIEW V1_TEST_ATTRIBS AS 
select * from TEST_ATTRIBS where SUBSTR(name, 1, 4) <> 'DUP_'; 

CREATE OR REPLACE VIEW V2_TEST_ATTRIBS AS 
select id, REPLACE(name, 'DUP_', '') name, attr1, attr2, attr3, attr4, attr5 from TEST_ATTRIBS where SUBSTR(name, 1, 4) = 'DUP_'; 

এবং তারপরে আমি পরিবর্তনগুলি যাচাই করে নিই

SELECT 1 SRC, NAME, ATTR1, ATTR2, ATTR3, ATTR4, ATTR5 FROM V1_TEST_ATTRIBS
MINUS
Select 1 SRC, NAME, ATTR1, ATTR2, ATTR3, ATTR4, ATTR5 from V2_TEST_ATTRIBS
UNION
SELECT 2 SRC, NAME, ATTR1, ATTR2, ATTR3, ATTR4, ATTR5 FROM V2_TEST_ATTRIBS
MINUS
SELECT 2 SRC ,NAME, ATTR1, ATTR2, ATTR3, ATTR4, ATTR5 FROM V1_TEST_ATTRIBS
ORDER BY NAME, SRC;

এখান থেকে আমি আপনার আসল আইডির সন্ধান করতে পারি

Select NVL(v1.id, v2.id) id,  t.name, t.attr1, t.attr2, t.attr3, t.attr4, t.attr5 from
(
SELECT 1 SRC, NAME, ATTR1, ATTR2, ATTR3, ATTR4, ATTR5 FROM V1_TEST_ATTRIBS
MINUS
Select 1 SRC, NAME, ATTR1, ATTR2, ATTR3, ATTR4, ATTR5 from V2_TEST_ATTRIBS
UNION
SELECT 2 SRC, NAME, ATTR1, ATTR2, ATTR3, ATTR4, ATTR5 FROM V2_TEST_ATTRIBS
MINUS
Select 2 SRC ,NAME, ATTR1, ATTR2, ATTR3, ATTR4, ATTR5 from V1_TEST_ATTRIBS
) t
LEFT JOIN V1_TEST_ATTRIBS V1 ON T.NAME = V1.NAME AND T.SRC = 1
LEFT JOIN V2_TEST_ATTRIBS V2 ON T.NAME = V2.NAME AND T.SRC = 2
ORDER by NAME, SRC;

বিটিডাব্লু: মাইনাস এবং ইউনিয়ন এবং গ্রুপ বিভিন্ন এনএইউএলকে সমান হিসাবে বিবেচনা করে। এই ক্রিয়াকলাপগুলি ব্যবহার করা প্রশ্নগুলি আরও মার্জিত করে তোলে।

এসকিউএল সার্ভার ব্যবহারকারীদের জন্য ইঙ্গিত: মিনাসের নাম এখানে EXCEPT রাখা হয়েছে, তবে একই রকম কাজ করে।

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