Відмова: Будь ласка, поводьтеся зі мною як з особою, яка використовує лише бази даних, невелику частину свого робочого часу. (Більшу частину часу я займаюся програмуванням на C ++ на своїй роботі, але мені потрібно щоденно шукати / виправляти / додавати щось у базу даних Oracle.)
Мені неодноразово потрібно писати складні запити SQL, як для спеціальних запитів, так і для запитів, вбудованих у додатки, де великі частини запитів, де щойно повторювався "код".
Написання подібних гидот традиційною мовою програмування загрожує глибоким неприємностям, але я ( I ) ще не зміг знайти жодної гідної методики для запобігання повторення коду запитів SQL.
Редагувати: Перше, я хочу подякувати тим, хто відповідав моїм оригінальним прикладом . Однак це питання не стосується мого прикладу. Йдеться про повторюваність у запитах SQL. Таким чином, відповіді ( JackP , Leigh ) поки що чудово працюють, показуючи, що ви можете зменшити повторюваність, написавши кращі запити . Однак навіть тоді ви стикаєтесь з деякою повторюваністю, яку, мабуть, неможливо зняти: Це завжди натякало мене на SQL. У "традиційних" мовах програмування я можу досить рефакторифікувати, щоб мінімізувати повторюваність у коді, але за допомогою SQL здається, що немає (?) Інструментів, які дозволяють це зробити, за винятком написання менш повторюваного твердження для початку.
Зауважте, що я знову видалив тег Oracle, тому що я був би щиро зацікавлений, чи немає в базі даних чи мови сценаріїв, що дозволяє щось більше.
Ось один такий дорогоцінний камінь, який я сьогодні спільно спіткав. В основному він повідомляє про різницю в наборі стовпців однієї таблиці. Прогляньте наступний код, 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)
;
Як бачимо, запит для створення "звіту про різниці" використовує один і той же блок SQL SELECT 5 разів (легко може бути 42 рази!). Це вважає мене абсолютно мозком мертвим (мені це дозволяється сказати, адже я написав код), але мені не вдалося знайти жодного хорошого рішення для цього.
Якщо це був би запит у деякому фактичному коді програми, я міг би записати функцію, яка поєднує цей запит у вигляді рядка, а потім я б виконував запит як рядок.
- -> Будівництво струн - жахливо і жахливо перевіряти і підтримувати. Якщо "код програми" написаний такою мовою, як PL / SQL, він відчуває себе так неправильно, боляче.
Крім того, якщо я використовую PL / SQL або подібне, я б припустив, що існують деякі процедурні засоби, щоб зробити цей запит більш доступним.
- -> Розгортання чогось, що може бути виражено в одному запиті в процедурні кроки, щоб запобігти повторенню коду, теж не так.
Якщо цей запит знадобиться як перегляд у базі даних, тоді - наскільки я розумію - не було б іншого способу, як насправді підтримувати визначення подання, як я розміщував вище. (!!?)
- -> Мені насправді довелося зробити певне обслуговування для визначення 2-сторінкового перегляду, коли це було не за горами вище. Очевидно, що змінити що-небудь в цьому представленні вимагало повторного пошуку тексту по визначенню перегляду для того, чи використовувався той самий підзаголовок в іншому рядку та чи потрібно там змінювати.
Отже, як йдеться в заголовку - які методи існують, щоб не дати писати такі гидоти?
UNION ALL
. ЧастоUNION
без цьогоALL
призводить до отримання котушки на тимчасове зберігання для необхідної операції сортування (оскільки "UNION" фактичноUNION ALL
слідує за цим,DISTINCT
що передбачає сортування), тому в деяких випадках різниця в продуктивності може бути величезною.