SQL Apprentice Question
Let's say I have a search screen in my application that allows users to 
do various AND OR conditions to about 14 pieces of criteria.  That is a 
complicated query to build dynamically and will be super slow because 
it is dynamic. 
Is there an efficient way to do this type of quering? 
Celko Answers
I think what you want is the ability to load tables with criteria and 
not have to use dynamic SQL.  Let's say you want to search for job 
candidates based on their skills. 
skill = Java AND (skill = Perl OR skill = PHP) 
becomes the disjunctive canonical form: 
(Java AND Perl) OR (Java AND PHP) 
 which we load into this table: 
CREATE TABLE Query 
(and_grp INTEGER NOT NULL, 
 skill CHAR(4) NOT NULL, 
 PRIMARY KEY (and_grp, skill)); 
INSERT INTO Query VALUES (1, 'Java'); 
INSERT INTO Query VALUES (1, 'Perl'); 
INSERT INTO Query VALUES (2, 'Java'); 
INSERT INTO Query VALUES (2, 'PHP'); 
Assume we have a table of job candidates: 
CREATE TABLE Candidates 
(candidate_name CHAR(15) NOT NULL, 
 skill CHAR(4) NOT NULL, 
 PRIMARY KEY (candidate_name, skill)); 
INSERT INTO Candidates VALUES ('John', 'Java'); --winner 
INSERT INTO Candidates VALUES ('John', 'Perl'); 
INSERT INTO Candidates VALUES ('Mary', 'Java'); --winner 
INSERT INTO Candidates VALUES ('Mary', 'PHP'); 
INSERT INTO Candidates VALUES ('Larry', 'Perl'); --winner 
INSERT INTO Candidates VALUES ('Larry', 'PHP'); 
INSERT INTO Candidates VALUES ('Moe', 'Perl'); --winner 
INSERT INTO Candidates VALUES ('Moe', 'PHP'); 
INSERT INTO Candidates VALUES ('Moe', 'Java'); 
INSERT INTO Candidates VALUES ('Celko', 'Java'); -- loser 
INSERT INTO Candidates VALUES ('Celko', 'Algol'); 
INSERT INTO Candidates VALUES ('Smith', 'APL');  -- loser 
INSERT INTO Candidates VALUES ('Smith', 'Algol'); 
The query is simple now: 
SELECT DISTINCT C1.candidate_name 
  FROM Candidates AS C1, Query AS Q1 
 WHERE C1.skill = Q1.skill 
 GROUP BY Q1.and_grp, C1.candidate_name 
HAVING COUNT(C1.skill) 
       = (SELECT COUNT(*) 
            FROM Query AS Q2 
           WHERE Q1.and_grp = Q2.and_grp); 
You can retain the COUNT() information to rank candidates.  For example 
Moe meets both qualifications, while other candidates meet only one of 
the two. You can Google "canonical disjunctive form" for more details. 
This is a form of relational division.
Tuesday, April 25, 2006
Subscribe to:
Post Comments (Atom)

 
 
No comments:
Post a Comment