1

Temat: Jak sprawdzić w funkcji czy w bazie jest dana tabela

Witam!
Mam funkcję w której muszę sprawdzić czy dana tabela jest w bazie z tym że większość tabel ma nazwy złożone z liczb. Chyba istnieje jakaś standardowa funkcja do tego sprawdzenia.

2

Odp: Jak sprawdzić w funkcji czy w bazie jest dana tabela

Jest funkcja pg_is_table_visible(oid), ktora sprawdza czy mozesz sie odwolac do tabeli bez podania prefixu schematu w którym została utworzona. O schematach w postgresie mozesz poczytac tu  (http://www.postgresql.org/docs/8.3/interactive/sql-createschema.html, ale ogólnie chodzi o to ze mozesz sobie podzielic baze na 'katalogi' kazdy ze swoimi tabelami (cos a'la system plikow gdzie schemat=katalog, tabela=plik). Jest taka zmienna, search_path, w ktorej możesz ustawić jakie schematy maja byc przegladane gdy wykonujesz jakies operacje na tabelach (cos jak zmienna $PATH w linuxie). Funkcja  pg_is_table_visible(oid) dziala mniej wiecej tak (wykorzystujac Twoja wczesniejsza funkcje)

>select f_sint_CreateTable_tbl(113::smallint);
 f_sint_createtable_tbl
------------------------

(1 row)

>select pg_table_is_visible(('113'::varchar)::regclass);
 pg_table_is_visible
---------------------
 t
(1 row)

(rzutowanie jest niezbedne, nie da sie chyba zrzutowac z integer na oid stad posrednie rzutowanie na varchar)

Czyli dostajesz 't' jesli tabela jest widoczna dla twoich polecen bez potrzeby prefixowania jej. Ale jesli dostaniesz 'f' to nie znaczy ze tabeli nie ma, moze istniec w schemacie, ktorego nie ma w search_path. Ale jesli nie tworzyles  swoich schematow to znaczy ze uzywasz tylko jednego domyslnego o nazwie public. Ten schemat jest domyślnie ustawiony w zmiennej search_path więc funkcja o ktora wspominam spokojnie ci wystarczy i bedzie dzialac.

Mozesz tez napisac wlasna funkcje, ktora bedzie przegladac tabele systemowa pg_tables i szukac czy jakas tabela (np przekazana jej jako argument) juz istnieje.


Ale sie napisalem smile. Mam nadzieje ze cos wyjasnilem smile

3

Odp: Jak sprawdzić w funkcji czy w bazie jest dana tabela

Sprawdzałem chyba powinno zadziałać tylko nie wiem jak mam tego użyć w mojej funkcji chodzi o to żeby sprawdzić czy dana tabela istnieje jeżeli nie to utworzyć jeżeli tak to wpisać do niej dane. W zmiennej Pojazd jest numer tabeli który ma być jej nazwą. I chyba nie przejdzie składnia INSERT INTO Pojazd (....).

CREATE OR REPLACE FUNCTION f_tri_aktual_mt_read() RETURNS trigger AS

$$

DECLARE 

licz INTEGER DEFAULT 0;
dg timestamp without time zone;
val INTEGER;
AwariaSkrot SMALLINT;
Pojazd SMALLINT;
BitInfo SMALLINT; 

BEGIN

dg := NEW.mt_time; 
val := NEW.mt_value;
AwariaSkrot := f_txt_AwariaSkrot_sint(NEW.mt_name);
Pojazd := f_txt_Pojazd_int(NEW.mt_name);
BitInfo := f_txt_BitInfo_sint(NEW.mt_name);

IF (tabela Pojazd nie istnieje) THEN Utworzyc tabele Pojazd END IF;

IF (BitInfo = 0) THEN 
    INSERT INTO Pojazd ("dtDataGodzina", "idfkAwarieSkroty", "sintNrBitu", "intWartosc")
    VALUES (dg, AwariaSkrot, 0, val);
RETURN NEW;
END IF;

IF (BitInfo = 16) THEN 
WHILE licz < 16 
LOOP
    IF ((val & (1<<licz))<>0) THEN 
        INSERT INTO Pojazd ("dtDataGodzina", "idfkAwarieGrupy", "sintNrBitu", "sintWartosc")
        VALUES (dg, AwariaSkrot, licz + 1, val & (1<<licz));
    END IF;
    licz=licz+1;
END LOOP;

RETURN NEW;
END IF;

END;
$$
LANGUAGE PLPGSQL;

Ostatnio edytowany przez WitekS (2009-03-03 09:02:27)

4

Odp: Jak sprawdzić w funkcji czy w bazie jest dana tabela

a

execute 'INSERT INTO "'||Pojazd||'" ("dtDataGodzina", "idfkAwarieSkroty", "sintNrBitu", "intWartosc")
    VALUES (dg, AwariaSkrot, 0, val)';

nie dziala?

Ostatnio edytowany przez rski (2009-03-03 19:01:52)

5

Odp: Jak sprawdzić w funkcji czy w bazie jest dana tabela

rzeczywiście składnia podobna do poprzedniej to pewnie zadziała tylko jak poprawnie sformułować ten kod:

IF (tabela Pojazd nie istnieje) 
    THEN Utworzyc tabele Pojazd 
END IF;

6

Odp: Jak sprawdzić w funkcji czy w bazie jest dana tabela

If' mozesz zaimplementowac tak

CREATE OR REPLACE FUNCTION ex(smallint)
RETURNS varchar AS $$
DECLARE
    str varchar;
begin
        select into str tablename from pg_tables where tablename="$1";
        if not found then
          -- TABELA NIE ISTNIEJE
        else
          --TABELA ISTNIEJE
        end if;
end;
$$ LANGUAGE plpgsql;

7

Odp: Jak sprawdzić w funkcji czy w bazie jest dana tabela

Wszystko OK tylko nazwę tabeli mam w zmiennej Pojazd i jest typu INTEGER chyba powinno być tak

SELECT INTO str tablename FROM pg_tables WHERE tablename='"'||Pojazd||'"';

ale nie jestem pewny bo nie znam tych składni PL/pgSQL a dopiero zaczynam z PostgreSQL-em stąd moja prośba czy możesz nieco nakreślić działanie tego sprawdzenia? pg_tables to widok w którym są przechowywane informacje o tabelach w bazie w danym shemacie, $1 odwołuje się do parametru funkcji ex(smallint) a jakie zadanie ma zmienna str która chyba bez przypisania wartości ma wartość NULL???
W przypadku gdy tabela nie istnieje chciałbym ją utworzyć przez funkcję którą wcześniej napisałem

f_int_CreateTable_tbl(Pojazd);

ale chyba musi to być inaczej napisane???

Ostatnio edytowany przez WitekS (2009-03-04 08:56:45)

8

Odp: Jak sprawdzić w funkcji czy w bazie jest dana tabela

Tak pg_tables to widok z tabeliami w bazie. $1 jak mówisz to pierwszy argument wywołania funkcji. W fukcjach plpgsql nie powinno się używać select'ów, które nigdzie nie zapisują swojego wyniku. Dlatego tu sztucznie wprowadziłem zmienną str aby przypisać jej nazwę tabeli jeśli istnieje. Zamiast sprawdzać czy str jest różne od null, możesz użyć składni "if not found" (lub "if found"), która przechowuje info o tym czy ostatnie wykonane zapytanie (ostatnie wykonane przed "if not found") coś  zwróciło lub nie.

Skrypt może wyglądać następująco

CREATE OR REPLACE FUNCTION ex(smallint)
RETURNS varchar AS $$
DECLARE
    str varchar;
begin
        select into str tablename from pg_tables where tablename="$1";
        if not found then
           perform f_sint_CreateTable_tbl($1);
           return 'created';
else
        return 'already exists';
        end if;
end;
$$ LANGUAGE plpgsql;

Użyty perform to taki select, w którym nie interesuje nas zwracana wartość, dlatego nie trzeba jej nigdzie zapisywać. Tutaj interesuje nas wyłącznie utworzenie tabeli wiec dlatego użyłem perform.
Ponieważ funkcja powinna coś zwracać więc i w if i else jest "return". Równie dobrze mógłbyć jeden return na końcu funkcji (poza if/else).
Funkcja ex(..) zadziała oczywiście tylko wtedy gdy będzie juz utworzona funkcja  f_sint_CreateTable_tbl(..)
Mam nadzieje, że to Ci pomoże.

9

Odp: Jak sprawdzić w funkcji czy w bazie jest dana tabela

Mam coś takiego:

CREATE OR REPLACE FUNCTION f_tri_ai_aktual_mt_read() RETURNS trigger AS

$$

DECLARE 


Pojazd INTEGER;
str VARCHAR;

BEGIN

Pojazd := f_txt_Pojazd_int(NEW.mt_name);


    SELECT INTO str tablename FROM pg_tables WHERE tablename='"'||Pojazd||'"';
        IF not found THEN
        PERFORM f_sint_CreateTable_tbl(Pojazd);
        RETURN 'created';
    ELSE
        RETURN 'already exists';
        END IF;

END;
$$
LANGUAGE PLPGSQL;

No i dostaje taki komunikat:

Use CREATE LANGUAGE to load the language into the database.

Coś mam nie tak tylko co?

10

Odp: Jak sprawdzić w funkcji czy w bazie jest dana tabela

createlang plpgsql nazwa_bazy

11

Odp: Jak sprawdzić w funkcji czy w bazie jest dana tabela

Używam windows xp a wcześniej wszystkie inne funkcje działały ;( link który podałeś nie dział więc spróbuję coś znaleźć na temat dodawania języka proceduralnego chociaż wydawało mi się że zaznaczyłem plpgsql przy instalacji...

12

Odp: Jak sprawdzić w funkcji czy w bazie jest dana tabela

select * from pg_language;

13

Odp: Jak sprawdzić w funkcji czy w bazie jest dana tabela

Język jest w bazie zainstalowany w zasadzie nic nie zmieniałem a teraz przy próbie zapisania funkcji:

CREATE OR REPLACE FUNCTION f_tri_ai_aktual_mt_read() RETURNS trigger AS

$$

DECLARE 

Pojazd INTEGER;
str VARCHAR;

BEGIN

Pojazd := f_txt_Pojazd_int(NEW.mt_name);


    SELECT INTO str tablename FROM pg_tables WHERE tablename='"'||Pojazd||'"';
        IF not found THEN
        PERFORM f_sint_CreateTable_tbl(Pojazd);
        RETURN 'created';
    ELSE
        RETURN 'already exists';
        END IF;

END;
$$
LANGUAGE PLPGSQL;

mam coś takiego

ERROR:  RETURN must specify a record or row variable in function returning tuple at or near "'created'"
LINE 19:         RETURN 'created';
                    ^

********** Błąd **********

Ostatnio edytowany przez WitekS (2009-03-10 08:52:20)

14

Odp: Jak sprawdzić w funkcji czy w bazie jest dana tabela

Przy return's trigger musisz zwracac

return new;

lub

return old;

lub

return null;

Czemu masz returns trigger?

15

Odp: Jak sprawdzić w funkcji czy w bazie jest dana tabela

returns trigger bo muszę sprawdzić przy wstawieniu danych do tabeli mt_read do jakiej tabeli mam wpisać zmodyfikowany rekord i jeżeli taka tabela nie istnieje to utworzyć, nazwa tabeli jest numerem zwracanym na podstawie wpisywanego do mt_read rekordu przez funkcję:

f_txt_Pojazd_int(NEW.mt_name);

Czyli z tego rozumiem że zamiast  RETURN 'created'; oraz RETURN 'already exists'; muszę napisać return null???;
Sprawdziłem działanie no i jest tak że jeżeli tabela nie istnieje to jest utworzona przez funkcję jednak jeżeli już jest to mam taki błąd:

ERROR:  relation "3111" already exists
KONTEKST:  SQL statement " CREATE TABLE "3111"(
          dtDataGodzina timestamp(0) without time zone NOT NULL,
          idfkAwarieSkroty smallint NOT NULL,
          sintNrBitu smallint NOT NULL,
          intWartosc integer
        ) WITH OIDS"
PL/pgSQL function "f_int_createtable_tbl" line 5 at EXECUTE statement
SQL statement "SELECT  f_int_CreateTable_tbl( $1 )"
PL/pgSQL function "f_tri_ai_aktual_mt_read" line 22 at PERFORM

Ostatnio edytowany przez WitekS (2009-03-10 15:06:25)

16

Odp: Jak sprawdzić w funkcji czy w bazie jest dana tabela

To pokaż jak teraz wyglada cała funkcja.

17

Odp: Jak sprawdzić w funkcji czy w bazie jest dana tabela

To jest funkcja wywoływana po wstawieniu rekordu do mt_read a po przeanalizowaniu z tego rekordu mają być wpisywane (jeden bądź kilka w zależności od wartości) do tabel tworzonych jeżeli nie istnieją o nazwie zwracanej przez funkcję.

-- Function: f_tri_ai_aktual_mt_read()

-- DROP FUNCTION f_tri_ai_aktual_mt_read();

CREATE OR REPLACE FUNCTION f_tri_ai_aktual_mt_read()
  RETURNS trigger AS
$BODY$

DECLARE 

licz INTEGER DEFAULT 0;
dg timestamp without time zone;
val INTEGER;
AwariaSkrot SMALLINT;
Pojazd INTEGER;
BitInfo SMALLINT; 
str VARCHAR;

BEGIN

dg := NEW.mt_time; 
val := NEW.mt_value;
AwariaSkrot := f_txt_AwariaSkrot_sint(NEW.mt_name);
Pojazd := f_txt_Pojazd_int(NEW.mt_name);
BitInfo := f_txt_BitInfo_sint(NEW.mt_name);

    SELECT INTO str tablename FROM pg_tables WHERE tablename='"'||Pojazd||'"';
        IF not found THEN
        PERFORM f_int_CreateTable_tbl(Pojazd);
        RETURN null;
    ELSE
        RETURN null;
        END IF;

IF (BitInfo = 0) THEN 
    EXECUTE 'INSERT INTO "'||Pojazd||'" ("dtDataGodzina", "idfkAwarieSkroty", "sintNrBitu", "intWartosc")
        VALUES (dg, AwariaSkrot, 0, val)';
RETURN NEW;
END IF;

IF (BitInfo = 16) THEN 
WHILE licz < 16 
LOOP
    IF ((val & (1<<licz))<>0) THEN 
        EXECUTE 'INSERT INTO "'||Pojazd||'" ("dtDataGodzina", "idfkAwarieGrupy", "sintNrBitu", "sintWartosc")
            VALUES (dg, AwariaSkrot, licz + 1, val & (1<<licz))';
    END IF;
    licz=licz+1;
END LOOP;

RETURN NEW;
END IF;

END;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE
  COST 100;
ALTER FUNCTION f_tri_ai_aktual_mt_read() OWNER TO postgres;

18

Odp: Jak sprawdzić w funkcji czy w bazie jest dana tabela

Dziwna troche ta funkcja. Musisz pamietac ze return powoduje wyjscie z funkcji. Jak masz w if'ie i else 'return null' to juz do tego 'return new' na koncu funkcji raczej nie dojdzie. Jestes pewien ze dobrze przemyslales dzialanie tej funkcji?

19

Odp: Jak sprawdzić w funkcji czy w bazie jest dana tabela

Nie wiem czy dziwna funkcja... nie znam postgres-a ani też składni plpgsql. Wcześniej miałem wszystko na MySQL-u i działało tak jak miało działać. W takim razie jak można wykonać takie zadanie. Przychodzi wpis do bazy do tabeli mt_read:
1. muszę sprawdzić  są wartości do wpisania i wykonać następne działania np. utworzyć tabelę jeżeli nie istnieje (to zadanie - sprawdzenie i utworzenie muszę chyba przenieść całkowicie do funkcji tworzącej tabele???)
2. w zależności od wartości liczby wpisywanej do mt_read muszę rozbić jeden wpis na kilka rekordów i wpisać je do tabeli utworzonej wcześniej która nazwa jest wyznaczona przez funkcję...
Jeżeli funkcja wyzwalacza może zwracać tylko trzy wartości new, old, null a po null kończy działanie to nie wiem jak mam wykonać ten wyzwalacz... sad

Ostatnio edytowany przez WitekS (2009-03-11 10:42:03)