簡體   English   中英

計算每行的不同值的數量(SQL)

[英]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.

解決方案是:

  1. 從沒有列#uniquePays初始表開始。
  2. 打開你的桌子。

由此

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
  1. 從unpivoted表中,運行SELECT COUNT(DISTINCT Pay)
  2. 重新調整表格,添加COUNT(DISTINCT Pay)。

這樣做,還是需要示例腳本? 我最近發布了很多關於旋轉和非旋轉的內容....似乎是一個受歡迎的需求: - ]

Marco the Sane

您可以編寫插入觸發器存儲過程來計算每個插入語句的唯一值的總數,並在唯一列中進行更新。

暫無
暫無

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

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