【发布时间】:2016-11-18 23:01:59
【问题描述】:
查询的第一部分获取Policy 的Premiums、Effective 和Expiration 日期。
第二部分创建Calendar,第三部分(最终SELECT 声明)返回按Month 和Year 细分的收益
一切正常,只需 3 秒即可显示结果。
但是然后我需要过滤PolicyNumbers 可以使用的内容,基本上我需要摆脱没有@ClassCode 的PolicyNumber。因此,在查询的第一部分中,我放置了WHERE 子句:
WHERE State IN ('CA','NV','AZ')
AND PolicyNumber IN (
SELECT PolicyNumber
FROM tblClassCodesPlazaCommercial
GROUP BY PolicyNumber
HAVING COUNT (CASE WHEN ClassCode NOT IN (@ClassCode)
THEN 1 END)=0
)
感谢@Prdp 用户,我有这样的声明:Case 语句将为列表中存在的 ClassCode 生成 1,否则将生成 NULL。现在计数聚合将为每个 PolicyNumber 计数 1。通过设置 = 0,我们可以确保 PolicyNumber 在给定列表中没有任何 ClassCode。
在该查询永远旋转之后,因为@ClassCode 在 SSRS 报告中可以有超过 200 个ClassCodes。
有趣的是,这两个语句分别可以正常工作。但是当我一起使用它们时(将WHERE 子句放在cte policy_data 中,那么执行将永远存在。
有什么方法可以告诉引擎执行查询的第一部分,即
; WITH Earned_to_date AS (
SELECT Cast(EOMONTH (GETDATE(), -1) AS DATE) AS Earned_to_date
), policy_data AS (
SELECT
PolicyNumber
, Cast(PolicyEffectiveDate AS DATE) AS PolicyEffectiveDate
, Cast(PolicyExpirationDate AS DATE) AS PolicyExpirationDate
, WrittenPremium
, State
FROM PlazaInsuranceWPDataSet
WHERE State IN ('CA','NV','AZ')
/* -------This statement gives me trouble ----------------------*/
AND PolicyNumber IN (
SELECT PolicyNumber
FROM tblClassCodesPlazaCommercial
GROUP BY PolicyNumber
HAVING COUNT (CASE WHEN ClassCode NOT IN (5151)
THEN 1 END)=0
)
)
然后仅计算和分解那些已过滤的保单的收益。
我的整个代码如下:
; WITH Earned_to_date AS (
SELECT Cast(EOMONTH (GETDATE(), -1) AS DATE) AS Earned_to_date
), policy_data AS (
SELECT
PolicyNumber
, Cast(PolicyEffectiveDate AS DATE) AS PolicyEffectiveDate
, Cast(PolicyExpirationDate AS DATE) AS PolicyExpirationDate
, WrittenPremium
, State
FROM PlazaInsuranceWPDataSet
WHERE State IN ('CA','NV','AZ')
/* -------This statement gives me trouble ----------------------*/
AND PolicyNumber IN (
SELECT PolicyNumber
FROM tblClassCodesPlazaCommercial
GROUP BY PolicyNumber
HAVING COUNT (CASE WHEN ClassCode NOT IN (@ClassCode)
THEN 1 END)=0
)
)
, digits AS (
SELECT digit
FROM (VALUES (0), (1), (2), (3), (4)
, (5), (6), (7), (8), (9)) AS z2 (digit)
), numbers AS (
SELECT 1000 * d4.digit + 100 * d3.digit + 10 * d2.digit + d1.digit AS number
FROM digits AS d1
CROSS JOIN digits AS d2
CROSS JOIN digits AS d3
CROSS JOIN digits AS d4
), calendar AS (
SELECT
DateAdd(month, number, '1753-01-01') AS month_of
, DateAdd(month, number, '1753-02-01') AS month_after
FROM numbers
), policy_dates AS (
SELECT
PolicyNumber
, CASE
WHEN month_of < PolicyEffectiveDate THEN PolicyEffectiveDate
ELSE month_of
END AS StartRiskMonth
, CASE
WHEN PolicyExpirationDate < month_after THEN PolicyExpirationDate
WHEN Earned_to_date.Earned_to_date < month_after THEN Earned_to_date
ELSE month_after
END AS EndRiskMonth
, DateDiff(day, PolicyEffectiveDate, PolicyExpirationDate) AS policy_days
, WrittenPremium
FROM policy_data
JOIN calendar
ON (policy_data.PolicyEffectiveDate < calendar.month_after
AND calendar.month_of < policy_data.PolicyExpirationDate)
CROSS JOIN Earned_to_date
WHERE month_of < Earned_to_date
)
SELECT
Year(StartRiskMonth) as YearStartRisk,
Month(StartRiskMonth) as MonthStartRisk,
c.YearNum,c.MonthNum,
convert(varchar(7), StartRiskMonth, 120) as RiskMonth,
sum(WrittenPremium * DateDiff(day, StartRiskMonth, EndRiskMonth) / policy_days) as EarnedPremium
FROM tblCalendar c
LEFT JOIN policy_dates l ON c.YearNum=Year(l.StartRiskMonth) AND c.MonthNum = Month(l.StartRiskMonth)
AND l.StartRiskMonth BETWEEN '01-01-2015' AND '12-31-2016'
WHERE c.YearNum Not IN (2017)
GROUP BY convert(varchar(7), StartRiskMonth, 120),
Year(StartRiskMonth) , Month(StartRiskMonth),
c.YearNum,c.MonthNum
ORDER BY c.YearNum,c.MonthNum
提高性能的最佳方法是什么?
我在两个表的PolicyNumber 上创建了non-clustered 索引。但还是一无所获。
就像我说的,在我看来,如果 SQL 引擎将处理需要 3 秒的第一部分(PolicyNumber 过滤),然后再执行需要 3 秒的第二部分(计算那些 PolicyNumber) - 那将是非常棒的。
但我是 DBA 的新手,所以我不确定它是否可能。
有什么建议吗?
谢谢
执行计划::
【问题讨论】:
-
Codereview.stackexchange.com 是一个更好的地方
标签: sql sql-server tsql join reporting-services