Відмова: Будь ласка, поводьтеся зі мною як з особою, яка використовує лише бази даних, невелику частину свого робочого часу. (Більшу частину часу я займаюся програмуванням на 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що передбачає сортування), тому в деяких випадках різниця в продуктивності може бути величезною.