Znalezienie pierwszego wolnego numeru w ciągu znaków

0

Cześć,
Mam tabelę o nazwie Tabela z kolumną o nazwie Numer. Dane w kolumnie Numer są ciągiem znaków w stylu: 123-1, 321-2, 231-1-2, 312-2-02 itd. Czyli jest to ciąg cyfr z myślnikami. Numery są unikalne (nie powtarzają się). Myślnik oznacza kolejny poziom w hierarchii. W numeracji mogą być jednak braki np. numer 250 może mieć kolejny poziom typu 250-1 a ten kolejne poziomy w stylu: 250-1-1, 250-1-2, 250-1-5, 250-1-6 (brak numerów 250-1-3 oraz 250-1-4).
Moje pytanie jest: jak napisać zapytanie, które zwróci pierwszy wolny numer dla podanego numeru? Np. wracając do powyższego przykładu, chcę wiedzieć jaki jest pierwszy wolny numer dla numer 250-1 -> dla podanych wyżej numerów będzie to 250-1-3 (są numery późniejsze, ale ten jest pierwszy wolny).

Z góry dzięki za pomoc.

1

@WojtekN nie da się tu napisać żadnego prostego zapytania które coś takiego zwróci. Musiałbyś sobie posortować te dane a potem przeglądać w pętlach i rozbijać na kolejne poziomy. Generalnie trochę hardkor i ja bym jednak przemyślał strukturę tej bazy.

0

@artur_bredzki
Tak jak pisałem wcześniej powiedzmy, że w kolumnie Numer przechowuję takie numery: 250-1-1, 250-1-2, 250-1-5, 250-1-6. Chcę wydobyć taki numer, który zaczyna się od 250-1 a kolejna cyfra po myślniku jest pierwszą wolną tj. -3 (250-1-3). Spawa ogólnie się troszkę jeszcze komplikuje, bo każdy z tych numerów może mieć kolejne poziomy tj. np. numer 250-1-5 może składać się z 250-1-5-1 oraz 250-1-5-2.

Numery, które mnie interesują można wydobyć tak: select * From Tabela Where Numer Like '250-1-%'
Następnie muszę usunąć ewentualne następne poziomy tj. z wydobytych numerów muszę jakoś uciąć '-%'...
Wtedy będę miał wszystkie znaki z których składa się poziom, który mnie interesuje (znak "-" jest swego rodzaju separatorem poziomu).
Zakładając, że poziomy składają się tylko z cyfr to chciałbym wiedzieć jaka jest najmniejsza wolna liczba zaczynając od 1. Jeśli nie byłoby numeru "1" (np. pierwszym numerem byłby 250-1-2) to chciałbym, żeby została zwrócona liczba 1. W powyższym przykładzie powinna zostać zwrócona liczba 3 (pierwszy wolny numer)

Mam nadzieję, że już jest bardziej czytelne o co mi chodzi :)

0

@Shalom
Niestety ja nie mam wpływu na strukturę bazy :-/. Zresztą ona nie jest taka zła - po prostu ja mam taki specyficzny problem... Do tego wszystko muszę zrobić w SQL-u :-/

0
WojtekN napisał(a):

@artur_bredzki
Tak jak pisałem wcześniej powiedzmy, że w kolumnie Numer przechowuję takie numery: 250-1-1, 250-1-2, 250-1-5, 250-1-6. Chcę wydobyć taki numer, który zaczyna się od 250-1 a kolejna cyfra po myślniku jest pierwszą wolną tj. -3 (250-1-3).

...jest następną/kolejną wolną, bo jeszcze ktoś pomyśli, że chodzi o pierwszą ;-)

WojtekN napisał(a):

Spawa ogólnie się troszkę jeszcze komplikuje, bo każdy z tych numerów może mieć kolejne poziomy tj. np. numer 250-1-5 może składać się z 250-1-5-1 oraz 250-1-5-2.

Trzeba zapytaniem sprawdzić, czy są kolejne poziomy.

WojtekN napisał(a):

Numery, które mnie interesują można wydobyć tak: select * From Tabela Where Numer Like '250-1-%'
Następnie muszę usunąć ewentualne następne poziomy tj. z wydobytych numerów muszę jakoś uciąć '-%'...
Wtedy będę miał wszystkie znaki z których składa się poziom, który mnie interesuje (znak "-" jest swego rodzaju separatorem poziomu).

Można to rozwiązać kilkoma zapytaniami, takimi jak podałeś.

WojtekN napisał(a):

Zakładając, że poziomy składają się tylko z cyfr to chciałbym wiedzieć jaka jest najmniejsza wolna liczba zaczynając od 1. Jeśli nie byłoby numeru "1" (np. pierwszym numerem byłby 250-1-2) to chciałbym, żeby została zwrócona liczba 1. W powyższym przykładzie powinna zostać zwrócona liczba 3 (pierwszy wolny numer)

Mam nadzieję, że już jest bardziej czytelne o co mi chodzi :)

</quote> Ok, zmyliło mnie to, że numer zawiera myślniki, dla mnie numer to ciąg cyfr, ja bym napisał symbol lub nazwa.
0

Najprościej jak mi się udało, na przykładzie bazy postgresql dla 'numeru' 83-xxxxxxx. Nie zastanawiałęm się nad tym zbyt długo, więc usterki być może są.

rollback;

\pset pager off
\timing off
SET statement_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SET check_function_bodies = false;
SET client_min_messages = warning;

\c postgres;
set role postgres;


DROP DATABASE IF EXISTS numer_db;
DROP TABLESPACE IF EXISTS numer_dbspace;
DROP ROLE IF EXISTS numer_db;


CREATE ROLE numer_db PASSWORD 'numer_db' NOSUPERUSER NOCREATEDB NOCREATEROLE INHERIT LOGIN;
CREATE DATABASE numer_db OWNER numer_db ENCODING 'UTF-8';
\c numer_db;

set role numer_db;



CREATE SEQUENCE seq_numer START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 100;


CREATE TABLE numers (
    id      bigint DEFAULT nextval('seq_numer') NOT NULL,
    numer    character varying(48) NOT NULL
) ;
ALTER TABLE ONLY numers ADD CONSTRAINT numers_pkey PRIMARY KEY (id);


create or replace function mk_data(length integer) returns void as 
$$
declare
  i integer;
  vnumer text;
begin
  
  for i in 1..length loop
    vnumer = floor( random() * 120 + 2 );
    if random() < 0.3 then
      vnumer = vnumer || '-' || floor( random() * 120 + 1 );
    end if;
    if random() < 0.3 then
      vnumer = vnumer || '-' || floor( random() * 120 + 1 );
    end if;
    if random() < 0.3 then
      vnumer = vnumer || '-' || floor( random() * 120 + 1 );
    end if;
    
    execute 'insert into numers (numer) values ($1)' using vnumer;

    
  end loop;
end;
$$ language plpgsql;




begin;
\timing on
select mk_data(1000);
\timing off
commit;

select * from numers limit 10;


select s from (select generate_series(1,1000) as s ) as s  where s.s not in (select (string_to_array(numer,'-'))[2]::integer as nr  from numers where (string_to_array(numer,'-'))[1] = '83' and (string_to_array(numer,'-'))[2] <> '') limit 1;
insert into numers (numer) values ('83-1');
select s from (select generate_series(1,1000) as s ) as s  where s.s not in (select (string_to_array(numer,'-'))[2]::integer as nr  from numers where (string_to_array(numer,'-'))[1] = '83' and (string_to_array(numer,'-'))[2] <> '') limit 1;


0

Dziękuję bardzo za pomoc!
Myślę, że plusik się należy :).

1 użytkowników online, w tym zalogowanych: 0, gości: 1