I will provide the macro below, in short what it does though. It takes a libname and gets all the columns in that libname. For each column name it gets the count(*) and count(columnname) so that we can check for missing values.
Is there a more efficient way to do this? Because of our huge libnames sometimes I make over 1.000 requests to a database and I presume that's not a good thing to do.
Simply doing a select * and temporarely saving it is not an option for a table over 100 milion rows.
Below some sample output:
Tabelnaam Kolomnaam Aantal_regels Aantal_gevulde_regels Missende_regels Percentage_gevuld
--------- --------- ------------- --------------------- --------------- -----------------
FCT_sales ID_BRON 1.000.000 900.000 100.000 90.00%
FCT_sales NR_SCHNOT 1.000.000 1.000.000 0 100.00%
DIM_worker emp_id 100.000 100.000 0 100.00%
%macro database_null_check
(database= /*LIBREF voor een database, voorbeeld: DMdata*/
);
/*Aangeven dat de macro begonnen is*/
%put ---------------------------------------------------------------;
%put --- Start van %upcase (&sysmacroname) macro;
%put ---;
/*Elke macro waarde naar de log schrijven*/
%put --- Macro parameter waardes;
%put --- database = &database;
%put ---------------------------------------------------------------;
/*Ophalen metadata gegevens van de library*/
PROC SQL;
CREATE TABLE &database AS
SELECT
(libname||'.'||memname) AS Database_tabel
, memname AS Tabelnaam
, name AS Kolomnaam
FROM dictionary.columns
WHERE libname = %UPCASE("&database");
RUN;
/*Toevoegen volgnummer om een dynamische do loop te maken*/
DATA metadata;
SET &database;
volgnummer = _N_;
RUN;
PROC SQL NOPRINT;
SELECT MAX(volgnummer) into: aantal_tabelkolommen
FROM metadata;
RUN;
DATA null_controle;
LENGTH Tabelnaam $40.;
LENGTH Kolomnaam $40.;
LENGTH Aantal_regels 8;
LENGTH Aantal_gevulde_regels 8;
RUN;
/*Doorloopt elke kolom in de database en voert hier de acties op uit*/
%DO i=1 %to &aantal_tabelkolommen;
PROC SQL NOPRINT;
SELECT Database_tabel, Tabelnaam, Kolomnaam
INTO :database_tabel, :tabelnaam, :kolomnaam
FROM metadata
WHERE volgnummer = &i.;
RUN;
%put ------------------;
%put &database_tabel;
%put &kolomnaam;
%put ------------------;
PROC SQL;
CREATE TABLE stap1_&i. AS
SELECT
"&tabelnaam" AS Tabelnaam
, "&kolomnaam" AS Kolomnaam
, COUNT(*) AS Aantal_regels
, COUNT(&kolomnaam) AS Aantal_gevulde_regels
FROM &database_tabel;
RUN;
DATA stap2_&i.;
LENGTH Tabelnaam $40.;
LENGTH Kolomnaam $40.;
LENGTH Aantal_regels 8;
LENGTH Aantal_gevulde_regels 8;
SET stap1_&i.;
RUN;
PROC APPEND
BASE=null_controle
DATA=stap2_&i.;
RUN;
%dsdelete(ds=stap1_&i.);
%dsdelete(ds=stap2_&i.);
%END;
PROC SQL;
CREATE TABLE output_null_controle AS
SELECT
Tabelnaam
, Kolomnaam
, aantal_regels FORMAT COMMA10.0
, aantal_gevulde_regels FORMAT COMMA10.0
, (aantal_regels-aantal_gevulde_regels) AS Missende_regels FORMAT COMMA10.0
, (aantal_gevulde_regels/aantal_regels) AS Percentage_gevuld FORMAT PERCENT10.2
FROM null_controle
WHERE tabelnaam IS NOT NULL;
RUN;
/*Opschonen van macro files*/
%dsdelete(ds=metadata);
%dsdelete(ds=&database);
%dsdelete(ds=null_controle);
/*Aangeven dat de macro klaar is*/
%put ---------------------------------------------------------------;
%put --- Einde van %upcase (&sysmacroname) macro;
%put ---------------------------------------------------------------;
%mend;```