确定在任何行中都具有值的列

时间:2018-10-25 13:16:19

标签: sql-server

我有一张桌子,上面有1400万条记录。对于给定的集合(即:其中PartId = 13),我希望形成一个在所有记录中值都大于0的所有列的列表。此查询有60个感兴趣的列。请注意,这些列是可为空的。

是否有比以下方法更快的方法?

select
        -- this sample uses 3 columns, but my actual table does this same thing
        -- for 60 columns

        stuff( -- remove the leading space and comma
            case when 0 = max(isnull(col_1, 0)) then '' else ', col_1' end + 
            case when 0 = max(isnull(col_2, 0)) then '' else ', col_2' end + 
            case when 0 = max(isnull(col_3, 0)) then '' else ', col_3' end,
            1, 2, ''
        )
from    Applications
where   PartId = 13

此查询返回的正是我想要的。对于给定的具有80万条分组记录的部分,此SQL在我的计算机上运行的时间不到5秒,这我认为还不错。

其结果将是在select语句中使用的列列表(业务逻辑表明,每一行将至少具有1个列,其值大于0)。

我尝试使用EXISTS进行包含60个子查询的查询,但这要慢得多。

我也尝试了SUM:

case when 0 = (sum(case when isnull(col_1, 0) > 0 then 1 else 0 end)) then '' else ', col_1' end +
case when 0 = (sum(case when isnull(col_2, 0) > 0 then 1 else 0 end)) then '' else ', col_2' end

与上面的最大变化速度大致相同。

进行查询的原因是,客户需要一份报告,其中我们仅显示在每个零件的任何行中都有值的列。我正在使用jqGrid显示数据(并允许XLSX下载)。使用jqGrid时,我不想逐页删除空列,因为这意味着并非所有页面都具有相同的列;这意味着排序/过滤的可能性会逐页变化。

编辑1

尽管我认为我可以通过以下方式摆脱ISNULL:

case when max(col_1) > 0 then ', col_1' else '' end

2 个答案:

答案 0 :(得分:1)

“可能”更具可读性和可管理性的一个选项是取消数据透视表,以便您不必检查60列,而只需检查1列。 如果您的检查列逻辑更为复杂,因为这样可以避免重复60次,那么这样做会更有用。

您会在选择的内容中添加一个“交叉应用”

CROSS APPLY (VALUES ('col_1', col_1), 
                    ('col_2', col_2) 
                    etc
             ) unpiv (col_name, col_val) 

然后的想法是,您可以编写一次支票,并将其应用于所有相关列。 在您的情况下,这将是一个简单的where子句

WHERE col_val > 0

答案 1 :(得分:0)

您在第一个代码段中完成此操作的方式恰好就是我要做的方式。