SQL查询根据填充的列数返回记录

时间:2015-04-30 08:38:54

标签: sql oracle

我有一个项目表。商品ID存储在ITEM列中。所有项目都有不同的变体,名为"80""85""90""95""100""105""110""115"(也是现有列)。如果某个项目具有特殊类型的变体,则该列(由变体类型命名)将填充数字。

我想只选择那些至少有4个变种的项目(4个变量列填充数字)。

ITEM    80    85    90    95    100    105    110    115
 A      1                        1                    3    <-- 3 variants
 B      2                        1                    3    <-- 3 variants
 C                        1                           3    <-- 2 variants
 D            1                                       3    <-- 2 variants
 E      1                 1                     1     1    <-- 4 variants

在此示例中,项目E 将是唯一选择的项目,因为它有4个变体。

create table itemtest (
    item varchar2(30 char),
    "80" integer,
    "85" integer,
    "90" integer,
    "95" integer,
    "100" integer,
    "105" integer,
    "110" integer,
    "115" integer
);

insert into itemtest values ('A', 1, null, null, null, 1, null, null, 3);

insert into itemtest values ('B', 2, null, null, null, 1, null, null, 3);

insert into itemtest values ('C', null, null, null, 1, null, null, null, 3);

insert into itemtest values ('D', null, 1, null, null, null, null, null, 3);

insert into itemtest values ('E', 1, null, null, 1, null, null, 1, 1);

commit;

3 个答案:

答案 0 :(得分:2)

避免输入繁琐的CASE表达式。使用Oracle的低估NVL2()功能!

select itemtest.*
from itemtest
where NVL2("80" , 1, 0) + NVL2("85" , 1, 0) + 
      NVL2("90" , 1, 0) + NVL2("95" , 1, 0) + 
      NVL2("100", 1, 0) + NVL2("105", 1, 0) + 
      NVL2("110", 1, 0) + NVL2("115", 1, 0) >= 4;

来自文档:

NVL2(expr1, expr2, expr3)
     

NVL2允许您根据指定的表达式是null还是非null来确定查询返回的值。如果expr1不为null,则NVL2返回expr2。如果expr1为null,则NVL2返回expr3。

奖金。用美丽的UNPIVOT条款

给你的同事留下深刻印象(或烦恼)

我不知道为什么我之前没有想到它。实际上,为了对它们进行计数,您实际上是在对列进行非活动。方法如下:

SELECT item, COUNT(*)
FROM itemtest
UNPIVOT (
  variants FOR code IN ("80", "85", "90", "95", "100", "105", "110", "115")
)
GROUP BY item
HAVING COUNT(*) >= 4
ORDER BY item

这将产生

ITEM  COUNT(*)
--------------
E            4

如何运作?

这是一个简单的UNPIVOT语句,没有分组和聚合:

SELECT *
FROM itemtest
UNPIVOT (
  variants FOR code IN ("80", "85", "90", "95", "100", "105", "110", "115")
)

哪个收益......

ITEM  CODE  VARIANTS
--------------------
A     80    1       
A     100   1       
A     115   3       
B     80    2       
B     100   1       
B     115   3       
C     95    1       
C     115   3       
D     85    1       
D     115   3       
E     80    1       
E     95    1       
E     110   1       
E     115   1       

其余的(GROUP BYHAVING)只是普通的SQL。

答案 1 :(得分:0)

只需计算它们并在大于或等于4时选择

select *
from itemtest 
where
   CASE WHEN "80" IS NOT NULL THEN 1 ELSE 0 END +
   CASE WHEN "85" IS NOT NULL THEN 1 ELSE 0 END +
   CASE WHEN "90" IS NOT NULL THEN 1 ELSE 0 END +
   CASE WHEN "95" IS NOT NULL THEN 1 ELSE 0 END +
   CASE WHEN "100" IS NOT NULL THEN 1 ELSE 0 END +
   CASE WHEN "105" IS NOT NULL THEN 1 ELSE 0 END +
   CASE WHEN "110" IS NOT NULL THEN 1 ELSE 0 END +
   CASE WHEN "115" IS NOT NULL THEN 1 ELSE 0 END >= 4

答案 2 :(得分:0)

如果要根据变体数返回行,可以使用CASE语句检查填充的列数:

select
    i.item
from
    (
    select
        item,
            case when "80"  is not null then 1 else 0 end +
            case when "85"  is not null then 1 else 0 end +
            case when "90"  is not null then 1 else 0 end +
            case when "95"  is not null then 1 else 0 end +
            case when "100" is not null then 1 else 0 end +
            case when "105" is not null then 1 else 0 end +
            case when "110" is not null then 1 else 0 end +
            case when "115" is not null then 1 else 0 end num_variants
    from
        itemtest
    ) i
where
    num_variants >= 4;

您可能仍然坚持设计,但如果可能的变体保存在单独的ITEM_VARIANT表中会更容易:

 ITEM  VARIANT_CODE  VARIANT_VALUE
 ----  ------------  -------------
  A        80            1
  A       100            1
  A       115            3
  B        80            2
  ...
  ...
  ...
  E       115            1

然后你有一个很好的直截了当的查询 - 例如以下内容:

select
    item
from
    (
    select
        item,
        count(*) num_variants
    from
        item_variant
    group by
        item
    )
where
    num_variants >= 4;