【问题标题】:Sql Statement to get customer who didn't place any order monthly (with month also showed)Sql 语句获取每月未下订单的客户(同时显示月份)
【发布时间】:2021-01-27 14:31:23
【问题描述】:

我有一个客户表和一个订单表 在这种情况下,我想要一份关于有多少客户没有下订单的月度报告 像这样 月 非活跃客户数

我写了一个这样的查询:

SELECT     Count (distinct Persons.id), Month (Orders.OrderDate)
FROM       Persons
LEFT JOIN  Orders ON Persons.id = Orders.Person_id
WHERE      Orders.Person_id IS NULL;
Group By   Month (Orders.OrderDate)

由于条件IS NULL,那么Month(OrderDate)的结果也是NULL 我应该如何让月份也显示? 我正在使用 tsql

【问题讨论】:

  • 您需要先将CROSS JOIN 添加到日历表中,或者首先将所有相关月份的开始和结束日期的不同列表包含在ON 中到您的Orders 表中。跨度>
  • @Larnu 您好,谢谢您的回复,我正在使用 tsql,可能无法进行交叉连接或者?
  • cross join 在 t-sql 中被支持
  • “可能无法进行交叉连接或” 为什么不呢? CROSS JOIN 在您的 Persons 和 Calendar 对象之间,然后 LEFT JOIN 到您的 Orders 表。
  • 你有什么尝试吗?

标签: sql sql-server tsql datetime count


【解决方案1】:

如果您在表orders 中每月至少有一个订单,那么您可以cross join 具有不同月份的人,并过滤具有not exists 条件的非活动客户:

select d.ordermonth, count(*) no_inactive_clients
from persons p
cross join (select distinct datefromparts(year(orderdate), month(orderdate), 1) ordermonth from orders) d
where not exists (
    select 1 
    from orders o 
    where 
        o.orderdate >= d.ordermonth 
        and o.orderdate < dateadd(month, 1 d.ordermonth)
        and o.person_id = p.id
)
group by d.ordermonth

如果有几个月没有任何顺序,但它们不会显示在结果集中。在这种情况下,您需要一个日历表;您可以永久存储它,或者使用递归 CTE 或计数生成它。

【讨论】:

  • 如果我将 where 条件 o.orderdate &gt;= d.ordermonth and o.orderdate &lt; dateadd(month, 1 d.ordermonth) 替换为 o.orderdate=d.ordermonth 会有什么不同?我已将所选时间段内的所有订单保存在一个临时表中,因此在#orders 中只有某些月份我想要的订单
  • @Olivia:d.dt 是当月的第一天,所以您要搜索当月内的订单,而不仅仅是当月的第一天。
【解决方案2】:

生成日期列表。一种方法是生成列表的递归 CTE。然后统计总人数,减去未下单的人数:

with dates as (
      select convert(date, '2019-01-01') as dte
      union all
      select dateadd(month, 1, dte)
      from dates
      where dte < getdate()
     )
select d.dte, p.total - count(distinct o.personid)
from dates d left join
     orders o
     on o.orderdate >= d.dte and
        o.orderdate < dateadd(month, 1, d.dte) cross join
     (select count(*) as total from person) p
group by d.dte
order by d.dte;

实际上,如果有人每月下订单,则不需要CTE:

select datefromparts(year(o.orderdate), month(o.orderdate), 1) as yyyymm,
       p.total - count(distinct o.person_id)
from orders o cross join
     (select count(*) as total from person) p
group by datefromparts(year(o.orderdate), month(o.orderdate), 1), p.total
order by min(orderdate);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-21
    相关资源
    最近更新 更多