添加新列,其中 CONCAT 的过去期间(日期范围)的值与 SQL 中的组有关

Add new column that CONCAT's values from past period (date range) respecting groups in SQL

我正在使用 MS SQL Server 2012 检查用户是否在过去一段时间内为每个 transaction/row.

选择了特定类型的电影

我想解决这个问题,方法是将过去的类型在给定时间段内连接到一个新列中,例如过去 12 个月,或 6 至 12 个月。我不关心新专栏中出现的重复类型。

然后我可以 运行 逻辑来检查特定类型是在 SQL 中还是由外部程序订购的。下面是两个订购视频的客户的预期输出示例。

这里是我用来生成初始table的SQL。

DROP TABLE IF EXISTS tb1;

CREATE TABLE tbl
    (id int IDENTITY(1,1) PRIMARY KEY,
     PersonName VARCHAR(10),
     OrderDT DATETIME,
     Genre VARCHAR(10));

INSERT INTO tbl (PersonName, OrderDT, Genre)
VALUES
    ('Bob', '2019-05-01', 'biopic'),
    ('Bob', '2019-10-01', 'drama'),
    ('Bob', '2020-02-01', 'doco, action' ),
    ('Bob', '2020-05-01', 'comedy'),
    ('Bob', '2020-09-01', 'horror'),
    ('Bob', '2020-12-01', 'action, comedy'),
    ('Alice', '2018-03-01', 'comedy, drama'),
    ('Alice', '2018-08-01', 'action'),
    ('Alice', '2018-12-01', 'horror');

我知道使用 STRING_AGG() 和 GROUP BY 可用于聚合每个客户的值行,但我需要帮助才能在过去一段时间和每一行中执行此操作。

即使我使用的是 MS SQL(我自己没有选择 :))我希望该解决方案足够通用,可以在 Postgres 或 MariaDB 中使用。因此,如果可能,我想避免使用特殊的 MS SQL 服务器专用命令,例如 STRING_AGG()。

这个问题在 SQL 服务器中已经够难的了。您不应该在一个字符串中存储多个流派。你提到 string_agg() 所以你显然没有使用 SQL Server 2012。这是在 SQL Server 的更新版本中工作的逻辑:

select t.*, t12.*, t6.*
from tbl t cross apply
     (select string_agg( trim(g.genre), ', ') as orders_12mon
      from (select distinct s.value as genre
            from tbl t2 cross apply
                 string_split(genre, ',') s
            where t2.personname = t.personname and
                  t2.orderdt <= t.orderdt and
                  t2.orderdt > dateadd(month, -12, t.orderdt)
           ) g
     ) t12 cross apply
     (select string_agg( trim(g.genre), ', ') as orders_6mon
      from (select distinct s.value as genre
            from tbl t2 cross apply
                 string_split(genre, ',') s
            where t2.personname = t.personname and
                  t2.orderdt > dateadd(month, -12, t.orderdt) and
                  t2.orderdt <= dateadd(month, -6, t.orderdt)
           ) g
     ) t6;

Here 是一个 db<>fiddle.

此代码是高度不可移植的。以下是一些原因:

  • Date/time函数在不同的数据库中是不同的。没有一致的方法可以在您提到的数据库中减去 6 个月。
  • SQL 服务器不支持带时间间隔的 range 关键字。
  • 不同数据库的字符串处理函数差异很大,所以拆分字符串并不标准。

就是说,如果您事先了解所有类型,我可以想出一种神秘的方法。但这真的很乱,你提到的每个数据库中都有更简单的方法。