X-Original-To: pgsql-sql-postgresql.org@localhost.postgresql.org Received: from localhost (unknown [200.46.204.144]) by svr1.postgresql.org (Postfix) with ESMTP id 2FFB33ABCBB for ; Tue, 21 Dec 2004 22:35:30 +0000 (GMT) Received: from svr1.postgresql.org ([200.46.204.71]) by localhost (av.hub.org [200.46.204.144]) (amavisd-new, port 10024) with ESMTP id 24152-08 for ; Tue, 21 Dec 2004 22:35:24 +0000 (GMT) Received: from mx.laposte.net (mx.laposte.net [80.245.62.11]) by svr1.postgresql.org (Postfix) with ESMTP id 391873ABCB1 for ; Tue, 21 Dec 2004 22:35:24 +0000 (GMT) Received: from laposte.net (82.123.210.148) by mx.laposte.net (7.0.028) (authenticated as thomas.silvi@laposte.net) id 41B63FA200541ED2; Tue, 21 Dec 2004 23:35:10 +0100 Message-ID: <41C8A604.7040708@laposte.net> Date: Tue, 21 Dec 2004 23:39:00 +0100 From: "thomas.silvi" Reply-To: thomas.silvi@laposte.net User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040115 X-Accept-Language: fr, en MIME-Version: 1.0 To: Doug Y Cc: pgsql-sql@postgresql.org Subject: Re: I'm stumped References: <41C6FE35.5030003@ptd.net> In-Reply-To: <41C6FE35.5030003@ptd.net> X-Enigmail-Version: 0.83.3.0 X-Enigmail-Supports: pgp-inline, pgp-mime Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 8bit X-Virus-Scanned: by amavisd-new at hub.org X-Spam-Status: No, hits=0 tagged_above=0 required=5 tests= X-Spam-Level: X-Archive-Number: 200412/149 X-Sequence-Number: 19769 Doug Y a écrit : > I can't figure out an efficient way to do this. Basically I had a > typical 3-tier relationship: > (Employee -> Department -> Division) > However, at some point the need to move employees arose, but instead > of changing the key in the emp table, we now have an over-ride table, > so a history can be tracked. > > If I want to get the info for a particular employee, its a pretty > simple deal, however, getting all the employees for a dept or division > has become troublesome. > > A very simplified schema: > divisions ( div_id, div_name ); > departments ( dept_id, dept_name, div_id ); > employees ( emp_id, emp_name, dept_id ); > emp_dept ( emp_id, dept_id, active, changed_by, changed_when ); > > The original way that worked well: > SELECT v.div_name, d.dept_id, e.emp_id, e.emp_name > FROM divisions v > INNER JOIN departments d > ON d.div_id = v.div_id > INNER JOIN employees e > ON e.dept_id = d.dept_id > WHERE v.div_id = 123; > > What was initially tried: > SELECT v.div_name, COALESCE(ed.dept_id, d.dept_id), e.emp_id, e.emp_name > FROM divisions v > INNER JOIN departments d > ON d.div_id = v.div_id > INNER JOIN employees e > ON e.dept_id = d.dept_id > LEFT JOIN emp_dept ed > ON ed.emp_id = e.emp_id AND ed.active = true > WHERE v.div_id = 123; > This query is flawed, as it still always puts the employees in their > original div, but reports the new dept. Which we didn't catch as a > problem until emps were moved to depts in a different division. > > I tried creating a function: > CREATE OR REPLACE FUNCTION get_empdept(int4) RETURNS int4 AS ' > SELECT CASE WHEN ed.dept_id IS NOT NULL > THEN ed.dept_id > ELSE e.dept_id END > FROM employees AS e > LEFT JOIN emp_dept AS ed > ON ed.emp_id = e.emp_id AND ed.active = true > WHERE e.emp_id = $1 > ' LANGUAGE SQL STABLE; > > And then tried: > SELECT v.div_name, d.dept_id, e.emp_id, e.emp_name > FROM divisions v > INNER JOIN departments d > ON d.div_id = v.div_id > INNER JOIN employees e > ON get_empdept(e.emp_id) = d.dept_id > WHERE v.div_id = 123; > > However since the function is not immutable (since it does a query), I > can't create an index, and the join always does a seq scan. > > I also thought to create a view, but I don't believe Postgres supports > indexed views. It was always using a seq scan too. > > The above examples are actually quite simplified, as several other > tables get joined along the way, I'm not sure a UNION would work or > not, how would it exclude the ones that match the dept_id in the emp > table for those emps that match on the over-ride table? > > Any suggestions? > Hello, have you an index on emp_dept on emp_id, dept_id ? what about this ? SELECT v.div_name, d.dept_id, e.emp_id, e.emp_name FROM divisions v INNER JOIN departments d ON d.div_id = v.div_id INNER JOIN employees e ON e.dept_id = d.dept_id WHERE NOT EXISTS (SELECT 1 FROM emp_dept ed WHERE ed.emp_id = e.emp_id) AND v.div_id = 2 UNION ALL SELECT v.div_name, d.dept_id, e.emp_id, e.emp_name FROM divisions v INNER JOIN departments d ON d.div_id = v.div_id INNER JOIN emp_dept ed ON d.dept_id = ed.dept_id INNER JOIN employees e ON e.emp_id = ed.emp_id WHERE ed.active=true AND v.div_id = 2 Regards, Thomas > Thanks > > ---------------------------(end of broadcast)--------------------------- > TIP 5: Have you checked our extensive FAQ? > > http://www.postgresql.org/docs/faqs/FAQ.html >