Oracle][ Zaliczenie - zebranie informacji o bazie

0

Cześć! Mam do zrobienia a nie za bardzo wiem jak, taką rzecz: zebranie informacji o bazie danych. Nie jest podane jaka - ma jakieś tabele, z jakimiś wierszami. Skrypcik ma sprawdzić jakie są w bazie kolumny, ile jest wierszy, wyliczyć dla każdej kolumny wiersze nullowe i nienullowe, wartość max i min każdej.

Z mojego obecnego stanowiska zacząłbym mniej więcej tak:

select column_name from information_schema.COLUMNS; 

co mi pozwoli wziąć te kolumny, dołożyłbym

select column_name, count(*) from information_schema.COLUMNS; 

to chyba pozwoli pokazać ilość wierszy w danej kolumnie.
Zastanawiam się co dalej. W info_schema jest takie cudo jak "IS_NULL", ale to pokazuje tylko czy w danej kolumnie są jakieś nulle.
Myślałem, że może pierdyknąć podzapytanie skorelowane typu:

select column_name, count(*), (select count(*) from ?table? where column_name is not null) from information_schema.COLUMNS; 

Tylko właśnie, tutaj "malusi" problem :) Mógłby mi ktoś pokazać jak to wrzucić do pętli która by leciała po tych wszystkich kolumnach? Szkoda, że to nie jakiś Cpp czy C# :P...

0

tak się nie da zrobić dla wszystkich baz. Każda baza ma takie informacje inaczej przechowywane. Możesz napisać taki skrypt pod konkretną bazę. Najpierw zdecyduj jaka to baza ma być. Co do np. pętli to google twoim przyjaciulem

0

No ma być dla jednej bazy, z tym że nie wiem ile ma tabel i jakie.
Czyli dobrze rozumuję, żeby to zapętlić w ten sposób co powyżej? Chciałem głównie wiedzieć, czy idę w dobrą stronę, bo czasem błądzę po omacku :)

0

ja bym tam skoystał z ALL_TABLES i DBA_TAB_SOLUMNS - masz w nich info o liczbie rekordów, nulli itp

0

Niestety muszę sam taką operację wykonać/zrobić.

1

Hasło do Wójka G: "oracle dynamic sql minimum value in each column".

1

Przecież masz np. kursory. Tutaj są przykłady do wszystkiego co Ci jest potrzebne, żeby to napisać. Przykłady są oczywiście przykładami jak to można zrobić a nie przykładowymi rozwiązaniami Twojego problemu

0

Pomieszałem, poczarowałem i wyszło póki co takie cudo :) Zdaje się, że działa (chyba).

 declare 
 kolumny record; 
 sql varchar;
 cnt_not_null int;
 wynik record;
 begin 
 	FOR kolumny in select column_name from information_schema where table_name = 'TESTOWA' 
 	LOOP 
 		sql := 'select count(*) a from TESTOWA where ' || kolumny.column_name || ' is not null;'; 
		for wynik in execute sql loop
		  cnt_not_null:=wynik.a;
		end loop;
 		INSERT INTO TEST_TAB VALUES (cnt_not_null);
 	END LOOP; 
 return 0; 
 end;

Przyjmując, że działa jest podobne w konstrukcji do C++/# (czy innych kompilowanych języków), zatem żeby "poszło" mi po kolei po wszystkich tabelach powinienem dodać jeszcze jednego FORa + LOOPa tworząc pętle zagnieżdżoną i w teorii coś takiego powinno zadziałać:

FOR tabele in select distinct table_name from information_schema
LOOP
   FOR kolumny in select column_name from information_schema where table_name = tabele.table_name
 	LOOP 
 		sql := 'select count(*) a from ' || tabele.table_name || ' where ' || kolumny.column_name || ' is not null;'; 
		for wynik in execute sql loop
		  cnt_not_null:=wynik.a;
		end loop;
 		INSERT INTO TEST_TAB VALUES (cnt_not_null);
 	END LOOP; 
END LOOP;

Jeśli się mylę i/albo coś przeoczyłem bardzo proszę mnie poprawić.

1

no nie do końca. Za bardzo sobie życie utrudniasz

 SQL := 'select count(*) INTO cnt_not_null from TESTOWA where ' || kolumny.column_name || ' is not null;'; 

załatwia sprawę pobrania do zmiennej - tam będziesz miał ZAWSZE jako wynik jeden rekord.

0

Nie do końca, bo potem będę dokładał tutaj jeszcze inne rzeczy, w ten sposób chyba będzie mi najprościej to pozbierać.

@IMHO Miałeś racje, nie ma sensu pomnażać bo o ile w małych bazach to nie robi różnicy o tyle operując na dużej to jest ogromna różnica. Takie cudo działa ZNACZNIE szybciej:

FOR kolumny IN SELECT column_name FROM information_schema WHERE TABLE_NAME = 'TESTOWA' 
     	LOOP 
         SQL := 'SELECT (select count(*) from TESTOWA where ' || kolumny.column_name || ' is not null) a
, (select count(*) a from TESTOWA where ' || kolumny.column_name || ' is null) b;'; 
        FOR wynik IN EXECUTE SQL loop
          cnt_not_null:=wynik.a;
          cnt_null:=wynik.b;
        END loop;
         INSERT INTO TEST_TAB VALUES (cnt_not_null,cnt_null);
     	END LOOP;  
1

chodziło mi o to, że zamiast robić FOR na zapytaniu, które ZAWSZE zwróci JEDEN rekord lepiej jest zrobić INTO

0

A wybacz przeoczyłem. Dzięki!
Jednak dając into costam - costam pozostaje nullowe, przynajmniej jeśli zrobie cos takiego:

SQL := 'SELECT (select count(*) into cnt_not_null from TESTOWA where ' || kolumny.column_name || ' is not null)
, (select count(*) into ' || cnt_null || ' from TESTOWA where ' || kolumny.column_name || ' is null);'; 

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