Tuyên bố miễn trừ trách nhiệm: Hãy đồng ý với tôi với tư cách là người chỉ sử dụng cơ sở dữ liệu một phần rất nhỏ thời gian làm việc của anh ấy. (Hầu hết thời gian tôi làm lập trình C ++ trong công việc của mình, nhưng mỗi tháng tôi cần tìm kiếm / sửa chữa / thêm một cái gì đó vào cơ sở dữ liệu của Oracle.)
Tôi đã nhiều lần cần phải viết các truy vấn SQL phức tạp, cả cho các truy vấn đặc biệt và cho các truy vấn được tích hợp trong các ứng dụng, trong đó phần lớn các truy vấn chỉ lặp lại "mã".
Viết những điều gớm ghiếc như vậy bằng ngôn ngữ lập trình truyền thống sẽ khiến bạn gặp rắc rối lớn, nhưng tôi ( tôi ) vẫn chưa thể tìm thấy bất kỳ kỹ thuật tử tế nào để ngăn chặn sự lặp lại mã truy vấn SQL.
Chỉnh sửa: Thứ nhất, tôi muốn cảm ơn những người trả lời đã cung cấp những cải tiến tuyệt vời cho ví dụ ban đầu của tôi . Tuy nhiên, câu hỏi này không phải là về ví dụ của tôi. Đó là về sự lặp lại trong các truy vấn SQL. Như vậy, các câu trả lời ( JackP , Leigh ) cho đến nay đã làm rất tốt cho thấy rằng bạn có thể giảm sự lặp lại bằng cách viết các truy vấn tốt hơn . Tuy nhiên, ngay cả sau đó bạn phải đối mặt với một số sự lặp đi lặp lại mà dường như không thể xóa được: Điều này luôn cằn nhằn tôi với SQL. Trong các ngôn ngữ lập trình "truyền thống", tôi có thể cấu trúc lại khá nhiều để giảm thiểu tính lặp lại trong mã, nhưng với SQL, dường như không có công cụ (?) Cho phép điều này, ngoại trừ việc viết một câu lệnh ít lặp đi lặp lại.
Lưu ý rằng tôi đã xóa thẻ Oracle một lần nữa, vì tôi thực sự quan tâm liệu không có cơ sở dữ liệu hoặc ngôn ngữ kịch bản nào cho phép thêm thứ gì nữa.
Đây là một viên ngọc quý mà tôi đã cùng nhau sở hữu ngày hôm nay. Về cơ bản, nó báo cáo sự khác biệt trong một tập hợp các cột của một bảng. Vui lòng đọc lướt qua đoạn mã sau, đặc biệt. truy vấn lớn ở cuối Tôi sẽ tiếp tục dưới đây.
--
-- 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)
;
Như bạn có thể thấy, truy vấn để tạo "báo cáo khác biệt" sử dụng cùng một khối SQL SELECT 5 lần (có thể dễ dàng là 42 lần!). Điều này khiến tôi hoàn toàn chết não (tôi được phép nói điều này, sau tất cả những gì tôi đã viết mã), nhưng tôi không thể tìm thấy bất kỳ giải pháp tốt nào cho việc này.
Nếu đây sẽ là một truy vấn trong một số mã ứng dụng thực tế, tôi có thể viết một hàm kết hợp truy vấn này thành một chuỗi và sau đó tôi sẽ thực hiện truy vấn dưới dạng một chuỗi.
- -> Xây dựng chuỗi là khủng khiếp và khủng khiếp để kiểm tra và bảo trì. Nếu "mã ứng dụng" được viết bằng một ngôn ngữ như PL / SQL thì cảm giác đó rất sai.
Ngoài ra, nếu được sử dụng từ PL / SQL hoặc tương tự, tôi đoán có một số phương tiện thủ tục để làm cho truy vấn này dễ duy trì hơn.
- -> Việc hủy một cái gì đó có thể được thể hiện trong một truy vấn duy nhất thành các bước thủ tục chỉ để ngăn chặn việc lặp lại mã cũng cảm thấy sai.
Nếu truy vấn này sẽ là cần thiết như một khung nhìn trong cơ sở dữ liệu, thì - theo như tôi hiểu - sẽ không có cách nào khác ngoài việc thực sự duy trì định nghĩa khung nhìn như tôi đã đăng ở trên. (!!?)
- -> Tôi thực sự phải thực hiện một số bảo trì cho định nghĩa chế độ xem 2 trang một khi không vượt quá tuyên bố trên. Rõ ràng, việc thay đổi bất cứ điều gì trong chế độ xem này yêu cầu tìm kiếm văn bản regrec qua định nghĩa chế độ xem liệu cùng một câu lệnh phụ đã được sử dụng trong một dòng khác hay chưa và liệu nó có cần thay đổi ở đó không.
Vì vậy, như tiêu đề đi - những kỹ thuật nào có để ngăn chặn việc phải viết những điều ghê tởm như vậy?
UNION ALL
. Thường thìUNION
không cóALL
kết quả trong một bộ đệm để lưu trữ tạm thời cho hoạt động sắp xếp cần thiết (vì 'UNION' được thực hiệnUNION ALL
theo cách hiệu quả theoDISTINCT
đó là một loại), do đó, trong một số trường hợp, sự khác biệt hiệu năng có thể rất lớn.