【问题标题】:SQL Server : count() for each group, but only groups having 1+ element like... AND all elements likeSQL Server:每个组的count(),但只有具有1+元素的组...以及所有元素,例如
【发布时间】:2014-10-17 14:53:49
【问题描述】:

有如下表(列):

  • Clients (clientID)
  • Houses (houseID)
  • Visits (clientID, houseID, visit_date)
  • Contracts (contractID, houseID, clientID,rentDate_from,rentDate_end)

我在编写此类 SQL 查询时遇到问题:

  • 每位客户在租用其中一间之前访问了多少次房屋?

很容易计算每个客户的总访问次数,按clientID 列出所有访问+ 组,并为每个组选择count(*)

假设这是 select_1,而 select_2 列出了所有客户的所有合同。

Select_1 不是答案,因为只能对组执行计数,其中:

  • 在 select_2 中至少有 1 行“喜欢”行(这意味着至少有一个已访问的房屋被租用,因为可能发生客户访问的房屋很少,但租用了其他未访问的房屋)。我的想法是将 select_1 和 select_2 与:

    其中 s1.clientID = s2.clientID 和 s1.houseID = s2.houseID

  • 每个组的所有行(访问)的日期必须在同一天或早于合同日期

    也许:datediff(day, s1.visit_date, s2.rentDate_from) >= 0

(为什么这个论坛按回车后有1个空行?)

【问题讨论】:

  • 这听起来更像是您向我们提出要求并要求我们为您编写。到目前为止,您尝试过什么?

标签: sql-server


【解决方案1】:

HAVING 子句用于从聚合查询中过滤组。它类似于WHERE 子句,但适用于聚合结果。在这种特殊情况下,您还想使用本质上相同的查询来形成初始结果行并过滤组;对于 SQL Server,WITH 子句允许您执行该查询一次并重用它。因此,你可能会得到这样的结果:

WITH previousVisits(clientId, houseId_visited, houseId_rented) AS 
  SELECT Visits.clientId, Visits.houseId, Contracts.houseId
    FROM Visits
      JOIN Contracts ON Visits.clientId = Contracts.clientId
    WHERE Visits.visit_date <= Contracts.rentDate_from
SELECT clientId, houseId_rented, COUNT(*) AS visitCount
  FROM previousVisits pv1
  GROUP BY clientId, houseId_rented
  HAVING houseId_rented IN (
    SELECT houseId_visited
      FROM previousVisits pv2
      WHERE
        pv2.clientId = clientId
        AND pv2.houseId_rented = houseId_rented
  )

请注意,在同一客户租用两套不同房屋的情况下,您应该考虑这是否符合您的要求。如所写,对于每所出租的房屋,它将计算在该出租之前访问过的所有房屋。即使这样,如果同一个客户多次租用同一个房子,也会有潜在的问题。

【讨论】:

  • 感谢您的回答和介绍+使用 WITH 的示例。您的查询需要分析和少量更改才能给出正确的结果,我相信这是您有意识的举动;)
【解决方案2】:

我用更简单的命令查询:

选择不同的

co.clientID,
(
 select count(*) from Visits vi
 where vi.clientID = co.clientID  and  vi.visit_date <= co.rentDate_from
)

来自合同公司

co.clientID 在哪里

    (
     select vi.clientID from Visits vi
     where vi.houseID = co.houseID  and  vi.clientID = co.clientID  and
           vi.visit_date <= co.rentDate_from    
    )

J.B.修改后的版本:

WITH previousVisits(clientId, houseId_visited, houseId_rented) AS

-> 选择不同的 Visits.clientId、Visits.houseId、Contracts.houseId

FROM Visits

  JOIN Contracts ON Visits.clientId = Contracts.clientId

WHERE Visits.visit_date <= Contracts.rentDate_from

SELECT clientId, houseId_rented, COUNT(*) AS visitCount

FROM previousVisits pv1

GROUP BY clientId, houseId_rented

HAVING houseId_rented IN (

SELECT houseId_visited

  FROM previousVisits

  WHERE

->clientId = pv.1clientId

-> AND houseId_rented = pv1.houseId_rented

)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-07-30
    • 1970-01-01
    • 2018-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多