ค้นหาคอลัมน์ว่างของตารางใน PostgreSQL


17

แบบสอบถามใดที่จะส่งคืนชื่อของคอลัมน์ของตารางที่ทุกแถวเป็น NULL


คุณหมายถึงตารางเฉพาะหรือตารางทั้งหมดในสคีมาหรือไม่
Jack Douglas

1
ทำไมคุณต้องทำเช่นนั้น? ดูเหมือนว่าคุณมีคอลัมน์ / ตารางมากเกินไปและควรคิดการออกแบบของคุณใหม่
eevar

คำตอบ:


13

testbed:

create role stack;
create schema authorization stack;
set role stack;

create table my_table as 
select generate_series(0,9) as id, 1 as val1, null::integer as val2;

create table my_table2 as 
select generate_series(0,9) as id, 1 as val1, null::integer as val2, 3 as val3;

ฟังก์ชั่น:

create function has_nonnulls(p_schema in text, p_table in text, p_column in text)
                returns boolean language plpgsql as $$
declare 
  b boolean;
begin
  execute 'select exists(select * from '||
          p_table||' where '||p_column||' is not null)' into b;
  return b;
end;$$;

แบบสอบถาม:

select table_schema, table_name, column_name, 
       has_nonnulls(table_schema, table_name, column_name)
from information_schema.columns
where table_schema='stack';

ผลลัพธ์:

 table_schema | table_name | column_name | has_nonnulls
--------------+------------+-------------+--------------
 stack        | my_table   | id          | t
 stack        | my_table   | val1        | t
 stack        | my_table   | val2        | f
 stack        | my_table2  | id          | t
 stack        | my_table2  | val1        | t
 stack        | my_table2  | val2        | f
 stack        | my_table2  | val3        | t
(7 rows)

นอกจากนี้คุณสามารถรับคำตอบโดยประมาณโดยการค้นหาแคตตาล็อก - ถ้าnull_fracเป็นศูนย์ที่ระบุว่าไม่มีค่า Null แต่ควรตรวจสอบซ้ำกับข้อมูล 'ของจริง':

select tablename, attname, null_frac from pg_stats where schemaname='stack';

 tablename | attname | null_frac
-----------+---------+-----------
 my_table  | id      |         0
 my_table  | val1    |         0
 my_table  | val2    |         1
 my_table2 | id      |         0
 my_table2 | val1    |         0
 my_table2 | val2    |         1
 my_table2 | val3    |         0
(7 rows)

1
นี่เป็นคำถามเก่าของเฮลลา แต่ผู้ที่ใช้ส่วนขยายเชิงพื้นที่ (postgis) ควรทราบว่าคอลัมน์อวกาศว่างไม่ปรากฏในpg_statsกรณีที่ว่างในการสร้างตาราง ฉันพบสิ่งนี้ในวันนี้เมื่อทำการดูแลทำความสะอาด ผมค้นพบว่าบางประวัติศาสตร์aspatialogr2ogrตารางได้ถูกนำเข้าใช้ หากไม่มีคอลัมน์อวกาศในข้อมูลที่กำลังนำเข้าogr2ogrสร้างคอลัมน์รูปทรงเรขาคณิตที่เต็มไป<NULL>ด้วย ของฉันpg_statsไม่มีคอลัมน์รูปทรงเรขาคณิตจากตาราง aspatial ที่นำเข้า (มันมีคอลัมน์อื่น ๆ ทั้งหมดสำหรับตารางเหล่านั้น) ฉันคิดว่าค่อนข้างแปลก
GT

6

ใน Postgresql คุณสามารถรับข้อมูลได้โดยตรงจากสถิติ:

vacuum analyze; -- if needed

select schemaname, tablename, attname
from pg_stats
where most_common_vals is null
and most_common_freqs is null
and histogram_bounds is null
and correlation is null
and null_frac = 1;

คุณอาจได้รับผลบวกปลอมสองสามข้อดังนั้นการตรวจสอบใหม่จึงเป็นไปตามลำดับหลังจากหาผู้สมัคร


คุณต้องการเงื่อนไขอื่นนอกเหนือจากนี้null_frac=1หรือไม่?
แจ็คดักลาส

ฉันไม่แน่ใจ. null_frac น่าจะเป็นจริงดังนั้นมันอาจเป็นได้ว่ามันปัดเศษเป็น 1 ในบางกรณีที่แปลก แต่ถึงแม้จะมี 1 จาก 10k แถวก็จะส่งผลในสิ่งที่เหมาะ
เดนิสเดอเบอร์นาดี

1

ฉันจะแสดงวิธีแก้ปัญหาของฉันใน T-SQL ที่ทำงานกับ SQL Server 2008 ฉันไม่คุ้นเคยกับ PostgreSQL แต่ฉันหวังว่าคุณจะพบแนวทางในการแก้ปัญหาของฉัน

-- create test table
IF object_id ('dbo.TestTable') is not null
    DROP table testTable
go
create table testTable (
    id int identity primary key clustered,
    nullColumn varchar(100) NULL,
    notNullColumn varchar(100) not null,
    combinedColumn varchar(100) NULL,
    testTime datetime default getdate()
);
go

-- insert test data:
INSERT INTO testTable(nullColumn, notNullColumn, combinedColumn)
SELECT NULL, 'Test', 'Combination'
from sys.objects
union all
SELECT NULL, 'Test2', NULL
from sys.objects

select *
from testTable

-- FIXED SCRIPT FOR KNOWN TABLE (known structure) - find all completely NULL columns
select sum(datalength(id)) as SumColLength,
    'id' as ColumnName
from dbo.testTable
UNION ALL
select sum(datalength(nullColumn)) as SumColLength,
    'nullColumn' as ColumnName
from dbo.testTable
UNION ALL
select sum(datalength(notNullColumn)) as SumColLength,
    'notNullColumn' as ColumnName
from dbo.testTable
UNION ALL
select sum(datalength(combinedColumn)) as SumColLength,
    'combinedColumn' as ColumnName
from dbo.testTable
UNION ALL
select sum(datalength(testTime)) as SumColLength,
    'testTime' as ColumnName
from dbo.testTable

-- DYNAMIC SCRIPT (unknown structure) - find all completely NULL columns
declare @sql varchar(max) = '', @tableName sysname = 'testTable';

SELECT @sql +=
        'select sum(datalength(' + c.COLUMN_NAME + ')) as SumColLength,
    ''' + c.COLUMN_NAME + ''' as ColumnName
from ' + c.TABLE_SCHEMA + '.' + c.TABLE_NAME --as StatementToExecute
+ '
UNION ALL
'
FROM INFORMATION_SCHEMA.COLUMNS c
WHERE c.TABLE_NAME = @tableName;

SET @sql = left(@sql, len(@sql)-11)
print @sql;
exec (@sql);

สิ่งที่ฉันทำในระยะสั้นคือการสร้างตารางทดสอบที่มี 5 คอลัมน์ ID และ testTime ที่ถูกสร้างขึ้นโดยฟังก์ชั่นเอกลักษณ์และ getdate () ในขณะที่คอลัมน์ 3 varchar เป็นส่วนที่น่าสนใจ หนึ่งจะมีค่า NULL เท่านั้นหนึ่งจะไม่มี NULL ใด ๆ อื่น ๆ จะเป็นคอลัมน์รวมกัน ผลลัพธ์สุดท้ายของสคริปต์คือสคริปต์จะรายงานคอลัมน์ nullColumn ว่ามีทุกแถว NULL

แนวคิดคือการคำนวณฟังก์ชันDATALENGTHสำหรับแต่ละคอลัมน์ (คำนวณจำนวนไบต์สำหรับนิพจน์ที่กำหนด) ดังนั้นฉันจึงคำนวณค่า DATALENGTH สำหรับแต่ละแถวของแต่ละคอลัมน์และทำ SUM ต่อคอลัมน์ ถ้า SUM ต่อคอลัมน์เป็น NULL คอลัมน์ที่สมบูรณ์จะมีแถว NULL มิฉะนั้นจะมีข้อมูลบางส่วนอยู่ภายใน

ตอนนี้คุณต้องค้นหาคำแปลสำหรับ PostgreSQL และหวังว่าเพื่อนร่วมงานจะสามารถช่วยคุณได้ หรืออาจจะมีมุมมองระบบที่ดีที่จะแสดงให้เห็นว่าฉันโง่สำหรับการคิดค้นล้อใหม่ :-)


1

คุณจำเป็นต้องค้นหาแคตตาล็อกข้อมูลสำหรับข้อมูลดังกล่าว:

SELECT column_name FROM information_schema.columns WHERE table_name='your_table'

ให้ตารางการจับคู่สำหรับคอลัมน์ของคุณ

ฉันยังไม่มีการติดตั้ง postgres ในขณะนี้ แต่ส่วนที่เหลือควรเรียบง่าย

   loop over the results of the above query and foreach result
        send a COUNT(*) to the table
        if the count is null, give back the column,
                 else ignore it
   end foreach

วิธีนี้ใช้งานได้ แต่เป็นวิธีการวนซ้ำ :-) ฉันชอบวิธีการตั้งค่าตาม
แมเรียน

0

หลังจากรวมจากแหล่งข้อมูลต่าง ๆ ฉันมาพร้อมกับฟังก์ชันนี้และแบบสอบถามเพื่อค้นหาคอลัมน์ว่างทั้งหมดในตารางฐานข้อมูลทั้งหมด

CREATE OR REPLACE FUNCTION public.isEmptyColumn(IN table_name varchar, IN column_name varchar)
RETURNS boolean AS $$
declare 
    count integer;
BEGIN
    execute FORMAT('SELECT COUNT(*) from %s WHERE %s IS NOT NULL', table_name, quote_ident(column_name)) into count;
    RETURN (count = 0);
END; $$
LANGUAGE PLPGSQL; 


SELECT s.table_name, s.column_name
FROM information_schema.columns s
WHERE (s.table_schema LIKE 'public') AND
      (s.table_name NOT LIKE 'pg_%') AND
      (public.isEmptyColumn(s.table_name, s.column_name))

สนุก :)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.