【问题标题】:Query to only to return rows IF all rows have data如果所有行都有数据,则查询仅返回行
【发布时间】:2023-01-19 19:43:51
【问题描述】:

我将如何编写基于下表的查询,以便在表中包含类似#Test1 的数据时查询将返回行。

如果同一个表包含类似#test2 的数据,其中至少 1 行的销售额为 0多于8 ProductTypes 那么查询不应该返回任何东西或者只返回 0

创建和插入脚本:

CREATE TABLE #TEST1
(
    ProductType nvarchar(30),
    Sales int,
    Tax int,
    Discount int

)


INSERT INTO #TEST1 (ProductType, Sales, Tax, Discount)
VALUES
('BIKES',100,1, 2),
('TRUCKS',100,1, 2),
('CARS',100,1, 2),
('SCOOTERS',100,1, 2),
('BOATS',100,1, 2),
('PLANES',100,1, 2),
('TANKS',100,1, 2),
('HELICOPTERS',100,1, 2),
('FOOD',100,1, 2),
('DRINKS',100,1, 2)

CREATE TABLE #TEST2
(
    ProductType nvarchar(30),
    Sales int,
    Tax int,
    Discount int

)

INSERT INTO #TEST2 (ProductType, Sales, Tax, Discount)
VALUES
('BIKES',100,1, 2),
('TRUCKS',100,1, 2),
('CARS',100,1, 2),
('SCOOTERS',100,1, 2),
('BOATS',100,1, 2),
('PLANES',100,1, 2),
('TANKS',100,1, 2),
('HELICOPTERS',0,0,0),
('FOOD',0,0,0),
('DRINKS',0,0,0)


select * from #TEST1
select * from #TEST2

【问题讨论】:

  • 所以,让我直截了当地说,你想回来全部#TEST1 中的行,但是只要如果每一行#TEST1 出现在#TEST2
  • 不应该返回任何东西或者只返回 0- 那是哪一个?目前尚不清楚你在问什么。请显示您对示例数据的期望。
  • 感谢您的回复,如果有 > 8 行并且没有一行的销售额为零,我只想返回所有行。
  • 我的想法是使用 ROW_NUMBER 来计算 CTE 中的行数,然后以某种方式在 where 子句中仅返回 sales > 0 的数据
  • 无论如何,这样的查询都会很昂贵。您需要计算所有行并在检查所有内容后确定 Sales 值。假设没有负销售额,MIN(Sales)=0 会告诉您是否有任何行有 0,COUNT()>8 会检查计数。这些只能出现在 HAVING 子句或 CTE 中

标签: sql tsql


【解决方案1】:

你能看看以下是否不存在标准就是您所期望的

select * 
from #TEST1 t
where not exists (
  select * from #test1 t2
  having Count(distinct ProductType)> 8 
  and sum(case when sales = 0 then 1 end) > 0
);

【讨论】:

    【解决方案2】:

    这完全基于以下评论:

    ,如果有 > 8 行并且没有一行的销售额为零,我只想返回所有行。

    如果这就是您想要的,您可以使用 EXISTS 来对抗 #TEST2COUNT 行数以及在 HAVING 中具有 0 值的行数,并检查值是否为> 8 和 0 分别是:

    SELECT *
    FROM #TEST1 T1
    WHERE EXISTS (SELECT 1
                  FROM #TEST2 T2
                  HAVING COUNT(*) > 8
                    AND COUNT(CASE T2.Sales WHEN 0 THEN 1 END) = 0);
    

    【讨论】:

      【解决方案3】:

      假设 Sales 永远不会为负,您可以找出是否有任何 Sales 值是 0MIN(Sales)

      您可以使用 CTE 计算整个结果集的最小销售额和行数来执行此操作

      ;with x as (
          select *, MIN(Sales) OVER() as MinSales,COUNT(*) OVER() as Cnt
          from #TEST2
      )
      select * from x
      where MinSales>0 AND Cnt<=8
      

      这个可能能够通过单表扫描计算出结果。

      您还可以使用子查询和HAVING,但这将导致两次表扫描。

      select * 
      from #TEST2
      where exists (select 1 from #TEST2 HAVING MIN(Sales)>0 AND COUNT(*)<=8)
      

      这两种情况的执行计划表明,第一种的成本是第二种的一半

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-12-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多