dynamisch Schema auswählen

Hallo allesamt,

ich habe momentan folgende (stark vereinfachte) Tabellensituation. Ich habe eine Tabelle “persons” und “groups”, die über einen Suchpfad sowohl in schema1 als auch in schema2 vorhanden sind. In den beiden Schemata getrennt vorhanden ist die Tabelle “dates”.
[ATTACH]81[/ATTACH]

Ich muss nun eine Abfrage schreiben, die mir zu einer “persons_pk” über die Gruppennummer Start- und Enddatum aus der “dates”-Tabelle raussucht. Problem: In “group” gibt es die Spalte “use_schema”, die eine 0 oder eine 1 enthalten kann. Je nach Inhalt soll entweder das schema1 oder das schema2 ausgewählt werden.

Als Lösung hab ich mir eine Testfunktion gebaut, die das auslesen soll und dann die Tabelle zurückgeben soll:

CREATE OR REPLACE FUNCTION get_test () RETURNS char(32) AS '
    DECLARE
    BEGIN
        RETURN ''schema1.dates'';
    END;
' LANGUAGE 'plpgsql';

SELECT
    persons.a,
    persons.b,
    groups.groups_pk,
    dates.start,
    dates.end
FROM
    persons,
    groups,
    get_test(),
WHERE
    persons.group_fk = groups.groups_pk AND
    groups.dates_fk = dates.dates_pk AND
    persons.persons_pk = 1234
;

Leider klappt das so nicht (“dates” nicht gefunden). Hat jemand eine Lösung?

Danke im Voraus!

Der Ansatz über eine Funktion ist richtig, der Weg aber falsch.

Erst einmal:
Was soll das einklich? Du machst Dir das Leben unnötig schwer. Verwende eine Tabelle, fertig ist. Willst Du auf diese Weise Partitionierung? Das geht anders. Und einfacher.

Okay.

Das, was Du willst, ist ein dynamisch generiertes (und ausgeführtes) SQL. Dafür hat die Doku Beispiele:
PostgreSQL: Documentation: Manuals: PostgreSQL 8.4: Basic Statements

In kurz: Du hast, zur Laufzeit, Dir das passende SQL zurecht zu friemeln und diese Gefriemel, ähm, SQL, dann auszuführen. Alles andere kann der Planner nicht planen, daher klappt das bei Dir auch nicht wie gewollt.

In lang: überdenke Deine Idee.


Andreas

Das ist eigentlich die kurze - und richtige - Aussage.

Ja :wink:

Andreas

Hallo Andreas,

ich habe ein fertiges Produkt mit einer unsäglich schrecklichen Datenbankstruktur, dass ich so hinbiegen muss, dass es für uns funktioniert. Das System kann nur einen Zeitrhythmus gleichzeitig abbilden, wir brauchten aber zwei - daher der Trick mit zwei Schemata und dem Suchpfad, der dann je nach benötigtem Schema angepasst wird.

Mein Problem ist, dass die Abfrage in Wirklichkeit etwa 50 Spalten zurückholt und ich die nicht alle in eine Funktion packen und zurückgeben lassen will. Gibt es keine elegantere Lösung für dieses simple IF…ELSE -Problem?

Vielleicht mit einem VIEW, der mittels UNION ALL aus den 2 Tabellen eine macht.

Aber vielleicht wäre es einfacher, das ‘Rodukt’ zu fixen. Ads macht Dir bestimmt gerne ein Angebot :wink:


Andreas

Hi Andreas,

dann hätte ich zwar alle Daten aus beiden Schemata drin (wenn ich deine Idee richtig verstehe), müsste aber die richtigen Daten immer noch über eine IF…ELSE o.Ä. rausfiltern - wobei ich das dann wieder in eine Funktion auslagern könnte… hmmm… ich lass es mir mal durch den Kopf gehen, danke für die Hilfe.

Produkt fixen ist leider nicht drin wegen späterer Updateproblematik vom Hersteller. :wink:

Nun ja, man kann ja auch mal tricksen:

test=*# create table lars1 (id int, value text);
CREATE TABLE
test=*# create table lars2 (id int, value text);
CREATE TABLE
test=*# insert into lars1 values (1, 'lars1');
INSERT 0 1
test=*# insert into lars1 values (2, 'lars2');
INSERT 0 1
test=*# create view view_lars as select 'table lars1' as tablename, id, value from lars1 union all select 'table lars2', id, value from lars2;
CREATE VIEW
test=*# select * from view_lars ;
  tablename  | id | value
-------------+----+-------
 table lars1 |  1 | lars1
 table lars1 |  2 | lars2
(2 rows)

Nun hast Du im VIEW ein Selektionsmerkmal.

Produkt fixen ist leider nicht drin wegen späterer Updateproblematik vom Hersteller. > :wink: >

Hersteller in die Weichteile treten?


Andreas

Oder eine zweite Lizenz vom Hersteller kaufen.
Oder Hersteller treten. Oh, hatten wir schon, den Ansatz.

Wenn du mit Views arbeitest, kriegst du auch ein Problem bei den Updates. Die musst du alle entfernen, bevor irgendwas aktualisiert wird. Andernfalls könnte das Update fehlschlagen.

Hallo Andreas,
hallo ads,

ich verstehe nicht ganz, wie die VIEW mein Problem lösen würde. Ich benötige als Rückgabe aus der Abfrage eine Spalte mit dem namen “startdate” und eine mit “enddate”, und zwar je nach flagfeld entweder aus Schema1 oder aus Schema2. Sowas hier würde mich ja erstmal nicht weiter bringen:

CREATE DATABASE mytest;

CREATE TABLE groups (
    groups_pk     INT PRIMARY KEY,
    schemeflag     SMALLINT NOT NULL,
    dates_fk     INT NOT NULL
    );

CREATE SCHEMA schema1
    CREATE TABLE schema1.dates (
        dates_pk     INT PRIMARY KEY,
        startdate     DATE NOT NULL,
        enddate     DATE NOT NULL
        );

CREATE SCHEMA schema2
    CREATE TABLE dates (
        dates_pk     INT PRIMARY KEY,
        startdate      DATE NOT NULL,
        enddate     DATE NOT NULL
        );

INSERT INTO schema1.dates VALUES
    (1, '2009-01-01', '2009-05-31'),
    (2, '2009-06-01', '2009-12-31');

INSERT INTO schema2.dates VALUES
    (1, '2009-01-01', '2009-03-31'),
    (2, '2009-04-01', '2009-07-30'),
    (3, '2009-08-01', '2009-12-31');

INSERT INTO groups VALUES
    (1111, 1, 2),    -- linked to scheme1
    (2222, 2, 2);    -- linked to scheme2

SELECT
    groups.*,
    schema1.dates.startdate AS s1start,
    schema1.dates.enddate AS s1end,
    schema2.dates.startdate AS s2start,
    schema2.dates.enddate AS s2end
FROM
    groups,
    schema1.dates,
    schema2.dates
WHERE
    groups.dates_fk = schema1.dates.dates_pk AND
    groups.dates_fk = schema2.dates.dates_pk
    ;

-- Resultat:
 groups_pk | schemeflag | dates_fk |  s1start   |   s1end    |  s2start   |   s2end
-----------+------------+----------+------------+------------+------------+------------
      1111 |          1 |        2 | 2009-06-01 | 2009-12-31 | 2009-04-01 | 2009-07-30
      2222 |          2 |        2 | 2009-06-01 | 2009-12-31 | 2009-04-01 | 2009-07-30

Die View würde mir ja auch nicht mehr zurückgeben, nur auf Zeilen aufgeteilt - oder versteh ich das falsch? :confused:

Ich weiß nicht genau, ob ich Dich richtig verstehe. Möglicherweise nicht. Was für ein Resultat erwartest Du denn aus Deinen Daten?

test=*# select * from schema1.dates ;
 dates_pk | startdate  |  enddate    
----------+------------+------------ 
        1 | 2009-01-01 | 2009-05-31  
        2 | 2009-06-01 | 2009-12-31  
(2 rows)

test=*# select * from schema2.dates ;
 dates_pk | startdate  |  enddate
----------+------------+------------
        1 | 2009-01-01 | 2009-03-31
        2 | 2009-04-01 | 2009-07-30
        3 | 2009-08-01 | 2009-12-31
(3 rows)

test=*# select * from groups ;
 groups_pk | schemeflag | dates_fk
-----------+------------+----------
      1111 |          1 |        2
      2222 |          2 |        2
(2 rows)

test=*# select g.*, v.startdate, v.enddate from groups g left join view_dates v on g.schemeflag=v.schema_flag;
 groups_pk | schemeflag | dates_fk | startdate  |  enddate
-----------+------------+----------+------------+------------
      1111 |          1 |        2 | 2009-01-01 | 2009-05-31
      1111 |          1 |        2 | 2009-06-01 | 2009-12-31
      2222 |          2 |        2 | 2009-01-01 | 2009-03-31
      2222 |          2 |        2 | 2009-04-01 | 2009-07-30
      2222 |          2 |        2 | 2009-08-01 | 2009-12-31
(5 rows)

test=*# \d view_dates
     View "public.view_dates"
   Column    |  Type   | Modifiers
-------------+---------+-----------
 schema_flag | integer |
 dates_pk    | integer |
 startdate   | date    |
 enddate     | date    |
View definition:
         SELECT 1 AS schema_flag, dates.dates_pk, dates.startdate, dates.enddate
           FROM schema1.dates
UNION ALL
         SELECT 2 AS schema_flag, dates.dates_pk, dates.startdate, dates.enddate
           FROM schema2.dates;

test=*#

Andreas

Das sieht sehr gut aus, ich denke das ist die Lösung für das Problem. Ich baus gleich mal ein. Vielen Dank! :slight_smile:

Und danach trittst du den Hersteller der Software?

Als der Hersteller letztes Mal hier war hatte ich ihm schon hochachtungsvoll gesagt: “Sie haben ganz schön Mut hier aufzutauchen”. :wink:

Aber in der nächsten Version wird alles besser - komplette Neuprogrammierung von Grund auf. War die richtige Entscheidung.

Habs übrigens eingebaut und funktioniert super - nochmals vielen Dank! :smiley:

Definitiv.

Wem darf ich da mehr über PostgreSQL beibringen? :wink:
Damit es das nächste Mal wirklich richtig ist.

Das muss leider ein Geheimnis bleiben. :wink: