0

我有以下声明:

SELECT
    (CONVERT(VARCHAR(10), f1, 120)) AS ff1,
    CONVERT(VARCHAR(10), f2, 103) AS ff2,
    ...,
    Bonus,
    Malus,
    ClientID,
FROM 
    my_table                        
WHERE
    <my_conditions>
ORDER BY 
    f1 ASC

此选择为每个 ClientID 返回几行。我必须过滤掉所有没有非空 Bonus 或 Malus 行的客户行。

我怎样才能通过仅通过一个语句更改此选择而不复制所有这些选择来做到这一点?

我可以将结果存储在#temp_table 中,然后对数据进行分组并使用分组结果来过滤临时表。-但我应该只用一个语句来做

我可以执行此选择两次 - 一次对其进行分组,然后我可以根据分组结果过滤行。但我不想选择它两次

可能是 CTE(通用表表达式)在此处仅用于执行一次选择并能够使用结果进行分组,然后根据分组结果选择所需的结果。

这个问题有更优雅的解决方案吗?

先感谢您!

只是为了澄清 SQL 应该做什么,我添加了一个示例:

ClientID  Bonus  Malus
1         1      
1                
1                1
2                
2                
3         4      
3                5
3         1      

所以在这种情况下,我不希望出现 ClientID=2 行(它们并不有趣)。结果应该是:

ClientID  Bonus  Malus
1         1      
1                
1                1
3         4      
3                5
3         1      
4

3 回答 3

0
SELECT Bonus,
       Malus,
       ClientID
FROM my_table                        
WHERE ClientID not in 
(
  select ClientID
  from my_table
  group by ClientID
  having count(Bonus) = 0 and count(Malus) = 0
)
于 2013-07-14T12:00:11.833 回答
0

CTE 可以正常工作,但实际上它的内容将被执行两次,因为它们被克隆到所有使用 CTE 的地方。与使用临时表相比,这可能是净性能的赢或输。如果查询非常昂贵,则可能会出现损失。如果它很便宜或者如果返回许多行,则临时表将丢失比较。

哪种解决方案更好?查看执行计划并衡量绩效。

CTE 是更容易、更可维护且冗余更少的替代方案。

于 2013-07-14T12:08:52.873 回答
0

您尚未指定 Bonus 和 Malus 列的数据类型。因此,如果它们是整数(或可以转换为整数),那么下面的查询应该会有所帮助。它为每个 ClientID 计算两列的总和。这些总和对于同一客户的每个明细行都是相同的,因此我们可以在WHERE条件下使用它们。语句SUM() OVER()被称为“窗口函数”,不能在WHERE子句中使用,所以我不得不将你的选择列表与父项包装起来,只是因为语法。

SELECT *
FROM (
    SELECT
        CONVERT(VARCHAR(10), f1, 120) AS ff1,
        CONVERT(VARCHAR(10), f2, 103) AS ff2,
        ...,
        Bonus,
        Malus,
        ClientID,
        SUM(Bonus) OVER (PARTITION BY ClientID) AS ClientBonusTotal,
        SUM(Malus) OVER (PARTITION BY ClientID) AS ClientMalusTotal
    FROM 
        my_table                        
    WHERE
        <my_conditions>
) a
WHERE ISNULL(a.ClientBonusTotal, 0) <> 0 OR ISNULL(a.ClientMalusTotal, 0) <> 0
ORDER BY f1 ASC
于 2013-07-14T15:12:52.890 回答