簡體   English   中英

如何 UPIVOT 表中的所有列並聚合到數據質量/驗證指標中? SQL 雪花

[英]How to UPIVOT all columns in a table and aggregate into Data Quality/ Validation Metrics? SQL SNOWFLAKE

我有一個包含 60 多列的表,我想 UNPIVOT 以便每一列變成一行,然后找到每個條目的填充率、最小值和最大值。

例如

ID 開始日期 結束日期 EVENT_ID PROVIDER_CODE
01 21 年 1 月 23 日 21 年 3 月 14 日 0023401 0012323
02 21 年 6 月 4 日 21 年 9 月 20 日 0025906 0023454
03 21 年 7 月 20 日 12/02/21 0027093 0034983

我希望 output 看起來像

列名 填充率 最大限度
ID 0.7934 01 03
開始日期 0.6990 21 年 1 月 23 日 21 年 7 月 20 日
結束日期 0.9089 21 年 3 月 14 日 12/02/21
事件 ID 1.0000 0023401 0027093

努力得到想要的 output,尤其是因為不同列中的數據類型不同

我嘗試執行以下操作,但它不允許在 unpivot 中使用 agg 函數

select *
from "DSVC_MERCKPAN_PROD"."COHORTS_LATEST"."MEDICAL_HEADERS"
UNPIVOT (
max(code) as max_value,
min(code) as min_value,
avg(code) as fill_rate,
code as column_name
)

對於填充率,我嘗試使用此邏輯,因為始終填充 ID,因此它具有總行數,但是其他列可以是 null

 (COUNT_IF(start_date is not null))/(COUNT_IF(ID is not null))) as FILL_RATE,

我有 2 個想法來實施該報告。

第一種方法是將所有值轉換為VARCHAR然后使用UNPIVOT

-- Generate dummy data
create or replace table t1 (c1 int, c2 int, c3 int, c4 int, c5 int, c6 int, c7 int, c8 int, c9 int, c10 int) as
select
    iff(random()%2=0, random(), null), iff(random()%2=0, random(), null),
    iff(random()%2=0, random(), null), iff(random()%2=0, random(), null),
    iff(random()%2=0, random(), null), iff(random()%2=0, random(), null),
    iff(random()%2=0, random(), null), iff(random()%2=0, random(), null),
    iff(random()%2=0, random(), null), iff(random()%2=0, random(), null)
from table(generator(rowcount => 1000000000))
;

-- Query
with
cols as (
    select column_name, ordinal_position
    from information_schema.columns
    where table_catalog = current_database()
    and table_schema = current_schema()
    and table_name = 'T1'
),
stringified as (
    select
        c1::varchar c1, c2::varchar c2, c3::varchar c3, c4::varchar c4, c5::varchar c5,
        c6::varchar c6, c7::varchar c7, c8::varchar c8, c9::varchar c9, c10::varchar c10
    from t1
),
data as (
    select column_name, column_value
    from stringified
    unpivot(column_value for column_name in (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10))
)
select
    c.column_name,
    count(d.column_value)/(select count(*) from t1) fill_rate,
    min(d.column_value) min,
    max(d.column_value) max
from cols c
left join data d using (column_name)
group by c.column_name, c.ordinal_position
order by c.ordinal_position
;
/*
COLUMN_NAME FILL_RATE   MIN MAX
C1  0.500000    -1000000069270747870    999999972962694409
C2  0.499980    -1000000027928146782    999999946877079818
C3  0.499996    -1000000012155323098    999999942281548701
C4  0.500017    -1000000056353213091    999999946421698482
C5  0.500015    -1000000015608859996    999999993977648967
C6  0.500003    -1000000007081089270    999999998851014730
C7  0.499987    -100000008605944993 999999968272328033
C8  0.499992    -1000000042470913027    999999977402822725
C9  0.500011    -1000000058928465662    999999969060696774
C10 0.500029    -1000000011306371004    99999996061390938
*/

這是一種簡單的方法,但它仍然需要列出所有列名兩次,並且在列數非常大的情況下有點困難(但我相信它比巨大的 UNION ALL 查詢要好得多)。


另一種解決方案有點棘手,但如果行長度不超過 VARIANT 值限制 (16 MiB),您可以使用OBJECT_CONSTRUCT(*)聚合來取消透視表:

with
cols as (
    select column_name, ordinal_position
    from information_schema.columns
    where table_catalog = current_database()
    and table_schema = current_schema()
    and table_name = 'T1'
),
data as (
    select f.key column_name, f.value::varchar column_value
    from (select object_construct(*) rec from t1) up,
    lateral flatten(up.rec) f
)
select
    c.column_name,
    count(d.column_value)/(select count(*) from t1) fill_rate,
    min(d.column_value) min,
    max(d.column_value) max
from cols c
left join data d using (column_name)
group by c.column_name, c.ordinal_position
order by c.ordinal_position
;

/*
COLUMN_NAME FILL_RATE   MIN MAX
C1  0.500000    -1000000069270747870    999999972962694409
C2  0.499980    -1000000027928146782    999999946877079818
C3  0.499996    -1000000012155323098    999999942281548701
C4  0.500017    -1000000056353213091    999999946421698482
C5  0.500015    -1000000015608859996    999999993977648967
C6  0.500003    -1000000007081089270    999999998851014730
C7  0.499987    -100000008605944993 999999968272328033
C8  0.499992    -1000000042470913027    999999977402822725
C9  0.500011    -1000000058928465662    999999969060696774
C10 0.500029    -1000000011306371004    99999996061390938
*/

OBJECT_CONSTRUCT(*)聚合是OBJECT_CONSTRUCT function 的一種特殊用法,它提取列名作為每個 JSON ZA8CFDE6331BD59EB26666ZC4 的鍵。 據我所知,這是以編程方式從表中提取列名以及值的唯一方法。

由於OBJECT_CONSTRUCT是一個比較繁重的操作,它通常比第一種解決方案需要更長的時間,但是你不需要用這個技巧寫所有的列名。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM