【问题标题】:How to use LEAD function with condition?如何在有条件的情况下使用 LEAD 功能?
【发布时间】:2018-12-20 22:10:50
【问题描述】:

我正在使用我的查询来拉回一个客户在多天购买东西的实例。我有兴趣只撤回客户在不同日期购买相同商品的行。

我的查询如下所示:

FROM (
   SELECT *,ROW_NUMBER() OVER(Partition by ordernumber,onlydate ORDER BY ordernumber  ) as ROW_Number2 
   FROM 
          (
          SELECT
                 Firstname
                 ,lastname
                 ,customerid
                 ,orderdate
                 ,ordernumber
                 ,producttype
                 ,
                     convert(date, orderdate) as onlydate,
             convert(time (0), orderdate)as onlytime
                 FROM sales a (nolock) 
                 JOIN product p(nolock)
                 ON a.customerid = p.customerid
                 WHERE orderdate BETWEEN '07/01/2018' AND '09/01/2018'

         )                   
          )as A
                       ) AS B
                       WHERE B.ROW_Number2=1 

它会拉回客户在不同日期购买东西的实例,但有时它会显示客户正在购买不同的物品。我想我需要在 producttype 上使用带有参数的 LEAD 函数,但不确定如何将其插入到此查询中。

我们将不胜感激!

示例数据:

firstname    lastname     customerid   b.department  orderdate   producttype 
---------    ---------    ---------     ---------    ---------    ---------
 alice        johnson       1            athletic      12/7/17     shoes
 alice        johnson       1            athletic      12/8/18     headband
 john         parker        2            toiletries    12/9/18     cleaning
 john         parker        2            toiletries    12/10/18    personal
 john         parker        2            toiletries    12/10/18    cleaning

所需数据:

 firstname    lastname     customerid   b.department  orderdate  producttype 
---------    ---------    ---------     ---------    ---------    ---------
 john         parker        2            toiletries    12/9/18     cleaning
 john         parker        2            toiletries    12/10/18    cleaning

希望它只显示约翰购买清洁的实例

【问题讨论】:

  • 你最好展示一些示例数据和预期结果
  • 已添加 - 感谢您的意见!

标签: sql sql-server tsql lead


【解决方案1】:

嗯。 . .

select t.*
from (select t.*,
             lag(orderdate) over (partition by customerid, department, producttype order by orderdate) as prev_orderdate,
             lead(orderdate) over (partition by customerid, department, producttype order by orderdate) as lead_orderdate
      from t
     ) t
where orderdate = dateadd(day, 1, prev_orderdate) or
      orderdate = dateadd(day, -1, next_orderdate) ;

这确实假设在同一天没有多次购买,尽管这可以用更多的逻辑来处理。

【讨论】:

  • 嘿!感谢您的回答。因此,使用行号分区构建查询的原因是因为我们在同一天看到了多次购买,这肯定会扭曲我们的数据。
【解决方案2】:
WITH cte AS
 ( -- your base query
   SELECT 
        Firstname
        ,lastname
        ,customerid
        ,ordernumber
        ,department
        ,producttype
        ,convert(DATE, orderdate) AS onlydate
        ,convert(time (0), orderdate)as onlytime
   FROM sales a (nolock) 
   JOIN Product p(nolock)
   ON a.customerid = p.customerid
   WHERE orderdate BETWEEN '07/01/2018' AND '09/01/2018'
 )
,MinMaxDate AS
 ( -- adding MIN/MAX
   SELECT *
      ,MIN(onlydate) Over (PARTITION BY customerid, producttype) AS MinDate
      ,MAX(onlydate) Over (PARTITION BY customerid, producttype) AS MaxDate
   FROM UniqueDates
 )
SELECT * 
FROM TypeCount
WHERE MinDate <> MaxDate -- same product purchased on at least two days

【讨论】:

    【解决方案3】:

    可玩的示例数据:

    DECLARE @Data TABLE (firstname NVARCHAR(255), lastname NVARCHAR(255), customerid INT, [b.department] NVARCHAR(255), orderdate DATE, producttype NVARCHAR(255));
    INSERT INTO @Data (firstname,lastname,customerid,[b.department],orderdate,producttype) VALUES 
         ('alice','johnson',1,'athletic','2017-07-12','shoes')
        ,('alice','johnson',1,'athletic','2018-08-12','headband')
        ,('john','parker',2,'toiletries','2018-09-12','cleaning')
        ,('john','parker',2,'toiletries','2018-10-12','personal')
        ,('john','parker',2,'toiletries','2018-10-12','cleaning')
    ;
    

    查询:

    SELECT a.*
    FROM (SELECT COUNT(*)OVER(PARTITION BY d.customerid,d.producttype) AS [CountSameThingsDifferentDays],d.* FROM @Data d) a
    WHERE a.CountSameThingsDifferentDays > 1
    ;
    

    【讨论】:

      【解决方案4】:

      也许我遗漏了一些东西,但我认为不需要窗口函数。为什么不直接使用 EXISTS 或 CROSS APPLY:

      -- prep data
      SELECT * 
      into #t
      FROM (values 
          ('alice' ,    'johnson',       1        ,'athletic',   '12/7/17' ,   'shoes'      ),
          ('alice' ,    'johnson',       1        ,'athletic',   '12/8/18' ,   'headband'),
          ('john'  ,    'parker' ,       2        ,'toiletries', '12/9/18' ,   'cleaning'),
          ('john'  ,    'parker' ,       2        ,'toiletries', '12/10/18',   'personal'),
          ('john'  ,    'parker' ,       2        ,'toiletries', '12/10/18',   'cleaning')
      )t(firstname    ,lastname     ,customerid   ,department  ,orderdate   ,producttype )
      
      
      -- output using EXISTS
      SELECT 
           t.firstname    
          ,t.lastname     
          ,t.customerid   
          ,t.department  
          ,t.orderdate   
          ,t.producttype 
      FROM #t t
      where exists (
          SELECT * 
          FROM #t it
          where 
              it.customerid = t.customerid
          and it.producttype = t.producttype
          and it.orderdate <> t.orderdate
      )
      
      
      -- output using a CROSS APPLY
      SELECT 
           t.firstname    
          ,t.lastname     
          ,t.customerid   
          ,t.department  
          ,t.orderdate   
          ,t.producttype 
      FROM #t t
      cross apply (
          SELECT *
          FROM #t it 
          where 
              it.customerid = t.customerid
          and it.producttype = t.producttype
          and it.orderdate <> t.orderdate
      ) ct
      

      【讨论】:

        【解决方案5】:

        根据您的描述,您向我们提供了一张桌子,而在您的原始表格中,您有两张桌子。我无法清楚地理解你的逻辑。请向我们展示您如何处理原始数据。

        据我了解,您可能不会使用 Lead() 来获取您的要求,而只会添加一些条件。

        描述更多?

         -----prep data
        SELECT * 
        into #t
        FROM (values 
            ('alice' ,    'johnson',       1        ,'athletic',   '12/7/17' ,   'shoes'      ),
            ('alice' ,    'johnson',       1        ,'athletic',   '12/8/18' ,   'headband'),
            ('john'  ,    'parker' ,       2        ,'toiletries', '12/9/18' ,   'cleaning'),
            ('john'  ,    'parker' ,       2        ,'toiletries', '12/10/18',   'personal'),
            ('john'  ,    'parker' ,       2        ,'toiletries', '12/10/18',   'cleaning')
        )t(firstname    ,lastname     ,customerid   ,department  ,orderdate   ,producttype )
        
        select * from #t where firstname='john' and producttype='cleaning'
        /*
        firstname lastname customerid  department orderdate producttype
        --------- -------- ----------- ---------- --------- -----------
        john      parker   2           toiletries 12/9/18   cleaning
        john      parker   2           toiletries 12/10/18  cleaning
        */
        

        最好的问候

        雷切尔

        【讨论】:

          猜你喜欢
          • 2023-01-24
          • 2020-07-18
          • 1970-01-01
          • 1970-01-01
          • 2018-11-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多