Wypisz wszystkie sekwencje w Postgres db 8.1 z SQL


147

Konwertuję bazę danych z postgres na mysql.

Ponieważ nie mogę znaleźć narzędzia, które samo załatwi sprawę, zamierzam przekonwertować wszystkie sekwencje postgres na identyfikatory autoincrement w mysql z wartością autoincrement.

Jak więc mogę wyświetlić listę wszystkich sekwencji w Postgres DB ( wersja 8.1 ) z informacjami o tabeli, w której jest używany, następną wartością itp. Z zapytaniem SQL?

Należy pamiętać, że nie mogę używać information_schema.sequenceswidoku w wersji 8.4.


1
Należy zauważyć, że wykonujesz konwersję w niewłaściwy sposób. Odkąd Oracle kupiło Sun'a, powoli zabijają MySQL, więc jeśli nie gardzisz swoim klientem (w takim przypadku powinieneś po prostu zrezygnować), powinieneś trzymać się PostgreSQL, ponieważ żadna korporacja (pro-monopolista nie) nie może się pojawić, pożreć PostgreSQL i ostatecznie zastąp je własną bazą danych.
Jan

@John Powiedziałbym, że jest miliard i jeszcze jeden powód, aby trzymać się postgres i miliard więcej, aby nigdy nie dotykać mysql, ale tak - twój punkt widzenia jest nadal bardzo aktualny :)
Ruslan

@John at the time (2009), potrzebujemy prostszej bazy danych - a mysql był lepiej połączony z php
apelliciari

Odpowiedzi:


250

Poniższe zapytanie podaje nazwy wszystkich sekwencji.

SELECT c.relname FROM pg_class c WHERE c.relkind = 'S';

Zazwyczaj sekwencja nosi nazwę ${table}_id_seq. Proste dopasowanie do wzorca wyrażenia regularnego daje nazwę tabeli.

Aby uzyskać ostatnią wartość sekwencji, użyj następującego zapytania:

SELECT last_value FROM test_id_seq;

5
${table}_id_seqWskazówkę była przydatna
Pierre de LESPINAY

${table}_${column}_seqdla automatycznie utworzonych sekwencji
Evgeny Nozdrev

80

Zwróć uwagę, że począwszy od PostgreSQL 8.4 możesz uzyskać wszystkie informacje o sekwencjach używanych w bazie danych poprzez:

SELECT * FROM information_schema.sequences;

Ponieważ używam wyższej wersji PostgreSQL (9.1) i szukałem tej samej odpowiedzi na wysokim i niskim poziomie, dodałem tę odpowiedź ze względu na potomność i przyszłych poszukiwaczy.


1
Protip: posortuj odpowiedzi według „aktywnych”. Potomność staje się coraz bardziej istotna w miarę
starzenia się

1
Chłodny. I wygląda na to, że jeśli wybiorę metodę sortowania „aktywną”, witryna po prostu od razu zapamiętuje ustawienie (tutaj szukałem preferencji, aby znaleźć miejsce, w którym można ustawić je jako domyślne, ale bezskutecznie). Hm, gdybyśmy tylko mieli opcję „odpowiedź zaakceptowana przez pytającego, która automatycznie nie przeważa nad wszystkim innym” - to byłoby naprawdę wielkim zwycięstwem dla potomności.
RzadkoNeedy

Zauważ, że ta tabela została wprowadzona w PG 8.4, wolałbym raczej powiedzieć PG 8.2 po oficjalnej dokumentacji: postgresql.org/docs/8.2/infoschema-sequences.html
Guillaume Husta

Te „wszystkie informacje” nie obejmują bieżącej wartości.
bart

62

Uruchom:, psql -Ea następnie\ds


1
nie potrzebuję tylko listy sekwencji, potrzebuję tabeli, w której jest używana, kolejnej wartości itp. I muszę to zrobić w SQL
apelliciari

Następnie w każdej sekwencji wykonaj \ d <nazwa> (będąc nadal w psql -E)

znowu, to nie jest w SQL i nie pokazuje, do której tabeli jest dołączona sekwencja
apelliciari

@avastreg: czy uruchomiłeś to tak, jak ci kazałem? czemu nie?

10
@avastreg: ZRÓB TO RAZ . I pokaże Ci zapytania!

26

po odrobinie bólu, mam to.

najlepszym sposobem na osiągnięcie tego jest wypisanie wszystkich tabel

select * from pg_tables where schemaname = '<schema_name>'

a następnie dla każdej tabeli podaj listę wszystkich kolumn z atrybutami

select * from information_schema.columns where table_name = '<table_name>'

następnie dla każdej kolumny sprawdź, czy ma sekwencję

select pg_get_serial_sequence('<table_name>', '<column_name>')

a następnie uzyskaj informacje o tej sekwencji

select * from <sequence_name>

13

informacja o sekwencji: wartość maksymalna

SELECT * FROM information_schema.sequences;

informacja o sekwencji: ostatnia wartość

SELECT * FROM <sequence_name>


11

Relacja między automatycznie generowanymi sekwencjami (takimi jak te utworzone dla kolumn SERIAL) a tabelą nadrzędną jest modelowana przez atrybut właściciela sekwencji.

Możesz zmodyfikować tę relację za pomocą klauzuli OWNED BY pliku ALTER SEQUENCE

np. ALTER SEQUENCE foo_id OWNED by foo_schema.foo_table

aby ustawić, aby był powiązany z tabelą foo_table

lub ALTER SEQUENCE foo_id OWNED by NONE

aby przerwać połączenie między sekwencją a dowolną tabelą

Informacje o tej relacji są przechowywane w tabeli katalogu pg_depend .

relacja łączenia jest połączeniem między pg_depend.objid -> pg_class.oid WHERE relkind = 'S' - które łączy sekwencję z rekordem łączenia, a następnie pg_depend.refobjid -> pg_class.oid WHERE relkind = 'r', które łączy dołącz rekord do relacji będącej właścicielem (tabela)

To zapytanie zwraca wszystkie sekwencje -> zależności tabel w bazie danych. Klauzula where filtruje ją tak, aby zawierała tylko relacje generowane automatycznie, co ogranicza ją do wyświetlania tylko sekwencji utworzonych przez kolumny o typie SERIAL.

WITH fq_objects AS (SELECT c.oid,n.nspname || '.' ||c.relname AS fqname , 
                           c.relkind, c.relname AS relation 
                    FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace ),

     sequences AS (SELECT oid,fqname FROM fq_objects WHERE relkind = 'S'),  
     tables    AS (SELECT oid, fqname FROM fq_objects WHERE relkind = 'r' )  
SELECT
       s.fqname AS sequence, 
       '->' as depends, 
       t.fqname AS table 
FROM 
     pg_depend d JOIN sequences s ON s.oid = d.objid  
                 JOIN tables t ON t.oid = d.refobjid  
WHERE 
     d.deptype = 'a' ;

Przydatne wyjaśnienie zależności między tabelami i sekwencjami. Ale twoje zapytanie nie znalazło dla mnie wszystkich sekwencji . Wydaje się, że niektóre sekwencje istnieją bez żadnych zależności.
Evgeny Nozdrev

tak, to zapytanie jawnie pokazuje tylko sekwencje zdefiniowane przez definicje kolumn szeregowych bazy danych. Wyjaśnia to odpowiedź.
cms

5

Wiem, że ten post jest dość stary, ale rozwiązanie CMS okazało się bardzo przydatne, ponieważ szukałem automatycznego sposobu na połączenie sekwencji z tabelą ORAZ kolumną i chciałem się nimi podzielić. Zastosowanie pg_depend tabeli katalogu był klucz. Rozszerzyłem to, co zostało zrobione, aby:

WITH fq_objects AS (SELECT c.oid,n.nspname || '.' ||c.relname AS fqname ,
                           c.relkind, c.relname AS relation
                    FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace ),

     sequences AS (SELECT oid,fqname FROM fq_objects WHERE relkind = 'S'),
     tables    AS (SELECT oid, fqname FROM fq_objects WHERE relkind = 'r' )
SELECT
       s.fqname AS sequence,
       '->' as depends,
       t.fqname AS table,
       a.attname AS column
FROM
     pg_depend d JOIN sequences s ON s.oid = d.objid
                 JOIN tables t ON t.oid = d.refobjid
                 JOIN pg_attribute a ON a.attrelid = d.refobjid and a.attnum = d.refobjsubid
WHERE
     d.deptype = 'a' ;

Ta wersja dodaje kolumnę do listy zwróconych pól. Mając pod ręką zarówno nazwę tabeli, jak i nazwę kolumny, wywołanie pg_set_serial_sequence ułatwia upewnienie się, że wszystkie sekwencje w bazie danych są ustawione poprawnie. Na przykład:

CREATE OR REPLACE FUNCTION public.reset_sequence(tablename text, columnname text)
 RETURNS void
 LANGUAGE plpgsql
AS $function$
DECLARE
    _sql VARCHAR := '';
BEGIN
    _sql := $$SELECT setval( pg_get_serial_sequence('$$ || tablename || $$', '$$ || columnname || $$'), (SELECT COALESCE(MAX($$ || columnname || $$),1) FROM $$ || tablename || $$), true)$$;
    EXECUTE _sql;
END;
$function$;

Mam nadzieję, że to pomoże komuś z resetowaniem sekwencji!


po kilku latach zauważam twoją aktualizację i wpadam, żeby dać głos :-)
cms

3

Ta instrukcja zawiera tabelę i kolumnę skojarzoną z każdą sekwencją:

Kod:

    SELECT t.relname as related_table, 
           a.attname as related_column,
           s.relname as sequence_name
    FROM pg_class s 
      JOIN pg_depend d ON d.objid = s.oid 
      JOIN pg_class t ON d.objid = s.oid AND d.refobjid = t.oid 
      JOIN pg_attribute a ON (d.refobjid, d.refobjsubid) = (a.attrelid, a.attnum)
      JOIN pg_namespace n ON n.oid = s.relnamespace 
    WHERE s.relkind     = 'S' 

  AND n.nspname     = 'public'

więcej zobacz tutaj link do odpowiedzi


2

Poprawa poprzedniej odpowiedzi:

select string_agg('select sequence_name, last_value from ' || relname, chr(13) || 'union' || chr(13) order by relname) 
from pg_class where relkind ='S'

3
Nie umieszczaj kodu bez żadnego wyjaśnienia. Ponadto, skoro stwierdziłeś, że Twój kod jest „ulepszeniem poprzedniej odpowiedzi”, powinieneś również powiedzieć nam, DLACZEGO to ulepszenie. Och, nie poddawaj się i witaj w SO!
Joel

Czy powinienem napisać stronę z bezsensownym tekstem zamiast dokładnego kodu (kilka wierszy)?
Alexander Ryabov

2
Nigdy tego nie powiedziałem. Lubię prosty, precyzyjny kod. Ale gdy stwierdzisz, że twój kod jest ulepszeniem, jeden lub dwa wiersze wyjaśniające DLACZEGO to ulepszenie (lepsza czytelność, lepsza wydajność itp.) Nie zaszkodzą. I prawdopodobnie dostaniesz ode mnie +1.
Joel

1

Częściowo przetestowane, ale wygląda na kompletne.

select *
  from (select n.nspname,c.relname,
               (select substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)
                  from pg_catalog.pg_attrdef d
                 where d.adrelid=a.attrelid
                   and d.adnum=a.attnum
                   and a.atthasdef) as def
          from pg_class c, pg_attribute a, pg_namespace n
         where c.relkind='r'
           and c.oid=a.attrelid
           and n.oid=c.relnamespace
           and a.atthasdef
           and a.atttypid=20) x
 where x.def ~ '^nextval'
 order by nspname,relname;

Kredyt tam, gdzie należny jest kredyt ... jest częściowo odtwarzany na podstawie kodu SQL zarejestrowanego z a \ d na znanej tabeli, która miała sekwencję. Jestem pewien, że może być też czystszy, ale hej, wydajność nie była problemem.


1

Coś w rodzaju włamania, ale spróbuj tego:

wybierz 'wybierz' '' || relname || '' 'jako sekwencja, ostatnia_wartość z' || relname || 'union' Z pg_catalog.pg_class c WHERE c.relkind IN ('S', '');

Usuń ostatnią UNION i wykonaj wynik


1

Uzyskaj sekwencje dla każdej kolumny każdej tabeli poprzez analizę klauzuli DEFAULT. Ta metoda dostarcza informacji o połączonych sekwencjach kolumn i nie używa zależności, które mogą nie istnieć dla niektórych sekwencji. Nawet pg_get_serial_sequence(sch.nspname||'.'||tbl.relname, col.attname)funkcja nie znalazła dla mnie wszystkich sekwencji!

Rozwiązanie:

SELECT
    seq_sch.nspname  AS sequence_schema
  , seq.relname      AS sequence_name
  , seq_use."schema" AS used_in_schema
  , seq_use."table"  AS used_in_table
  , seq_use."column" AS used_in_column
FROM pg_class seq
  INNER JOIN pg_namespace seq_sch ON seq_sch.oid = seq.relnamespace
  LEFT JOIN (
              SELECT
                  sch.nspname AS "schema"
                , tbl.relname AS "table"
                , col.attname AS "column"
                , regexp_split_to_array(
                      TRIM(LEADING 'nextval(''' FROM
                           TRIM(TRAILING '''::regclass)' FROM
                                pg_get_expr(def.adbin, tbl.oid, TRUE)
                           )
                      )
                      , '\.'
                  )           AS column_sequence
              FROM pg_class tbl --the table
                INNER JOIN pg_namespace sch ON sch.oid = tbl.relnamespace
                --schema
                INNER JOIN pg_attribute col ON col.attrelid = tbl.oid
                --columns
                INNER JOIN pg_attrdef def ON (def.adrelid = tbl.oid AND def.adnum = col.attnum) --default values for columns
              WHERE tbl.relkind = 'r' --regular relations (tables) only
                    AND col.attnum > 0 --regular columns only
                    AND def.adsrc LIKE 'nextval(%)' --sequences only
            ) seq_use ON (seq_use.column_sequence [1] = seq_sch.nspname AND seq_use.column_sequence [2] = seq.relname)
WHERE seq.relkind = 'S' --sequences only
ORDER BY sequence_schema, sequence_name;

Zwróć uwagę, że 1 sekwencja może być używana w wielu tabelach, więc można ją tutaj wyświetlić w wielu wierszach.


0

Dzięki za pomoc.

Oto funkcja pl / pgsql, która aktualizuje każdą sekwencję bazy danych.

---------------------------------------------------------------------------------------------------------
--- Nom : reset_sequence
--- Description : Générique - met à jour les séquences au max de l'identifiant
---------------------------------------------------------------------------------------------------------

CREATE OR REPLACE FUNCTION reset_sequence() RETURNS void AS 
$BODY$
DECLARE _sql VARCHAR := '';
DECLARE result threecol%rowtype; 
BEGIN
FOR result IN 
WITH fq_objects AS (SELECT c.oid,n.nspname || '.' ||c.relname AS fqname ,c.relkind, c.relname AS relation FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace ),
    sequences AS (SELECT oid,fqname FROM fq_objects WHERE relkind = 'S'),
    tables    AS (SELECT oid, fqname FROM fq_objects WHERE relkind = 'r' )
SELECT
       s.fqname AS sequence,
       t.fqname AS table,
       a.attname AS column
FROM
     pg_depend d JOIN sequences s ON s.oid = d.objid
                 JOIN tables t ON t.oid = d.refobjid
                 JOIN pg_attribute a ON a.attrelid = d.refobjid and a.attnum = d.refobjsubid
WHERE
     d.deptype = 'a' 
LOOP
     EXECUTE 'SELECT setval('''||result.col1||''', COALESCE((SELECT MAX('||result.col3||')+1 FROM '||result.col2||'), 1), false);';
END LOOP;
END;$BODY$ LANGUAGE plpgsql;

SELECT * FROM reset_sequence();

0

Oto kolejny, który ma nazwę schematu obok nazwy sekwencji

select nspname,relname from pg_class c join pg_namespace n on c.relnamespace=n.oid where relkind = 'S' order by nspname

0

Ta funkcja pokazuje ostatnią_wartość każdej sekwencji.

Wyprowadza tabelę z 2 kolumnami, która zawiera nazwę sekwencji oraz ostatnią wygenerowaną wartość.

drop function if exists public.show_sequence_stats();
CREATE OR REPLACE FUNCTION public.show_sequence_stats()
    RETURNS TABLE(tablename text, last_value bigint) 
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE 
    ROWS 1000
AS $BODY$
declare r refcursor; rec record; dynamic_query varchar;
        BEGIN
            dynamic_query='select tablename,last_value from (';
            open r for execute 'select nspname,relname from pg_class c join pg_namespace n on c.relnamespace=n.oid where relkind = ''S'' order by nspname'; 
            fetch next from r into rec;
            while found 
            loop
                dynamic_query=dynamic_query || 'select '''|| rec.nspname || '.' || rec.relname ||''' "tablename",last_value from ' || rec.nspname || '.' || rec.relname || ' union all ';
                fetch next from r into rec; 
            end loop;
            close r; 
            dynamic_query=rtrim(dynamic_query,'union all') || ') x order by last_value desc;';
            return query execute dynamic_query;
        END;
$BODY$;

select * from show_sequence_stats();

0

Zakładając exec()funkcję zadeklarowaną w tym poście https://stackoverflow.com/a/46721603/653539 , sekwencje wraz z ich ostatnimi wartościami można pobrać jednym zapytaniem:

select s.sequence_schema, s.sequence_name,
  (select * from exec('select last_value from ' || s.sequence_schema || '.' || s.sequence_name) as e(lv bigint)) last_value
from information_schema.sequences s

0
select sequence_name, (xpath('/row/last_value/text()', xml_count))[1]::text::int as last_value
from (
    select sequence_schema,
            sequence_name,         
            query_to_xml(format('select last_value from %I.%I', sequence_schema, sequence_name), false, true, '') as xml_count
    from information_schema.sequences
    where sequence_schema = 'public'
) new_table order by last_value desc;

0

Oto przykład, jak użyć, psqlaby uzyskać listę wszystkich sekwencji z ich last_value:

psql -U <username> -d <database> -t -c "SELECT 'SELECT ''' || c.relname || ''' as sequence_name, last_value FROM ' || c.relname || ';' FROM pg_class c WHERE (c.relkind = 'S')" | psql -U <username> -d <database> -t

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.