计算每行的不同值的数量(SQL)

时间:2017-01-27 18:00:37

标签: sql oracle distinct

如何创建一个新列,返回表格中每行中不同值的数量?例如,

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技能很原始,但感谢任何帮助!

6 个答案:

答案 0 :(得分:4)

如果您拥有或可以创建用户定义的数字表,您可以使用创建集合,使用the set function删除重复项,然后使用the cardinality function计算剩余数量值:

SELECT DISTINCT ID_Num
FROM t
WHERE ID_Num NOT IN
(SELECT ID_Num
 FROM t
 WHERE code = 'C'
 OR code = 'D')

要包含所有八个列,只需将额外的列名添加到传递给cardinality(set(t_num(pay1, pay2, pay3))) as uniquepays 构造函数的列表中。

tnum()

将您的样本表演示为CTE:

cardinality(set(t_num(pay1, pay2, pay3, pay4, pay5, pay6, pay7, pay8))) as uniquepays

这是否足够有效,需要测试数百万行。

答案 1 :(得分:2)

这是一种相对简单的方法:

viewControllers

答案 2 :(得分:1)

将每个值拆分为自己的行(就像它应该存储在第一位),然后union然后向上和(因为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,这样他们就可以干净地参与重复数据删除。

答案 3 :(得分:1)

这是一个只读取基表一次的解决方案,并利用已经按行组织的数据。 (不信任将是低效的,因为这些信息将丢失,导致大量的额外工作。)

它假设所有NULL被计为相同。如果相反它们应被视为彼此不同,请将-1中的nvl更改为不同的值:-1Pay1-2Pay2等等。

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.

答案 4 :(得分:0)

解决方案是:

  1. 从没有列#uniquePays
  2. 的初始表开始
  3. 解开你的桌子。
  4. 从此

    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. 从不透明的表中,运行SELECT COUNT(DISTINCT Pay)
    2. 重新调整表格,添加COUNT(DISTINCT Pay)。
    3. 这样做,还是需要示例脚本?我最近发布了很多关于旋转和非旋转的内容....似乎是一个受欢迎的需求: - ]

      Marco the Sane

答案 5 :(得分:-1)

您可以在插入触发器存储过程上编写,以计算每个插入语句的唯一值总数,并在唯一列中进行更新。