【问题标题】:SQL filter rows based without using Group by基于 SQL 过滤行而不使用 Group by
【发布时间】:2017-10-24 20:38:04
【问题描述】:

我有一个查询,它将对 6 个表执行连接,并根据条件获取各种列。我想添加一个额外的过滤条件,它只会给我那些拥有count(distinct dateCaptured)>30 的成员。我可以使用Group byhaving 获得满足此条件的成员列表。但由于这一情况,我不想按其他列名分组。在这种情况下我需要使用PARTITION BY吗?

示例表 a

+-----+------------+--------------+
| Id  | Identifier | DateCaptured |
+-----+------------+--------------+
| 1   |      05548 | 2017-09-01   |
| 2   |      05548 | 2017-09-01   |
| 3   |      05548 | 2017-09-01   |
| 4   |      05548 | 2017-09-02   |
| 5   |      05548 | 2017-09-03   |
| 6   |      05548 | 2017-09-04   |
| 7   |      37348 | 2017-08-15   |
| 8   |      37348 | 2017-08-15   |
| .   |            |              |
| .   |            |              |
| .   |            |              |
| 54  |      37348 | 2017-10-15   |
+-----+------------+--------------+

查询

SELECT  a.value,
        b.value, c.value,
        d.value
        FROM Table a
    INNER JOIN Table b on a.Id=b.id
    INNER JOIN Table c on a.Id=c.Id and s.Invalid=0
    INNER JOIN Table d on a.Id=d.Id 

假设表 a 有超过 30 条标识符 37348 的记录。我怎样才能只获得上述查询的这个标识符。

这些是我对上述 SELECT 感兴趣的患者。

SELECT  a.Identifier,count(DISTINCT DateCaptured)
    FROM Table a
    INNER JOIN Table b on a.Id=b.id
    INNER JOIN Table c on a.Id=c.Id and s.Invalid=0
    INNER JOIN Table d on a.Id=d.Id 
    GROUP BY Identifier
    HAVING count(DISTINCT DateCaptured)>30

【问题讨论】:

  • ....这取决于您希望输出的外观以及您从什么条件开始。您当然可以只对具有DateCaptured 的任何表进行聚合,但不清楚是否还需要首先减少计数行(即,还必须在其他表中具有引用)。如果除了计数之外,您还显示每个日期,则窗口计数主要有用。
  • 您使用的是什么版本的 SQL Server?
  • @Clockwork-Muse 与第一个查询相同的输出。 count(distinct dateCaptured)>30 只是一个过滤条件,它只考虑那些有超过 30 个不同日期的Identifier
  • @Sparrow 2008 R2

标签: sql sql-server group-by partition-by


【解决方案1】:
WITH cte as (
    SELECT  a.Identifier
    FROM Table a
    INNER JOIN Table b on a.Id=b.id
    INNER JOIN Table c on a.Id=c.Id and s.Invalid=0
    INNER JOIN Table d on a.Id=d.Id 
    GROUP BY Identifier
    HAVING count(DISTINCT DateCaptured) > 30
)
SELECT  a.value,
        b.value, c.value,
        d.value
FROM Table a
INNER JOIN Table b on a.Id=b.id
INNER JOIN Table c on a.Id=c.Id and s.Invalid=0
INNER JOIN Table d on a.Id=d.Id 
INNER JOIN cte on cte.Identifier = a.Identifier

【讨论】:

    【解决方案2】:
    SELECT  a.value,
            b.value, c.value,
            d.value
            FROM Table a
        INNER JOIN Table b on a.Id=b.id
        INNER JOIN Table c on a.Id=c.Id and s.Invalid=0
        INNER JOIN Table d on a.Id=d.Id 
    WHERE a.Identifier IN (SELECT  a1.Identifier  
        FROM Table a1
        GROUP BY a1.Identifier HAVING count(DISTINCT a1.DateCaptured)>30)
    

    【讨论】:

    • 看起来像获取所需患者的 OP 查询过于复杂。 +1
    【解决方案3】:

    如果多行确实在tableA,那么你可以这样做:

    SELECT a.value, b.value, c.value, d.value
    FROM (SELECT a.*, COUNT(*) OVER (PARTITION BY id) as cnt
          FROM a
         ) a INNER JOIN
         b 
         ON a.Id = b.id INNER JOIN 
         c 
         ON a.Id = c.Id AND s.Invalid = 0 INNER JOIN 
         d 
         ON a.Id = d.Id
    WHERE a.cnt > 30;
    

    注意:如果您仍然需要count(distinct),您可以这样做:

    SELECT a.value, b.value, c.value, d.value
    FROM (SELECT a.*, SUM(CASE WHEN seqnum = 1 THEN 1 ELSE 0 END) OVER (PARTITION BY id) as cnt
          FROM (SELECT a.*, ROW_NUMBER() OVER (PARTITION BY id ORDER BY DateCaptured) as seqnum
                FROM a
               ) a
         ) a INNER JOIN
         b 
         ON a.Id = b.id INNER JOIN 
         c 
         ON a.Id = c.Id AND s.Invalid = 0 INNER JOIN 
         d 
         ON a.Id = d.Id
    WHERE a.cnt > 30;
    

    【讨论】:

      猜你喜欢
      • 2023-03-12
      • 1970-01-01
      • 2013-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-07
      • 1970-01-01
      相关资源
      最近更新 更多