2022-03-16
Jeden z ostatnich kroków migracji danych, to sprawdzenie, czy migracja „niczego nie zgubiła”. Potencjalnie można się np. spodziewać, że tuż po zakończeniu migracji, jakiś zbłąkany użytkownik dopisał swoje rekordy do źródłowej bazy danych, a my tego rekordu nie przenieśliśmy. Jeden z „topornych” sposobów sprawdzenia, czy żaden rekord nie zostanie utracony, jest po prostu policzenie rekordów w źródłowej i docelowej bazie danych.
Najpierw wypadałoby ustalić, jakie mamy schematy w bazie. Robimy to głównie po to, żeby wykluczyć z raportu schematy systemowe, względnie inne, które mają być z jakiegoś powodu ominięte. psql pozwala na uruchomienie skróconego polecenia \dn, ale ta właśnie pomija schematy systemowe. Dlatego proponuję:
SELECT schema_name FROM information_schema.schemata;
Oto możliwy wynik:
schema_name
--------------------
public
information_schema
pg_catalog
pg_toast_temp_1
pg_temp_1
pg_toast
Znając schematy bazy danych, pora na sztuczkę. Poniższe zapytanie automatycznie zbierze ze wszystkich tabel z wybranych schematów liczbę rekordów. Ponieważ zapytanie jest uruchamiane na faktycznych danych (a nie np. ze statystyk), jego wykonanie może zająć chwilę czasu. Zapytanie jest sprytne, bo korzysta z możliwości wykonania XML w tym zapytaniu. Poniekąd więc dla każdego rekordu zwracanego z tabel systemowych uruchomi się jeszcze jedno zapytanie XML, zliczające liczbę rekordów:
select table_schema,
table_name,
(xpath('/row/cnt/text()', xml_count))[1]::text::int as row_count
from (
select table_name,
table_schema,
query_to_xml(format('select count(*) as cnt from %I.%I', table_schema, table_name), false, true, '') as xml_count
from information_schema.tables
where table_schema NOT LIKE 'pg_%' and table_schema != 'information_schema'
) t
U mnie zwrcony wynik wygląda mniej więcej tak:
table_schema | table_name | row_count
--------------+--------------------+-----------
public | pg_stat_statements | 0
public | towns4 | 1000000
public | pg_buffercache | 262144
public | towns5 | 1000000
public | towns | 1000000
public | towns2 | 1000000
public | towns3 | 1000000
public | towns6 | 1000000
public | towns7 | 1000000
public | towns8 | 1000000
public | towns9 | 1000000
public | towns0 | 1000000
public | large_test | 20000000
public | a_table | 1013
(14 rows)
Powyższe zapytanie można by uruchomić na obu bazach danych i po prostu porównać uzyskane wyniki – czy to excelu, czy pythonie, czy palcem na ekranie – obojętnie.
Istnieją też inne propozycje rozwiązania tego problemu, ale niekoniecznie zliczające rekordy co do jednego, np. zapytanie:
SELECT relname,
n_tup_ins - n_tup_del as rowcount
FROM pg_stat_all_tables
WHERE schemaname NOT LIKE 'pg_%' and schemaname != 'information_schema';
zwraca:
relname | rowcount
------------+----------
towns | 1044898
towns5 | 1000000
towns6 | 1000000
a_table | 1016
towns4 | 1000000
large_test | 20000000
towns7 | 1000000
towns2 | 1000000
towns0 | 1000000
towns9 | 1000000
towns8 | 1000000
towns3 | 1000000
(12 rows)
ale już dla tabeli a_table, widać różnice… Jeśli więc, chcesz mieć dokładne wyniki, to musisz liczyć wszystko. Z pomocą powyższych zapytań będzie to i tak rozwiązanie automatyczne, tylko może z punktu widzenia PostgreSQL, jakby trochę na piechotę.
2022-03-16
Niektóre mechanizmy PostgreSQL, jak np. replikacja logiczna wymagają, aby tabele posiadały primary key. Dlatego przyda się wiedzieć, czy baza danych spełnia wymogi dla replikacji logicznej. Oto polecenie, które wyświetli informację o tabelach bez primary key:
select tab.table_schema,
tab.table_name
from information_schema.tables tab
left join information_schema.table_constraints tco
on tab.table_schema = tco.table_schema
and tab.table_name = tco.table_name
and tco.constraint_type = 'PRIMARY KEY'
where tab.table_type = 'BASE TABLE'
and tab.table_schema not in ('pg_catalog', 'information_schema')
and tco.constraint_name is null
order by table_schema, table_name;
I co jeśli takie tabele się znajdą? Ogólnie masz kłopot, ale w najlepszym przypadku, znajdzie się w tabelach kolumna, która może być potraktowana jako primary key. Zaczynamy więc od sprawdzenia struktur tabel:
mytest=> \d towns
Table "public.towns"
Column | Type | Collation | Nullable | Default
------------+-----------------------+-----------+----------+-----------------------------------
id | integer | | not null | nextval('towns_id_seq'::regclass)
code | character varying(10) | | not null |
article | text | | |
name | text | | not null |
department | character varying(4) | | not null |
Indexes:
"towns_code_department_key" UNIQUE CONSTRAINT, btree (code, department)
"towns_id_key" UNIQUE CONSTRAINT, btree (id)
Dodanie indeksu opartego o kolumnę id wyglądałoby tak:
alter table towns add primary key (id);
I gotowe!
2022-03-12
Problem:
Dane pochodzące z wielu plików, zostały zaimportowane do Pandas Data Frame w następującej postaci:

Chcielibyśmy uniknąć wielokrotnie powtarzanej daty, wartości numeryczne znajdujące się w col1, col2 i col3 powinny się nasumować, dając taki efekt:

Rozwiązanie:
Wydaje się, że funkcjonalnością stworzoną do takiego celu jest grupowanie. Wystarczy na rzecz obiektu data frame wywołać metodę groupby wskazując, że grupowanie ma się odbyć ze względu na datę, a dla kolumn numerycznych chcemy zobaczyć sumę. Oto propozycja rozwiązania:
import pandas as pd
data = ({
'date' :['2000-01','2000-02','2000-01','2000-02','2000-01','2000-02'],
'col1' :[22000,25000,0,0,0,0],
'col2' :[0,0,23000,24000,0,0],
'col3' :[0,0,0,0,26000,25000]
})
df = pd.DataFrame(data, columns=['date','col1','col2','col3'])
print(df)
df2 = df.groupby('date').sum()
print(df2)
2022-03-05
Zadanie z jakim się zmierzam, to ustalenie minimalnych uprawnień jakie powinien posiadać użytkownik, aby wykonać pewną czynność. W tym przypadku chodziło o budowanie specyficznej infrastruktury z wykorzystaniem skryptu Terraform, ale metoda sprawdzi się też w innych scenariuszach.
Zacząłem od stworzenia service principal, bo w moim przypadku skrypt miał być uruchamiany na service principal. Gdyby miało to być zwykłe konto użytkownika, to oczywiście należało by stworzyć konto:
az ad sp create-for-rbac --name myserviceprincipal
W wyniku tego polecenia jest tworzony service principal, a w zwróconym output można znaleźć coś w tym stylu:
{
"appId": "6...XXX...",
"displayName": "myserviceprincipal",
"password": "y...XXX...",
"tenant": "6...XXX..."
}
Mamy tu: appId, bo jest on wykorzystywany przez dalsze polecenia i można go utożsamiać z określonym service principal i password, bo to tajna część utworzonego właśnie service principal i wreszcie tenant określający, gdzie tego service principal można używać (w jakiej organizacji). Czytaj dalej »
2022-02-23
CTRL+w s podział okna na 2 ułożone obok siebie – s jak split
CTRL+w v podział okna na 2 ułożone jedno pod drugim – v jak vertical
CTRL+w n otwarcie nowego okna, poniżej – n jak new
CTRL+w q wyjście z okna – q jak quit
CTRL+w i jeden z klawiszy hjkl lub strzałki – zmiana aktywnego okna na po lewej, prawej u góry lub na dole
CTRL+w w – zmiana aktywnego okna na kolejne (pętelka)
CTRL+w r – zmiana miejscami okien – r jak rotate
CTRL+w i jeden z klaiszy + – = – zmiana wielkości okna: powieksz, pomniejsz, ułóż równo
:ter – uruchomienie terminala (można dzięki temu symulować wygląd code)
:set cursorline cursorcolumn – bieżący wiersz i kolumna będą wyróżnione
:highlight CursorColumn ctermbg=Grey ctermfg=Black – zmiana koloru kolumny wyróżniającej
Jeśli w trakcie testowania klawiszy przypadkiem naciśniesz CTRL+s, to terminal się „zamrozi”. Odmrożenie można wykonać naciskając CTRL+q
Ustawienia, zwłaszcza te dotyczące kolorów, można na stałe zapisać w pliku .vimrc o tak:
cat .vimrc
set cursorline cursorcolumn
highlight CursorColumn ctermbg=Grey ctermfg=Black
Pełny help dotyczący również innych skrótów zobaczysz wpisując polecenie:
:help windows.txt
2022-02-19
Domyślne linki pozwalające na instalację przeglądarki MS Edge na Windows Server 2019 nie działają… dzięki Microsoft!
Ale ten link zadziała:
https://www.microsoft.com/en-us/edge/business/download
Co istotne, może być wymagana zmiana ustawień bezpieczeństwa w IE, żeby instalator edge dało się pobrać.
- Należy przejść do IE -> Internet Options
- Na zakładce Security wybrać Custom Level
- Przewinąć prawie na sam dół. Jest tam sekcja Scripting
- Upewnić się, że opcja Active Scripting jest ustawiona na „Enable”
Enjoy!
2022-02-09
Gdy skrypt, który przygotowujesz musi pracować z róznymi tenantami i subskrypcjami przyda się wiedza na temat tego jak wybrać właściwą subskrypcję z linii komend. A robi się to tak:
Logowanie poleceniem az do Azure:
az login
Sprawdzenie „a gdzie to ja się właściwie zalogowałem”:
az account show
{
"environmentName": "AzureCloud",
"homeTenantId": "7d*****-****-****-****-**********aa",
"id": "cc******-****-****-****-**********78",
"isDefault": true,
"managedByTenants": [],
"name": "Azure Pass - Sponsorship",
"state": "Enabled",
"tenantId": "7d*****-****-****-****-**********aa",
"user": {
"name": "m******@*****.pl",
"type": "user"
}
}
Identyfikator subskrypcji widać już właściwie powyżej w polu id.
Wyświetlenie dostępnych subskrypcji:
az account list --output table
Name CloudName SubscriptionId State IsDefault
------------------------ ----------- ------------------------------------ ------- -----------
Azure Pass - Sponsorship AzureCloud cce*****-****-****-****-**********78 Enabled True
MSDN Platforms AzureCloud b0f*****-****-****-****-**********56 Enabled False
Przełączenie się do innej subskrypcji:
az account set --subscription "MSDN Platforms"
To polecenie jest ciche, więc po wszystkim radziłbym ponownie wylistować konta i sprawdzić, czy aktywna jest właściwa subskrypcja
Więcej: https://docs.microsoft.com/pl-pl/cli/azure/manage-azure-subscriptions-azure-cli