- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我们的一项措施取决于在最后一次“标记”联系之后至少 30 天确定第一个联系客户的人,其中第一个联系始终被标记。例如,我们在 7 月 1 日首次获得客户 - 该员工获得联系“点数”。然后,客户在 7 月 10 日调用另一位工作人员 - 他们没有得到联系“点”。客户在 9 月 1 日(7 月 1 日最后一次标记联系人后 62 天)打电话,并与第三名工作人员通话 - 他们得到了一个联络点。最后,他们在 9 月 20 日与第四个人交谈 - 第四个人没有得分。
我们使用循环实现 SQL Server:
我很想删除这个循环,因为它非常慢,一遍又一遍地读取表格,而且通常我更喜欢基于集合的操作而不是循环。我希望有人已经解决了这个问题并可以提供一些建议。
这是现在的样子:
DROP TABLE IF EXISTS #CUSTOMER_CONTACT
--Set up our table with the contact dates of each customer
--This is the "live" table in our system
CREATE TABLE #CUSTOMER_CONTACT (
CUSTOMER_CODE INT NOT NULL,
EVENT_DATE DATE NOT NULL,
CONTACT_STAFF_CODE VARCHAR(20) NOT NULL,
FIRST_CONTACT_IN_30 INT NOT NULL,
CONSTRAINT PK_#CUSTOMER_CONTACT PRIMARY KEY CLUSTERED ( CUSTOMER_CODE, EVENT_DATE )
)
--Insert some dummy data for one customer over a few years
INSERT INTO #CUSTOMER_CONTACT( CUSTOMER_CODE, EVENT_DATE, CONTACT_STAFF_CODE, FIRST_CONTACT_IN_30 )
VALUES ( 1, '2014-10-07', 'A', 0 ),
( 1, '2014-12-01', 'A', 0 ),
( 1, '2015-10-06', 'B', 0 ),
( 1, '2015-10-07', 'C', 0 ),
( 1, '2015-10-15', 'C', 0 ),
( 1, '2015-11-10', 'C', 0 ),
( 1, '2016-03-15', 'D', 0 ),
( 1, '2016-03-18', 'A', 0 ),
( 1, '2016-05-02', 'D', 0 ),
( 1, '2016-09-09', 'D', 0 ),
( 1, '2017-10-09', 'C', 0 ),
( 1, '2017-10-10', 'B', 0 ),
( 1, '2017-10-11', 'B', 0 ),
( 1, '2017-10-20', 'D', 0 ),
( 1, '2018-10-10', 'D', 0 ),
( 1, '2019-03-07', 'D', 0 ),
( 1, '2019-06-12', 'A', 0 ),
( 1, '2019-08-02', 'A', 0 )
--Tag the very first contact per client so the staff person "A" gets a "point"
UPDATE C
SET C.FIRST_CONTACT_IN_30 = 1
FROM #CUSTOMER_CONTACT AS C
INNER JOIN (
SELECT CUSTOMER_CODE,
MIN( EVENT_DATE ) AS FIRST_EVENT_DATE
FROM #CUSTOMER_CONTACT
GROUP BY CUSTOMER_CODE
) AS M
ON M.CUSTOMER_CODE = C.CUSTOMER_CODE
AND M.FIRST_EVENT_DATE = C.EVENT_DATE
DROP TABLE IF EXISTS #NEXT_CONTACT_DATE
--This temp table will store the next event to be tagged
CREATE TABLE #NEXT_CONTACT_DATE (
CUSTOMER_CODE INT NOT NULL,
EVENT_DATE DATE NOT NULL,
CONSTRAINT PK_#NEXT_CONTACT_DATE PRIMARY KEY CLUSTERED ( CUSTOMER_CODE, EVENT_DATE )
)
--Just in case there is a flaw in my logic for the WHILE I'll use this to cap the iterations
DECLARE @I INT = 1
--For each customer, as long as I can find any record at least 30 days after the latest tagged records, keep
--on looping
WHILE EXISTS (
SELECT *
FROM #CUSTOMER_CONTACT AS CC
INNER JOIN (
--Find the latest tagged event
SELECT CUSTOMER_CODE,
MAX( EVENT_DATE ) AS LATEST_CONTACT_DATE
FROM #CUSTOMER_CONTACT
WHERE FIRST_CONTACT_IN_30 = 1
GROUP BY CUSTOMER_CODE
) AS L
ON L.CUSTOMER_CODE = CC.CUSTOMER_CODE
--Find any event at least 30 days after that
AND DATEADD( DAY, 30, L.LATEST_CONTACT_DATE ) <= CC.EVENT_DATE
) AND
--And make sure I haven't hit my iteration limit
@I <= 100
BEGIN
TRUNCATE TABLE #NEXT_CONTACT_DATE
--Now store the earliest contact date for each customer that was at least 30 days
--after the latest tagged event date
INSERT INTO #NEXT_CONTACT_DATE( CUSTOMER_CODE, EVENT_DATE )
SELECT CC.CUSTOMER_CODE,
MIN( CC.EVENT_DATE ) AS EVENT_DATE
FROM #CUSTOMER_CONTACT AS CC
INNER JOIN (
SELECT CUSTOMER_CODE,
MAX( EVENT_DATE ) AS LATEST_CONTACT_DATE
FROM #CUSTOMER_CONTACT
WHERE FIRST_CONTACT_IN_30 = 1
GROUP BY CUSTOMER_CODE
) AS L
ON L.CUSTOMER_CODE = CC.CUSTOMER_CODE
AND DATEADD( DAY, 30, L.LATEST_CONTACT_DATE ) <= CC.EVENT_DATE
GROUP BY CC.CUSTOMER_CODE
--Update the main table to tag that contact date to give a "point" to that staff member
UPDATE CC
SET CC.FIRST_CONTACT_IN_30 = 1
FROM #CUSTOMER_CONTACT AS CC
INNER JOIN #NEXT_CONTACT_DATE AS N
ON N.CUSTOMER_CODE = CC.CUSTOMER_CODE
AND N.EVENT_DATE = CC.EVENT_DATE
--Don't forget to increment so my loop isn't endless
SET @I = @I + 1
END
--Check the data at the end.
--It looks good to me
SELECT CC.CUSTOMER_CODE,
CC.EVENT_DATE,
CC.CONTACT_STAFF_CODE,
CC.FIRST_CONTACT_IN_30
FROM #CUSTOMER_CONTACT AS CC
下表显示了结果。您可以看到前 3 个事件中的每一个都被标记为相隔 30 天,但第 4 个事件在第 3 个事件之后不到 30 天。事件 5 仍在事件 3 的 30 天内,但事件 6 现在距离最新标记的事件已超过 30 天,因此它也被标记。
CUSTOMER_CODE EVENT_DATE CONTACT_STAFF_CODE FIRST_CONTACT_IN_30
1 07/10/2014 A 1
1 01/12/2014 A 1
1 06/10/2015 B 1
1 07/10/2015 C 0
1 15/10/2015 C 0
1 10/11/2015 C 1
1 15/03/2016 D 1
1 18/03/2016 A 0
1 02/05/2016 D 1
1 09/09/2016 D 1
1 09/10/2017 C 1
1 10/10/2017 B 0
1 11/10/2017 B 0
1 20/10/2017 D 0
1 10/10/2018 D 1
1 07/03/2019 D 1
1 12/06/2019 A 1
1 02/08/2019 A 1
您可以假设一位客户没有重复的联系日期,因此我不必担心标记两行。
我还没有把它从循环中去掉。我一直认为 ROW_NUMBER 或一些累积 SUM 有一些聪明之处,但我一直坚持这样一个事实,即每次标记事件时计数器都需要重置,这可能是上次标记事件后 31 天,或 365 天。
最佳答案
这个逻辑需要循环。如果您只是寻找 30 天的安静期,则不需要循环。但如果每天都有事件,请考虑并发症。
您可以使用递归 CTE 在数据库中 执行循环。这应该比在外部使用多个查询快得多。代码如下所示:
with cs as (
select cc.*, row_number() over (partition by customer_code order by event_date) as seqnum
from customer_contact cc
),
cte as (
select customer_code, event_date, contact_staff_code, seqnum, 1 as flag
from cs
where seqnum = 1
union all
select cte.customer_code, cs.event_date, cs.contact_staff_code, cs.seqnum,
(case when cs.event_date > dateadd(day, 30, cte.event_date) then 1 else 0 end)
from cte join
cs
on cs.customer_code = cte.customer_code and cs.seqnum = cte.seqnum + 1
)
select *
from cte
order by customer_code, event_date;
Here是一个数据库<> fiddle 。
关于sql - 避免 SQL 中的循环 - 在最后一个标记事件后至少 30 天为客户标记最早的事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63841533/
我需要一个带有条件的正则表达式: 最少 6 个字符,最多 50 个字符 必须包含 1 个字母 必须包含 1 个数字 可能包含特殊字符,例如!@#$%^&*()_+ 目前我有模式:(?!^[0-9]*$
我想检查密码是否至少包含一个字母和一个数字。接受特殊字符但不是必需的... 那将是一个简单的密码检查器。 最佳答案 您可以使用先行断言来检查任何数字和任何字母的存在,如下所示: ^(?=.*[a-zA
我需要找到生产至少三种不同型号电脑的制造商。结果集:制造商、型号数量。 我的 table 是产品(制造商、型号、类型)PC(代码、型号、速度、内存、高清、CD、价格) 我现在已经这样做了 SELECT
在我正在处理的哈希字典中,根据 GDB,数组的大小已从 500 调整到 1000。它在尝试添加时崩溃的数组索引是 799,所以它没有超出范围......我不是确定它为什么会出现段错误,尤其是在这样一条
我需要一个正则表达式来检查字符串的长度是否至少为 10 个字符。这些字符是什么并不重要。 谢谢 最佳答案 您可以使用: .{10,} 自 .默认情况下不匹配换行符,您必须使用合适的修饰符(如果您的正则
我有以下代码: val num1: Int? = someObject.number val num2: Int? = anotherObject?.anotherNumber val numToFa
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我一直在进行查询以获取用户列表及其各自的组。我知道了。 但是有一些限制: 如果用户只是 group5 的成员,则不应出现在列表中 如果是 group5 和其他组的成员,它应该出现在列表中 我可以获得不
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,
我需要忽略任何一个空格,并且应该匹配至少大于一个空格的空格... "MARY HAD A LITTLE LAMB" 我希望 "MARY", "HAD A LITTLE", "
如何在仅数字验证中允许空格(至少 8 位数字)?当允许空格时,输入电话号码会更容易。例如0400 123 456、9699 1234。 到目前为止,这是我的代码,我只进行了最少 8 位数字验证: jQ
我想将以下内容重写为 HTML 模式: if (/\S/.test(myString)) { // string is not empty and not just whitespace }
我的想法是使用 php 或 js 创建大量的 div。 (我从昨天开始写js。) 所以我自己给定的任务是使用 php 或 js 或两者生成一个 div 网格。到目前为止的想法是有一个通用的 div 作
显示字符串中至少有 10 个数字字符的正则表达式。 可以多于 10 个,但不能少于 10 个。在随机位置可以有任意数量的其他字符,将数字分隔开。 示例数据: (123) 456-7890 123-45
我目前在 Firefox 中使用边框动画时遇到问题,从无到 50px。 Chrome 非常好,但 Firefox 不是,我想同样的问题也会出现在 Opera 中。 这里有一个 fiddle 来向您展示
作为 ruby 挑战训练的一部分,我被要求创建一个方法 substrings(string),它将接受一个字符串,并返回一个包含所有子字符串的数组。 即 substrings("cat") #=>
我目前有这段代码,它检查数组中的所有元素是否相同。如果是这种情况,则返回 true def all_equal(lst): """ >>> all_equal([1,1,1,1,1,1,1])
当我注意到 Libre Office 电子表格显示远低于 2^53 的数字的错误值时,我正在做一些计算以计划改进我的主要筛选器的实现,这是 FoxPro 和许多其他精确整数计算的限制内部使用 C do
我有一个复选框,我想检查用户是否填写了它后面的文本框。必须至少包含 5 个字符才能选中复选框。 pro)) echo 'checked' ?>> pro?>">Please supply your I
我正在为我的食谱设计一个数据库。我在我的设计中创建了多个表格:书籍、作者、食谱、成分,对于所有这些项目,我想将媒体(图像或视频)链接到所有这些表格中的项目。 我在想这样的设计: media_id, r
我是一名优秀的程序员,十分优秀!