【问题标题】:Query to get the customers who haven't transacted in the past two months查询过去两个月没有交易的客户
【发布时间】:2015-06-25 18:20:05
【问题描述】:

我有一些数据格式如下(表名-ORDERS):

╔══════════╦═════════╦═════════════════════════════╗
║ OrderID  ║ CustNum ║ OrderDate                   ║
╟──────────╫─────────╢─────────────────────────────╢
║ 1        ║ 100     ║ 2015-02-05 00:00:00.0000000 ║
║ 2        ║ 101     ║ 2015-03-05 00:00:00.0000000 ║
║ 4        ║ 102     ║ 2015-04-05 00:00:00.0000000 ║
║ 5        ║ 102     ║ 2015-05-05 00:00:00.0000000 ║
║ 6        ║ 102     ║ 2015-06-05 00:00:00.0000000 ║
║ 10       ║ 101     ║ 2015-06-05 00:00:00.0000000 ║
║ 34       ║ 100     ║ 2015-06-05 00:00:00.0000000 ║
╚══════════╩═════════╩═════════════════════════════╝

我有一个customers 表,其中包含以下格式的客户信息:

╔═════════╦══════════╗
║ CustNum ║ CustName ║
╟─────────╫──────────╢
║ 100     ║ ABC      ║
║ 101     ║ DEF      ║
║ 102     ║ GHI      ║
╚═════════╩══════════╝

此数据跨越多年,ORDERS 表本身有 500 万多条记录。我想知道过去两个月没有交易(或下订单)的客户数量。

在上面的示例中,CustNum 100101 在过去两个月内没有交易(如果我们查看 2015 年 6 月),102 在过去两个月内进行过交易(同样,如果我们看的是 2015 年 6 月),所以我希望输出采用以下格式:

Time        NumberOfCustNotPlacingOrders
Apr-2014    1 (CustNum 102, didnt place orders in Feb and Mar)
May-2014    1 (CustNum 100, didnt place orders in Mar and Apr)
Jun-2014    2 (CustNum 100 and 101, didnt place orders in Apr and Mar)

换句话说,我想查看整个月,在这种情况下假设为 2015 年 6 月。我现在想看看 2 个月前(4 月和 5 月)并计算有多少客户 (CustNum) 没有下订单,在这种情况下是 100101我想在所有月份都这样做,比如从 2​​012 年 1 月到 2015 年 6 月。

我会发布我会尝试过的初始查询,但我真的不知道如何实现这一点,所以这对我来说几乎是一张白纸。看起来像self join 可能是为了,但我不完全确定。

任何帮助将不胜感激。

【问题讨论】:

  • 除非您提供一些详细信息,否则这对我们来说也像是一张白纸。这是一个很好的起点。 spaghettidba.com/2015/04/24/…
  • OrderDate 列是日期时间吗?
  • 自联接或 WHERE NOT EXISTS() 子句将是一个很好的起点。
  • 编辑了问题。

标签: sql sql-server


【解决方案1】:

这是第一个解决方案,可以用作工作基础。

CREATE TABLE #orders(OrderId int identity(1,1), CustNum int, Orderdate date)

-- using system columns to populate demo data (I'm lazy)
INSERT INTO #orders(CustNum,Orderdate)
    SELECT system_type_id, DATEADD(month,column_id*-1,GETDATE())
    FROM sys.all_columns

-- Possible Solution 1:
-- Getting all your customers who haven't placed an order in the last 2 months
SELECT *
FROM (
        -- All your customers
        SELECT DISTINCT CustNum
        FROM #orders
        EXCEPT
        -- All customers who have a transaction in the last 2 months
        SELECT DISTINCT CustNum
        FROM #orders
        WHERE Orderdate >= DATEADD(month,-2,GETDATE())
    ) dat

DROP TABLE #orders

基于客户表可用的事实,这也可以是一个解决方案:

CREATE TABLE #orders(OrderId int identity(1,1), CustNum int, Orderdate date)

-- using system columns to populate demo data (I'm lazy)
INSERT INTO #orders(CustNum,Orderdate)
    SELECT system_type_id, DATEADD(month,column_id*-1,GETDATE())
    FROM sys.all_columns

CREATE TABLE #customers(CustNum int)

-- Populate customer table with demo data
INSERT INTO #customers(CustNum)
    SELECT DISTINCT custNum 
    FROM #orders

-- Possible Solution 2:
SELECT 
    COUNT(*) as noTransaction
FROM #customers as c
LEFT JOIN(
        -- All customers who have a transaction in the last 2 months
        SELECT DISTINCT CustNum
        FROM #orders
        WHERE Orderdate >= DATEADD(month,-2,GETDATE())
    ) t
    ON c.CustNum = t.CustNum
WHERE t.CustNum IS NULL

DROP TABLE #orders
DROP TABLE #customers

您将收到过去 2 个月内未购买任何商品的每位客户的计算价值。正如我所读到的,您尝试定期运行此查询(可能是针对特殊时事通讯或类似的东西)。如果您不计算,您将获得可用于进一步处理的客户编号。

滚动月份的解决方案 清除问题后,这应该是您正在寻找的东西。它会根据滚动月份生成输出。

CREATE TABLE #orders(OrderId int identity(1,1), CustNum int, Orderdate date)

-- using system columns to populate demo data (I'm lazy)
INSERT INTO #orders(CustNum,Orderdate)
    SELECT system_type_id, DATEADD(month,column_id*-1,GETDATE())
    FROM sys.all_columns

CREATE TABLE #customers(CustNum int)

-- Populate customer table with demo data
INSERT INTO #customers(CustNum)
    SELECT DISTINCT custNum 
    FROM #orders

-- Possible Solution with rolling months:
-- first of all, get all available months
-- this can be also achieved with an temporary table (which may be better)
-- but in case, that you can't use an procedure, I'm using the CTE this way.
;WITH months AS(
    SELECT DISTINCT DATEPART(month,orderdate) as allMonths, 
                    DATEPART(year,orderdate) as allYears
    FROM #orders
)
SELECT m.allMonths,m.allYears, monthyCustomers.noBuyer
FROM months m
OUTER APPLY(
        SELECT N'01/'+m.allMonths+N'/'+m.allYears as monthString, COUNT(c.CustNum) as noBuyer
        FROM #customers as c
        LEFT JOIN(
                -- All customers who have a transaction in the last 2 months
                SELECT DISTINCT CustNum
                FROM #orders
                -- to get the 01/01/2015 out of 03/2015
                WHERE Orderdate BETWEEN DATEADD(month,-2,
                                            CONVERT(date,N'01/'+CONVERT(nvarchar(max),m.allMonths)
                                            +N'/'+CONVERT(nvarchar(max),m.allYears)))
                                -- to get the 31/03/2015 out of the 03/2015                     
                                AND DATEADD(day,-1,
                                        DATEADD(month,+1,CONVERT(date,N'01/'+
                                            CONVERT(nvarchar(max),m.allMonths)+N'/'+
                                            CONVERT(nvarchar(max),m.allYears))))
                                -- NOTICE: the conversion to nvarchar is needed
                                -- After extracting the dateparts in the CTE, they are INT not DATE
                                -- A explicit conversion from INT to DATE isn't allowed
                                -- This way we cast it to NVARCHAR and convert it afterwards to DATE

            ) t
            ON c.CustNum = t.CustNum
        WHERE t.CustNum IS NULL
            -- optional: Count only users which were present in the counting month.
            AND t.CustRegdate >= CONVERT(date,N'01/'+CONVERT(nvarchar(max),m.allMonths)+N'/'+CONVERT(nvarchar(max),m.allYears))
    ) as monthyCustomers
ORDER BY m.allYears, m.allMonths

DROP TABLE #orders
DROP TABLE #customers

【讨论】:

  • 非常感谢您的帮助,这正是我想要的。
  • 我知道这可能有点冗长,但我们可以只计算在我们计算时注册的客户吗?例如,customers 表中有一个字段名为registerdate。如果客户在 2015 年 4 月 1 日注册,那么我们不应该在 2015 年 4 月之前的所有月份都计算该客户。这​​有意义吗?
  • 是的,这是有道理的,应该是一件容易的事。我认为它应该只是加入时的附加 on 子句。我可以稍后提供,因为我正在回家的路上。 :-)
  • 嗨,昨天晚上没来。我在OUTER APPLY WHERE-clause 中添加了AND-clause。
【解决方案2】:

如果您想要尚未下订单的客户,您将需要一个客户表并使用外连接到订单表。这应该是一个起点,直到您使您的要求更清晰......

http://sqlfiddle.com/#!3/3aeb9/12

select c.CustNum ,odata.omonth from 
Customer c
left outer join
(select o.CustNum,
 REPLACE(RIGHT(CONVERT(VARCHAR(11), o.OrderDate, 106), 8), ' ', '-') 
  as OMONTH
from Orders o
where o.OrderDate between '2015-05-01' and '2015-06-30'
) odata
on c.CustNum = odata.CustNum
where odata.omonth is null;

请注意,您的代码需要比这更复杂...但它应该让您了解如何开始。

【讨论】:

  • 很抱歉没有提出更清晰的问题,我现在已经编辑了。是的,我确实有一个包含客户信息的 customer 表。
【解决方案3】:
   select TOP 2 year(orderdate), month (orderdate),  
   (select count (*) FROM CUTOMER)  - count (distinct custnum) 
    from orders 
   group by  year (orderdate),month (orderdate)
   order by year (ORDERDATE),MONTH (ORDERDATE)

【讨论】:

    【解决方案4】:

    你可以使用:

    select  
      b.mobile_number, max(b.bill_number), max(b.created_on), c.name
    from 
      MasterBill as b, MasterCustomer as c
    WHERE 
      b.created_on < NOW() - INTERVAL 60 DAY 
      and b.mobile_number = c.mobile_number
    group by 
      mobile_number;
    

    【讨论】:

      猜你喜欢
      • 2013-09-16
      • 1970-01-01
      • 2023-03-09
      • 1970-01-01
      • 1970-01-01
      • 2019-04-09
      • 2022-07-07
      • 2020-08-30
      • 2020-12-20
      相关资源
      最近更新 更多