我有一张桌子,上面有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
答案 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)
您在第一个代码段中完成此操作的方式恰好就是我要做的方式。