sql窗口在给定条件下持久保存记录

时间:2017-08-24 22:04:27

标签: sql windowing

我在一个网站上有一些数据,网站上有不同的商店部分但是当用户最后结账时,我们只通过寻找他们最近的部分内容来了解​​它的商店部分

例如,如果我的数据看起来像

session, hit_number, page
a,1,homepage
a,2,generic_page
a,3,shoe_store,
a,4,buy_add_basket
a,5,buy_checkout
b,1,sock_store
b,2,shoe_store,
b,3,buy_add_to_basket
b,4,buy_checkout
c,1,homepage
c,2,sock_store
c,3,sock_store
c,4,buy_add_to_basket
c,5,home_page
c,6,shoe_store
a,5,home_page

我想坚持他们去的最后一家商店(存在的地方,只有当他们在网页的购买部分时(即网页名称以“购买”开头)

我期待的输出是:

session, hit_number, page
a,1,homepage,null
a,2,generic_page,null
a,3,shoe_store,null
a,4,buy_add_basket,shoe_store
a,5,buy_checkout,shoe_store
b,1,sock_store,null
b,2,shoe_store,null
b,3,buy_add_to_basket,shoe_store
b,4,buy_checkout,shoe_store
c,1,homepage,null
c,2,sock_store,null
c,3,sock_store,null
c,4,buy_add_to_basket,sock_store,
c,5,home_page,null
c,6,shoe_store,null
a,5,home_page,null

3 个答案:

答案 0 :(得分:3)

我在SQL Server中执行了此操作,但获取结果的查询在大多数供应商中都有效。其背后的逻辑是检查page列何时包含'buy'然后获取min值,即上面的页面名称包含'store'

的值

创建并填充表格:

DECLARE @table TABLE
(
    session    VARCHAR(1),
    hit_number INT,
    page       VARCHAR(50)
);
INSERT INTO @table VALUES 
('a',1,'homepage'),
('a',2,'generic_page'),
('a',3,'shoe_store'),
('a',4,'buy_add_basket'),
('a',5,'buy_checkout'),
('b',1,'sock_store'),
('b',2,'shoe_store'),
('b',3,'buy_add_to_basket'),
('b',4,'buy_checkout'),
('c',1,'homepage'),
('c',2,'sock_store'),
('c',3,'sock_store'),
('c',4,'buy_add_to_basket'),
('c',5,'home_page'),
('c',6,'shoe_store'),
('a',5,'home_page');

Select * From @table会得到以下结果:

session hit_number  page
a       1           homepage
a       2           generic_page
a       3           shoe_store
a       4           buy_add_basket
a       5           buy_checkout
b       1           sock_store
b       2           shoe_store
b       3           buy_add_to_basket
b       4           buy_checkout
c       1           homepage
c       2           sock_store
c       3           sock_store
c       4           buy_add_to_basket
c       5           home_page
c       6           shoe_store
a       5           home_page

查询:

SELECT
    session,
    hit_number,
    page,
    CASE
        WHEN page LIKE 'buy%'
        THEN MIN(CASE
                     WHEN page LIKE '%store'
                     THEN page
                     ELSE NULL
                 END) OVER(PARTITION BY session ORDER BY hit_number)
        ELSE NULL
    END AS previous_buy_page
FROM @table;

返回所需的结果:

session hit_number  page                previous_buy_page
a       1           homepage            NULL
a       2           generic_page        NULL
a       3           shoe_store          NULL
a       4           buy_add_basket      shoe_store
a       5           buy_checkout        shoe_store
a       5           home_page           NULL
b       1           sock_store          NULL
b       2           shoe_store          NULL
b       3           buy_add_to_basket   shoe_store
b       4           buy_checkout        shoe_store
c       1           homepage            NULL
c       2           sock_store          NULL
c       3           sock_store          NULL
c       4           buy_add_to_basket   sock_store
c       5           home_page           NULL
c       6           shoe_store          NULL

答案 1 :(得分:2)

如果您的架构如下:

create table weblog
(session varchar(10)
,hit_number int
,page varchar(30)
);

INSERT INTO weblog VALUES 
('a',1,'homepage')
,('a',2,'generic_page')
,('a',3,'shoe_store')
,('a',4,'buy_add_basket')
,('a',5,'buy_checkout')
,('b',1,'sock_store')
,('b',2,'shoe_store')
,('b',3,'buy_add_to_basket')
,('b',4,'buy_checkout')
,('c',1,'homepage')
,('c',2,'sock_store')
,('c',3,'sock_store')
,('c',4,'buy_add_to_basket')
,('c',5,'home_page')
,('c',6,'shoe_store')
,('a',5,'home_page');

然后你想要一个SELECT语句,如:

SELECT "session"
, hit_number
, page
, CASE 
  WHEN page like 'buy%' THEN 
  max(CASE 
        WHEN page like '%store' THEN page 
        ELSE NULL
      END) OVER (PARTITION BY session ORDER BY hit_number)
  ELSE NULL
  END as last_store
FROM weblog;

(这是postgres 9.6,你使用的是哪个数据库?)

顺便说一句,我同意@ SteveKline的评论,这似乎不是正确的方法。

答案 2 :(得分:1)

根据我的理解,“最后访问过的商店页面”应该是持久的,直到访问另一个页面或会话结束。我是在后端做这种操作的朋友。围绕add opeartion的触发器或存储过程应该能够做到。特别是添加触发器可能有效。但是您可以使用并且理想的选项在很大程度上取决于您使用的DBMS(并非所有选项都支持相同,并且性能也可能大不相同)。

我个人会在会话中坚持“访问过的最后一个商店”并将其添加到所有插页中。我认为所显示的表上的2个触发器可以做到:

  • 每次向此表添加内容时,尝试更新会话端“上次访问过的页面”条目的一个触发器。
  • 传输“last”的输入的一个触发器或存储过程 访问过的页面“从会话到此表。

除了触发器,您当然也可以使用包装这一切的存储过程,但在这种情况下IMHO触发器更干净,因为它不依赖于数据的添加方式。正常会话清理代码还将处理清理该临时数据。会话的默认值可以是“null”。您应该考虑两个触发器代码中没有会话(无论出于何种原因)的罕见情况。 当然这只是为了将来添加它。它不会追溯适用于现有表格。

如果您希望它应用于所有现有和未来的数据,视图上的计算列将是我最好的想法。至少DBMS可以对这些进行大量的缓存。但它又取决于DBMS,是否支持像计算列的视图。