[英]Count the number of distinct values of each row (SQL)
如何創建一個新列,返回表中每行中不同值的數量? 例如,
ID Description Pay1 Pay2 Pay3 #UniquePays
1 asdf1 10 20 10 2
2 asdf2 0 10 20 3
3 asdf3 100 100 100 1
4 asdf4 0 10 3
查詢可能返回> 1百萬行,因此需要有點效率。 總共有8個'Pay'列,它們是NULL或整數。 另請注意,'0'應與NULL不同。
到目前為止,我能夠完成的最多(我剛剛意識到這一點甚至不准確)是計算每行中支付條目的總數:
nvl(length(length(Pay1)),0)
+nvl(length(length(Pay2)),0)
+nvl(length(length(Pay3)),0) "NumPays"
典型的行只填充了8列中的4列,其余為空,Pay列中的最大整數為'999'(因此長度轉換嘗試...)
我的SQL技能是原始的,但任何幫助表示贊賞!
如果您擁有或可以創建用戶定義的數字表,則可以使用創建集合,使用set
函數去除重復項,然后使用cardinality
函數計算剩余值:
cardinality(set(t_num(pay1, pay2, pay3))) as uniquepays
要包含所有八個列,只需將額外的列名添加到傳遞給tnum()
構造函數的列表中。
cardinality(set(t_num(pay1, pay2, pay3, pay4, pay5, pay6, pay7, pay8))) as uniquepays
將您的樣本表演示為CTE:
create type t_num as table of number
/
with t (ID, Description, Pay1, Pay2, Pay3) as (
select 1, 'asdf1', 10, 20, 10 from dual
union all select 2, 'asdf2', 0, 10, 20 from dual
union all select 3, 'asdf3', 100, 100, 100 from dual
union all select 4, 'asdf4', null, 0, 10 from dual
)
select id, description, pay1, pay2, pay3,
cardinality(set(t_num(pay1, pay2, pay3))) as uniquepays
from t
order by id;
ID DESCR PAY1 PAY2 PAY3 UNIQUEPAYS
---------- ----- ---------- ---------- ---------- ----------
1 asdf1 10 20 10 2
2 asdf2 0 10 20 3
3 asdf3 100 100 100 1
4 asdf4 0 10 3
是否有足夠的效率以及數百萬行需要進行測試。
這是一個相對簡單的方法:
CREATE TYPE number_list AS TABLE OF NUMBER;
with t (ID, Description, Pay1, Pay2, Pay3) as (
select 1, 'asdf1', 10, 20, 10 from dual
union all select 2, 'asdf2', 0, 10, 20 from dual
union all select 3, 'asdf3', 100, 100, 100 from dual
union all select 4, 'asdf4', null, 0, 10 from dual
)
SELECT id,
description,
pay1,
pay2,
pay3,
(SELECT COUNT (DISTINCT NVL (TO_CHAR (COLUMN_VALUE), '#NULL#'))
FROM TABLE (number_list (pay1, pay2, pay3))) uniquepays
FROM t;
ID DESCR PAY1 PAY2 PAY3 UNIQUEPAYS
---------- ----- ---------- ---------- ---------- ----------
1 asdf1 10 20 10 2
2 asdf2 0 10 20 3
3 asdf3 100 100 100 1
4 asdf4 0 10 3
將每個值拆分為它自己的行(就像它應該存儲在第一個位置),然后union
然后up(因為union
丟棄重復項)只計算行數:
select id, description, count(*) unique_pays from (
select id, description, nvl(pay1, -1) from mytable
union select id, description, nvl(pay2, -1) from mytable
union select id, description, nvl(pay3, -1) from mytable
union select id, description, nvl(pay4, -1) from mytable
union select id, description, nvl(pay5, -1) from mytable
union select id, description, nvl(pay6, -1) from mytable
union select id, description, nvl(pay7, -1) from mytable
union select id, description, nvl(pay8, -1) from mytable
) x
group by id, description
我將空值更改為-1,這樣他們就可以干凈利落地參與重復數據刪除。
這是一個只讀取基表一次的解決方案,並利用已經按行組織的數據。 (不信任將是低效的,因為這些信息會丟失,導致大量的額外工作。)
它假設所有NULL
都被計為相同。 如果相反它們應該被認為彼此不同,則將nvl
的-1
更改為不同的值: -1
表示Pay1
, -2
表示Pay2
,等等。
with
inputs( ID, Description, Pay1, Pay2, Pay3 ) as (
select 1, 'asdf1', 10, 20, 10 from dual union all
select 2, 'asdf2', 0, 10, 20 from dual union all
select 3, 'asdf3', 100, 100, 100 from dual union all
select 4, 'asdf4', cast(null as number), 0, 10 from dual
)
-- End of TEST data (not part of solution!) SQL query begins BELOW THIS LINE.
select id, description, pay1, pay2, pay3,
1
+ case when nvl(pay2, -1) not in (nvl(pay1, -1))
then 1 else 0 end
+ case when nvl(pay3, -1) not in (nvl(pay1, -1), nvl(pay2, -1))
then 1 else 0 end
as distinct_pays
from inputs
order by id -- if needed
;
ID DESCRIPTION PAY1 PAY2 PAY3 DISTINCT_PAYS
-- ------------ ------- ------- ------- -------------
1 asdf1 10 20 10 2
2 asdf2 0 10 20 3
3 asdf3 100 100 100 1
4 asdf4 0 10 3
4 rows selected.
解決方案是:
#uniquePays
初始表開始。 由此
ID Description Pay1 Pay2 Pay3
1 asdf1 10 20 10
這個:
ID seq Description Pay
1 1 asdf1 10
1 2 asdf1 20
1 3 asdf1 10
這樣做,還是需要示例腳本? 我最近發布了很多關於旋轉和非旋轉的內容....似乎是一個受歡迎的需求: - ]
Marco the Sane
您可以編寫插入觸發器或存儲過程來計算每個插入語句的唯一值的總數,並在唯一列中進行更新。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.