我可以在 SQL 查询中使用什么来帮助我确定为什么我的查询没有返回任何数据结果
What can I use in a SQL query to help me determine why my query is not returning any data results
有人可以帮助我对 SQL 查询进行故障排除,以了解为什么它没有返回任何结果,只返回列别名吗?
我把它分开了,所有显然组合在一起的部分 returns 单独的预期数据。提前感谢任何guidance/assistance。下面是我的脚本:
...
DECLARE @u_cnt INT;
DECLARE @f_yr DATE;
DECLARE @qrt VARCHAR(3);
DECLARE @dnum VARCHAR(5);
SET @u_cnt = 10000;
SET @f_yr = '2002-05-20';
SET @qrt = 'Q2';
SET @dnum = '43234';
SELECT c.GroupLabel AS ORG_Code,
CONVERT (VARCHAR(7), FORMAT((CONVERT(DATE, c.changedate)), 'MM-yyyy')) AS [MONTH],
COUNT(DISTINCT CASE s.TestType
WHEN 'IR' THEN c.changedate
ELSE NULL END) AS TEST_DAYS,
COUNT(DISTINCT c.changedate) AS ALLDAYS,
COUNT(s.Id) AS total,
(CASE WHEN (@u_cnt IS NULL) THEN -1
ELSE @u_cnt
END) AS board_cnt,
FORMAT((COUNT(s.Id) / CASE
WHEN (@u_cnt IS NULL) THEN -1
ELSE @u_cnt
END), 'P0') AS pct_tested_text,
CASE WHEN 100 * (COUNT(s.Id) / CASE
WHEN (@u_cnt IS NULL) THEN -1
ELSE @u_cnt
END) >= 15
AND (COUNT(DISTINCT CASE s.TestType
WHEN 'IR' THEN c.changedate
ELSE NULL END)) >= 4
THEN 'Yes'
ELSE 'NO' END
FROM cforms c
INNER JOIN spitems sp
ON c.Id = s.FormId
WHERE c.Group = 'HR'
AND c.bFlag IS NULL
AND s.Report IN ('P', 'N')
AND CONVERT(VARCHAR(6), c.changedate, 112) IN
(SELECT
CASE
WHEN f.Quarter = 'Q1' THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1) + f.FyMonthNumber
WHEN f.Quarter = 'ALL' AND f.FyMonth IN ('OCT', 'NOV', 'DEC') THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1, 112) + f.FyM
ELSE CONVERT(VARCHAR(4), YEAR(@f_yr), 112) + f.FyM
END AS FY_MONTH
FROM fis f
WHERE f.Quarter = @qrt)
AND c.GroupLabel = 'Hr' + @dnum
GROUP BY c.GroupLabel, FORMAT((CONVERT(DATE, c.changedate)), 'MM-yyyy')
ORDER BY 1, FORMAT((CONVERT(DATE, c.changedate)), 'MM-yyyy');
可能会限制您的数据的一切都在下面的这部分代码中。我将其拆开并在 why 和 where 中添加了注释,它们是有限的。我认为你的 CONVERT
是罪魁祸首。
--this inner join will limit the rows to only those with matching Id and FormId
INNER JOIN spitems sp
ON c.Id = s.FormId
--of the rows already filtered via the JOIN, they are further limited to thous with the Group = 'HR', a NULL bFlag, and Report = to P or N
WHERE c.Group = 'HR'
AND c.bFlag IS NULL
AND s.Report IN ('P', 'N')
--The first convert here changed changedate to yyyymmd (notice the day).
--In the sub-query, you seem to only be returning yyyymm formatted with a -,
--thus this would return ZERO rows. varchar(6) could resolve this,
--by dropping the day, but you'd need to add the hyphen or remove it from the `IN` clause
AND CONVERT(VARCHAR(7), c.changedate, 112) IN
(SELECT
CASE
WHEN f.Quarter = 'Q1' THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1) + '-' + f.FyMonthNumber
WHEN f.Quarter = 'ALL' AND f.FyMonth IN ('OCT', 'NOV', 'DEC') THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1, 112) + '-' + f.FyMonthNumber
ELSE CONVERT(VARCHAR(4), YEAR(@f_yr), 112) + '-' + f.FyMonthNumber
END AS FY_MONTH
FROM FyQm f
WHERE f.Quarter = @qrt)
--Lastly, there may be a case sensitivity here Hr vs HR or there just simply aren't any rows that match this predicate
AND c.GroupLabel = 'Hr' + @dnum
编辑
详细说明我上面的回答...您已经更改了 where 子句的一部分。特别是您正在评估 c.changedate
值列表的部分。您已更改为:
AND CONVERT(VARCHAR(6), c.changedate, 112) IN ...
这是部分修复。它会删除您之前的尾随 DAY 值,留下 YYYYMM
。但是,在您的子查询中,您将值列表格式化为 YYYYMM-?
,其中 ? f.FyMonthNumber
是什么。如您所见,这将永远不会匹配您原来的 convert
语句,因为它没有 连字符 。首先要更改的是从字符串连接中删除连字符。在您编辑的 post 中,您已经这样做了,所以 干得好 。接下来,问题可能是当您尝试将 +
与 f.FyMonthNumber
组合时,您的 +
未被视为加法而不是串联。如果 f.FyMonthNumber
是一个 int
那么它将添加它。
DECLARE @f_yr DATE;
SET @f_yr = '2002-05-20';
SELECT CONVERT(VARCHAR(4), YEAR(@f_yr) - 1) + 02
这里你希望它是 return 200102 但它是 returns 2003 因为它正在执行加法。您可以将其转换为 varchar
或 char
来解决此问题。
SELECT CONVERT(VARCHAR(4), YEAR(@f_yr) - 1) + cast('02' as varchar)
最后,您 可能 运行 遇到的一个问题是,如果 f.FyMonthNumber
存储为 int
,它不会前导零。因此,对于 1 月,它将表示为 1
而不是 01
,这也将 return 十月之前的任何一个月的零行。您可以使用 right
函数处理此问题。
DECLARE @f_yr DATE;
SET @f_yr = '2002-05-20';
SELECT CONVERT(VARCHAR(4), YEAR(@f_yr) - 1) + right('0' + cast('1' as varchar(2)),2) --a month as a single digit
SELECT CONVERT(VARCHAR(4), YEAR(@f_yr) - 1) + right('0' + cast('12' as varchar(2)),2) --a month with double digits
综上所述,我怀疑此编辑可以解决您的问题。不过我会注意到,您没有评估 Q2、Q3 或 Q4 的任何 case 表达式 如果适用...
DECLARE @u_cnt INT;
DECLARE @f_yr DATE;
DECLARE @qrt VARCHAR(3);
DECLARE @dnum VARCHAR(5);
SET @u_cnt = 10000;
SET @f_yr = '2002-05-20';
SET @qrt = 'Q2';
SET @dnum = '43234';
SELECT c.GroupLabel AS ORG_Code,
CONVERT (VARCHAR(7), FORMAT((CONVERT(DATE, c.changedate)), 'MM-yyyy')) AS [MONTH],
COUNT(DISTINCT CASE s.TestType
WHEN 'IR' THEN c.changedate
ELSE NULL END) AS TEST_DAYS,
COUNT(DISTINCT c.changedate) AS ALLDAYS,
COUNT(s.Id) AS total,
(CASE WHEN (@u_cnt IS NULL) THEN -1
ELSE @u_cnt
END) AS board_cnt,
FORMAT((COUNT(s.Id) / CASE
WHEN (@u_cnt IS NULL) THEN -1
ELSE @u_cnt
END), 'P0') AS pct_tested_text,
CASE WHEN 100 * (COUNT(s.Id) / CASE
WHEN (@u_cnt IS NULL) THEN -1
ELSE @u_cnt
END) >= 15
AND (COUNT(DISTINCT CASE s.TestType
WHEN 'IR' THEN c.changedate
ELSE NULL END)) >= 4
THEN 'Yes'
ELSE 'NO' END
FROM cforms c
INNER JOIN spitems sp
ON c.Id = s.FormId
WHERE c.Group = 'HR'
AND c.bFlag IS NULL
AND s.Report IN ('P', 'N')
AND CONVERT(VARCHAR(6), c.changedate, 112) IN
(SELECT
CASE
WHEN f.Quarter = 'Q1' THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1) + right('0' + cast(f.FyMonthNumber as varchar(2)))
WHEN f.Quarter = 'ALL' AND f.FyMonth IN ('OCT', 'NOV', 'DEC') THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1, 112) + right('0' + cast(f.FyMonthNumber as varchar(2)))
ELSE CONVERT(VARCHAR(4), YEAR(@f_yr), 112) + right('0' + cast(f.FyMonthNumber as varchar(2)))
END AS FY_MONTH
FROM fis f
WHERE f.Quarter = @qrt)
AND c.GroupLabel = 'Hr' + @dnum
GROUP BY c.GroupLabel, FORMAT((CONVERT(DATE, c.changedate)), 'MM-yyyy')
ORDER BY 1, FORMAT((CONVERT(DATE, c.changedate)), 'MM-yyyy');
尝试改成这样(看第一个转换):
...
AND CONVERT(VARCHAR(7), c.changedate, 120) IN
(SELECT
CASE
WHEN f.Quarter = 'Q1' THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1) + '-' + f.FyMonthNumber
WHEN f.Quarter = 'ALL' AND f.FyMonth IN ('OCT', 'NOV', 'DEC') THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1, 112) + '-' + f.FyMonthNumber
ELSE CONVERT(VARCHAR(4), YEAR(@f_yr), 112) + '-' + f.FyMonthNumber
END AS FY_MONTH
FROM FyQm f
WHERE f.Quarter = @qrt)
...
您转换的是 112 (yyyymm
) 而不是 120 (yyyy-mm
) 并且您的内心 select returns yyyy-mm
我敢打赌不同的列定义
DECLARE @qrt VARCHAR(3);
vs
whatever is FROM FyQm f WHERE f.Quarter = @qrt
'Q2 ' with a blank or null probably does not equal f.Quarter which may be defined as VARCHAR(2)
Perhaps we could try this sql to see that each criterion has some rows
Select
Sum(1) as cntAll
,Sum (CASE When c.Group = 'HR' Then 1 Else 0 End) as cntGroup
,Sum (CASE When c.bFlag IS NULL Then 1 Else 0 End) as cntbFlag
,Sum (CASE When s.Report IN ('P', 'N') Then 1 Else 0 End) as cntsReport
,Sum (CASE When CONVERT(VARCHAR(6), c.changedate, 112)
IN ('200204', '200205', '200206') Then 1 Else 0 End) as cntchangedate
,Sum (CASE When c.GroupLabel = 'Hr43234' Then 1 Else 0 End) as cntGroupLabel
FROM cforms c
INNER JOIN spitems s
ON c.Id = s.FormId
Maybe time to follow @scsimon advice, and add back criteria one at a time and see which one blocks all of the rows
-- WHERE c.Group = 'HR'
-- AND c.bFlag IS NULL
-- AND s.Report IN ('P', 'N')
-- AND CONVERT(VARCHAR(6), c.changedate, 112) IN ('200204', '200205', '200206')
-- AND c.GroupLabel = 'Hr43234'
我已经重新格式化了您的代码并附上备注:
declare @u_cnt int, @f_yr date, @qrt varchar(3), @dnum varchar(5);
select @u_cnt = 10000, @f_yr = '20020520', @qrt = 'Q2', @dnum = '43234';
select c.GroupLabel as ORG_CODE
-- Assuming c.changedate is datetime, otherwise cast(c.changedate as datetime)
, format(c.changedate, 'MM-yyyy') as [MONTH]
, count(distinct case s.TestType when 'IR' then c.changedate else null end) as IR_TEST_DAYS
, count(distinct c.changedate) as TEST_DAYS
, count(s.Id) as TOTAL
, (case when (@u_cnt is null) then - 1 else @u_cnt end) as BOARD_CNT
, format((count(s.Id) /
-- avoiding also division by 0
case when isnull(@u_cnt, 0) = 0
then - 1
else @u_cnt end), 'P0')
as PCT
, case
when 100 * (count(s.Id) /
-- avoiding also division by 0
case when isnull(@u_cnt, 0) = 0
then - 1
else @u_cnt
end) >= 15
and (count(distinct case s.TestType
when 'IR' then c.changedate else null
end)) >= 4
then 'Yes' else 'NO'
end as PCT_TEST_COMP
from cforms c
join spitems s on (c.Id = s.FormId)
where c.group = 'HR'
and c.bFlag is null
and s.Report in ('P', 'N')
and convert(varchar(6), c.changedate, 112) in -- yyyymm (ISO format)
(
select
cast(year(@f_yr) +
case
when f.Quarter = 'Q1'
then (-1)
when f.Quarter = 'ALL'
and f.FyMonthNumber in ('10', '11', '12')
then (-1)
else (0)
end as varchar(4))
+ f.FyMonthNumber -- JAN = '01' or '1' ?
from FyQm f
where f.Quarter = @qrt
)
and c.GroupLabel = 'Hr' + @dnum
group by c.GroupLabel
-- Assuming c.changedate is datetime, otherwise cast(c.changedate as datetime)
, format(c.changedate, 'MM-yyyy')
order by ORG_CODE, [MONTH];
你能检查一下 FyQm.FyMonthNumber 是 varchar(2)
还是 char(2)
并且将一月表示为 '01' 而不是 '1'?
您的主要问题是为什么您没有获取给定查询的数据?
所以你要调试看看问题出在哪里
所以对于给定的参数,
DECLARE @u_cnt INT;
DECLARE @f_yr DATE;
DECLARE @qrt VARCHAR(3);
DECLARE @dnum VARCHAR(5);
SET @u_cnt = 10000;
SET @f_yr = '2002-05-20';
SET @qrt = 'Q2';
SET @dnum = '43234';
所以从基础开始
select *
FROM cforms c
--INNER JOIN spitems sp
--ON c.Id = s.FormId
WHERE c.Group = 'HR'
--AND c.bFlag IS NULL
--AND s.Report IN ('P', 'N')
注意注释部分,它是否是 return 数据,如果是,则取消注释 AND c.bFlag IS NULL
并以这种方式取消注释其他部分。
你确定是INNER JOIN
还是LEFt JOIN
?
将期间子查询放在临时 table 中,虽然这不是主要原因,如果 return 记录较少,那么您也可以使用 CTE,
Create table #tempperiod(period varchar(6))
insert into #tempperiod(period)
select
cast(year(@f_yr) +
case
when f.Quarter = 'Q1'
then (-1)
when f.Quarter = 'ALL'
and f.FyMonthNumber in ('10', '11', '12')
then (-1)
else (0)
end as varchar(4))
+ f.FyMonthNumber
from FyQm f
where f.Quarter = @qrt
-- in order to test,does it return any records,does it return desire output
select * from #tempperiod
- 在谓词中使用的列中检查 space (
LTRIM and RTRIM
)。
- 避免在 case 语句中除以 0
- 如果确实如此,
INNER JOIN
则使用 EXISTS
子句,因为您不需要 spitems sp
列。
- 什么是
ORDER BY 1
? GroupLabel
?那么您在 Order 子句中不需要它们,因为所有行都是 'HR'+'43234'
- 最重要的是,您根本不需要
Order by
,因为 Group By
会为您分类,这是唯一的要求。
仔细检查#tempperiod数据,格式是否与
相同
CONVERT(VARCHAR(6), c.changedate, 112)
JOIN or/and WHERE 子句可以是一个原因。
以下基本推导方法是找出查询的哪一部分给出这样的结果:
首先,消除所有的 WHERE 子句并检查当前 JOIN 是否可以通过这样设置 WHERE 来 return 行:
WHERE 1 = 1
--AND c.Group = 'HR'
--AND c.bFlag IS NULL
--AND s.Report IN ('P', 'N')
--AND CONVERT(VARCHAR(6), c.changedate, 112) IN
-- (SELECT
-- CASE
-- WHEN f.Quarter = 'Q1' THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1) + f.FyMonthNumber
-- WHEN f.Quarter = 'ALL' AND f.FyMonth IN ('OCT', 'NOV', 'DEC') THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1, 112) + f.FyM
-- ELSE CONVERT(VARCHAR(4), YEAR(@f_yr), 112) + f.FyM
-- END AS FY_MONTH
-- FROM fis f
-- WHERE f.Quarter = @qrt)
--AND c.GroupLabel = 'Hr' + @dnum
然后,逐一取消注释 WHERE 语句以确定哪一个过滤行:
WHERE 1 = 1
AND c.Group = 'HR'
--AND c.bFlag IS NULL
--AND s.Report IN ('P', 'N')
--AND CONVERT(VARCHAR(6), c.changedate, 112) IN
-- (SELECT
-- CASE
-- WHEN f.Quarter = 'Q1' THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1) + f.FyMonthNumber
-- WHEN f.Quarter = 'ALL' AND f.FyMonth IN ('OCT', 'NOV', 'DEC') THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1, 112) + f.FyM
-- ELSE CONVERT(VARCHAR(4), YEAR(@f_yr), 112) + f.FyM
-- END AS FY_MONTH
-- FROM fis f
-- WHERE f.Quarter = @qrt)
--AND c.GroupLabel = 'Hr' + @dnum
然后,再声明:
WHERE 1 = 1
AND c.Group = 'HR'
AND c.bFlag IS NULL
--AND s.Report IN ('P', 'N')
--AND CONVERT(VARCHAR(6), c.changedate, 112) IN
-- (SELECT
-- CASE
-- WHEN f.Quarter = 'Q1' THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1) + f.FyMonthNumber
-- WHEN f.Quarter = 'ALL' AND f.FyMonth IN ('OCT', 'NOV', 'DEC') THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1, 112) + f.FyM
-- ELSE CONVERT(VARCHAR(4), YEAR(@f_yr), 112) + f.FyM
-- END AS FY_MONTH
-- FROM fis f
-- WHERE f.Quarter = @qrt)
--AND c.GroupLabel = 'Hr' + @dnum
依此类推,直到进入没有行的地步returned
此技术最终会将您带到过滤掉行的查询的一部分(部分)
如果原始数据集 return 的行数太多,在调试过程中检索所有行可能会很昂贵,所以我建议将它们注释掉并改用 COUNT(*) :
SELECT COUNT(*)
/*
c.GroupLabel AS ORG_Code,
CONVERT (VARCHAR(7), FORMAT((CONVERT(DATE, c.changedate)), 'MM-yyyy')) AS [MONTH],
COUNT(DISTINCT CASE s.TestType
WHEN 'IR' THEN c.changedate
ELSE NULL END) AS TEST_DAYS,
COUNT(DISTINCT c.changedate) AS ALLDAYS,
COUNT(s.Id) AS total,
(CASE WHEN (@u_cnt IS NULL) THEN -1
ELSE @u_cnt
END) AS board_cnt,
FORMAT((COUNT(s.Id) / CASE
WHEN (@u_cnt IS NULL) THEN -1
ELSE @u_cnt
END), 'P0') AS pct_tested_text,
CASE WHEN 100 * (COUNT(s.Id) / CASE
WHEN (@u_cnt IS NULL) THEN -1
ELSE @u_cnt
END) >= 15
AND (COUNT(DISTINCT CASE s.TestType
WHEN 'IR' THEN c.changedate
ELSE NULL END)) >= 4
THEN 'Yes'
ELSE 'NO' END
*/
FROM cforms c
有人可以帮助我对 SQL 查询进行故障排除,以了解为什么它没有返回任何结果,只返回列别名吗?
我把它分开了,所有显然组合在一起的部分 returns 单独的预期数据。提前感谢任何guidance/assistance。下面是我的脚本:
...
DECLARE @u_cnt INT;
DECLARE @f_yr DATE;
DECLARE @qrt VARCHAR(3);
DECLARE @dnum VARCHAR(5);
SET @u_cnt = 10000;
SET @f_yr = '2002-05-20';
SET @qrt = 'Q2';
SET @dnum = '43234';
SELECT c.GroupLabel AS ORG_Code,
CONVERT (VARCHAR(7), FORMAT((CONVERT(DATE, c.changedate)), 'MM-yyyy')) AS [MONTH],
COUNT(DISTINCT CASE s.TestType
WHEN 'IR' THEN c.changedate
ELSE NULL END) AS TEST_DAYS,
COUNT(DISTINCT c.changedate) AS ALLDAYS,
COUNT(s.Id) AS total,
(CASE WHEN (@u_cnt IS NULL) THEN -1
ELSE @u_cnt
END) AS board_cnt,
FORMAT((COUNT(s.Id) / CASE
WHEN (@u_cnt IS NULL) THEN -1
ELSE @u_cnt
END), 'P0') AS pct_tested_text,
CASE WHEN 100 * (COUNT(s.Id) / CASE
WHEN (@u_cnt IS NULL) THEN -1
ELSE @u_cnt
END) >= 15
AND (COUNT(DISTINCT CASE s.TestType
WHEN 'IR' THEN c.changedate
ELSE NULL END)) >= 4
THEN 'Yes'
ELSE 'NO' END
FROM cforms c
INNER JOIN spitems sp
ON c.Id = s.FormId
WHERE c.Group = 'HR'
AND c.bFlag IS NULL
AND s.Report IN ('P', 'N')
AND CONVERT(VARCHAR(6), c.changedate, 112) IN
(SELECT
CASE
WHEN f.Quarter = 'Q1' THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1) + f.FyMonthNumber
WHEN f.Quarter = 'ALL' AND f.FyMonth IN ('OCT', 'NOV', 'DEC') THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1, 112) + f.FyM
ELSE CONVERT(VARCHAR(4), YEAR(@f_yr), 112) + f.FyM
END AS FY_MONTH
FROM fis f
WHERE f.Quarter = @qrt)
AND c.GroupLabel = 'Hr' + @dnum
GROUP BY c.GroupLabel, FORMAT((CONVERT(DATE, c.changedate)), 'MM-yyyy')
ORDER BY 1, FORMAT((CONVERT(DATE, c.changedate)), 'MM-yyyy');
可能会限制您的数据的一切都在下面的这部分代码中。我将其拆开并在 why 和 where 中添加了注释,它们是有限的。我认为你的 CONVERT
是罪魁祸首。
--this inner join will limit the rows to only those with matching Id and FormId
INNER JOIN spitems sp
ON c.Id = s.FormId
--of the rows already filtered via the JOIN, they are further limited to thous with the Group = 'HR', a NULL bFlag, and Report = to P or N
WHERE c.Group = 'HR'
AND c.bFlag IS NULL
AND s.Report IN ('P', 'N')
--The first convert here changed changedate to yyyymmd (notice the day).
--In the sub-query, you seem to only be returning yyyymm formatted with a -,
--thus this would return ZERO rows. varchar(6) could resolve this,
--by dropping the day, but you'd need to add the hyphen or remove it from the `IN` clause
AND CONVERT(VARCHAR(7), c.changedate, 112) IN
(SELECT
CASE
WHEN f.Quarter = 'Q1' THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1) + '-' + f.FyMonthNumber
WHEN f.Quarter = 'ALL' AND f.FyMonth IN ('OCT', 'NOV', 'DEC') THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1, 112) + '-' + f.FyMonthNumber
ELSE CONVERT(VARCHAR(4), YEAR(@f_yr), 112) + '-' + f.FyMonthNumber
END AS FY_MONTH
FROM FyQm f
WHERE f.Quarter = @qrt)
--Lastly, there may be a case sensitivity here Hr vs HR or there just simply aren't any rows that match this predicate
AND c.GroupLabel = 'Hr' + @dnum
编辑
详细说明我上面的回答...您已经更改了 where 子句的一部分。特别是您正在评估 c.changedate
值列表的部分。您已更改为:
AND CONVERT(VARCHAR(6), c.changedate, 112) IN ...
这是部分修复。它会删除您之前的尾随 DAY 值,留下 YYYYMM
。但是,在您的子查询中,您将值列表格式化为 YYYYMM-?
,其中 ? f.FyMonthNumber
是什么。如您所见,这将永远不会匹配您原来的 convert
语句,因为它没有 连字符 。首先要更改的是从字符串连接中删除连字符。在您编辑的 post 中,您已经这样做了,所以 干得好 。接下来,问题可能是当您尝试将 +
与 f.FyMonthNumber
组合时,您的 +
未被视为加法而不是串联。如果 f.FyMonthNumber
是一个 int
那么它将添加它。
DECLARE @f_yr DATE;
SET @f_yr = '2002-05-20';
SELECT CONVERT(VARCHAR(4), YEAR(@f_yr) - 1) + 02
这里你希望它是 return 200102 但它是 returns 2003 因为它正在执行加法。您可以将其转换为 varchar
或 char
来解决此问题。
SELECT CONVERT(VARCHAR(4), YEAR(@f_yr) - 1) + cast('02' as varchar)
最后,您 可能 运行 遇到的一个问题是,如果 f.FyMonthNumber
存储为 int
,它不会前导零。因此,对于 1 月,它将表示为 1
而不是 01
,这也将 return 十月之前的任何一个月的零行。您可以使用 right
函数处理此问题。
DECLARE @f_yr DATE;
SET @f_yr = '2002-05-20';
SELECT CONVERT(VARCHAR(4), YEAR(@f_yr) - 1) + right('0' + cast('1' as varchar(2)),2) --a month as a single digit
SELECT CONVERT(VARCHAR(4), YEAR(@f_yr) - 1) + right('0' + cast('12' as varchar(2)),2) --a month with double digits
综上所述,我怀疑此编辑可以解决您的问题。不过我会注意到,您没有评估 Q2、Q3 或 Q4 的任何 case 表达式 如果适用...
DECLARE @u_cnt INT;
DECLARE @f_yr DATE;
DECLARE @qrt VARCHAR(3);
DECLARE @dnum VARCHAR(5);
SET @u_cnt = 10000;
SET @f_yr = '2002-05-20';
SET @qrt = 'Q2';
SET @dnum = '43234';
SELECT c.GroupLabel AS ORG_Code,
CONVERT (VARCHAR(7), FORMAT((CONVERT(DATE, c.changedate)), 'MM-yyyy')) AS [MONTH],
COUNT(DISTINCT CASE s.TestType
WHEN 'IR' THEN c.changedate
ELSE NULL END) AS TEST_DAYS,
COUNT(DISTINCT c.changedate) AS ALLDAYS,
COUNT(s.Id) AS total,
(CASE WHEN (@u_cnt IS NULL) THEN -1
ELSE @u_cnt
END) AS board_cnt,
FORMAT((COUNT(s.Id) / CASE
WHEN (@u_cnt IS NULL) THEN -1
ELSE @u_cnt
END), 'P0') AS pct_tested_text,
CASE WHEN 100 * (COUNT(s.Id) / CASE
WHEN (@u_cnt IS NULL) THEN -1
ELSE @u_cnt
END) >= 15
AND (COUNT(DISTINCT CASE s.TestType
WHEN 'IR' THEN c.changedate
ELSE NULL END)) >= 4
THEN 'Yes'
ELSE 'NO' END
FROM cforms c
INNER JOIN spitems sp
ON c.Id = s.FormId
WHERE c.Group = 'HR'
AND c.bFlag IS NULL
AND s.Report IN ('P', 'N')
AND CONVERT(VARCHAR(6), c.changedate, 112) IN
(SELECT
CASE
WHEN f.Quarter = 'Q1' THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1) + right('0' + cast(f.FyMonthNumber as varchar(2)))
WHEN f.Quarter = 'ALL' AND f.FyMonth IN ('OCT', 'NOV', 'DEC') THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1, 112) + right('0' + cast(f.FyMonthNumber as varchar(2)))
ELSE CONVERT(VARCHAR(4), YEAR(@f_yr), 112) + right('0' + cast(f.FyMonthNumber as varchar(2)))
END AS FY_MONTH
FROM fis f
WHERE f.Quarter = @qrt)
AND c.GroupLabel = 'Hr' + @dnum
GROUP BY c.GroupLabel, FORMAT((CONVERT(DATE, c.changedate)), 'MM-yyyy')
ORDER BY 1, FORMAT((CONVERT(DATE, c.changedate)), 'MM-yyyy');
尝试改成这样(看第一个转换):
...
AND CONVERT(VARCHAR(7), c.changedate, 120) IN
(SELECT
CASE
WHEN f.Quarter = 'Q1' THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1) + '-' + f.FyMonthNumber
WHEN f.Quarter = 'ALL' AND f.FyMonth IN ('OCT', 'NOV', 'DEC') THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1, 112) + '-' + f.FyMonthNumber
ELSE CONVERT(VARCHAR(4), YEAR(@f_yr), 112) + '-' + f.FyMonthNumber
END AS FY_MONTH
FROM FyQm f
WHERE f.Quarter = @qrt)
...
您转换的是 112 (yyyymm
) 而不是 120 (yyyy-mm
) 并且您的内心 select returns yyyy-mm
我敢打赌不同的列定义
DECLARE @qrt VARCHAR(3);
vs
whatever is FROM FyQm f WHERE f.Quarter = @qrt
'Q2 ' with a blank or null probably does not equal f.Quarter which may be defined as VARCHAR(2)
Perhaps we could try this sql to see that each criterion has some rows
Select
Sum(1) as cntAll
,Sum (CASE When c.Group = 'HR' Then 1 Else 0 End) as cntGroup
,Sum (CASE When c.bFlag IS NULL Then 1 Else 0 End) as cntbFlag
,Sum (CASE When s.Report IN ('P', 'N') Then 1 Else 0 End) as cntsReport
,Sum (CASE When CONVERT(VARCHAR(6), c.changedate, 112)
IN ('200204', '200205', '200206') Then 1 Else 0 End) as cntchangedate
,Sum (CASE When c.GroupLabel = 'Hr43234' Then 1 Else 0 End) as cntGroupLabel
FROM cforms c
INNER JOIN spitems s
ON c.Id = s.FormId
Maybe time to follow @scsimon advice, and add back criteria one at a time and see which one blocks all of the rows
-- WHERE c.Group = 'HR'
-- AND c.bFlag IS NULL
-- AND s.Report IN ('P', 'N')
-- AND CONVERT(VARCHAR(6), c.changedate, 112) IN ('200204', '200205', '200206')
-- AND c.GroupLabel = 'Hr43234'
我已经重新格式化了您的代码并附上备注:
declare @u_cnt int, @f_yr date, @qrt varchar(3), @dnum varchar(5);
select @u_cnt = 10000, @f_yr = '20020520', @qrt = 'Q2', @dnum = '43234';
select c.GroupLabel as ORG_CODE
-- Assuming c.changedate is datetime, otherwise cast(c.changedate as datetime)
, format(c.changedate, 'MM-yyyy') as [MONTH]
, count(distinct case s.TestType when 'IR' then c.changedate else null end) as IR_TEST_DAYS
, count(distinct c.changedate) as TEST_DAYS
, count(s.Id) as TOTAL
, (case when (@u_cnt is null) then - 1 else @u_cnt end) as BOARD_CNT
, format((count(s.Id) /
-- avoiding also division by 0
case when isnull(@u_cnt, 0) = 0
then - 1
else @u_cnt end), 'P0')
as PCT
, case
when 100 * (count(s.Id) /
-- avoiding also division by 0
case when isnull(@u_cnt, 0) = 0
then - 1
else @u_cnt
end) >= 15
and (count(distinct case s.TestType
when 'IR' then c.changedate else null
end)) >= 4
then 'Yes' else 'NO'
end as PCT_TEST_COMP
from cforms c
join spitems s on (c.Id = s.FormId)
where c.group = 'HR'
and c.bFlag is null
and s.Report in ('P', 'N')
and convert(varchar(6), c.changedate, 112) in -- yyyymm (ISO format)
(
select
cast(year(@f_yr) +
case
when f.Quarter = 'Q1'
then (-1)
when f.Quarter = 'ALL'
and f.FyMonthNumber in ('10', '11', '12')
then (-1)
else (0)
end as varchar(4))
+ f.FyMonthNumber -- JAN = '01' or '1' ?
from FyQm f
where f.Quarter = @qrt
)
and c.GroupLabel = 'Hr' + @dnum
group by c.GroupLabel
-- Assuming c.changedate is datetime, otherwise cast(c.changedate as datetime)
, format(c.changedate, 'MM-yyyy')
order by ORG_CODE, [MONTH];
你能检查一下 FyQm.FyMonthNumber 是 varchar(2)
还是 char(2)
并且将一月表示为 '01' 而不是 '1'?
您的主要问题是为什么您没有获取给定查询的数据? 所以你要调试看看问题出在哪里
所以对于给定的参数,
DECLARE @u_cnt INT;
DECLARE @f_yr DATE;
DECLARE @qrt VARCHAR(3);
DECLARE @dnum VARCHAR(5);
SET @u_cnt = 10000;
SET @f_yr = '2002-05-20';
SET @qrt = 'Q2';
SET @dnum = '43234';
所以从基础开始
select *
FROM cforms c
--INNER JOIN spitems sp
--ON c.Id = s.FormId
WHERE c.Group = 'HR'
--AND c.bFlag IS NULL
--AND s.Report IN ('P', 'N')
注意注释部分,它是否是 return 数据,如果是,则取消注释 AND c.bFlag IS NULL
并以这种方式取消注释其他部分。
你确定是INNER JOIN
还是LEFt JOIN
?
将期间子查询放在临时 table 中,虽然这不是主要原因,如果 return 记录较少,那么您也可以使用 CTE,
Create table #tempperiod(period varchar(6))
insert into #tempperiod(period)
select
cast(year(@f_yr) +
case
when f.Quarter = 'Q1'
then (-1)
when f.Quarter = 'ALL'
and f.FyMonthNumber in ('10', '11', '12')
then (-1)
else (0)
end as varchar(4))
+ f.FyMonthNumber
from FyQm f
where f.Quarter = @qrt
-- in order to test,does it return any records,does it return desire output
select * from #tempperiod
- 在谓词中使用的列中检查 space (
LTRIM and RTRIM
)。 - 避免在 case 语句中除以 0
- 如果确实如此,
INNER JOIN
则使用EXISTS
子句,因为您不需要spitems sp
列。 - 什么是
ORDER BY 1
?GroupLabel
?那么您在 Order 子句中不需要它们,因为所有行都是 'HR'+'43234' - 最重要的是,您根本不需要
Order by
,因为Group By
会为您分类,这是唯一的要求。 仔细检查#tempperiod数据,格式是否与
相同CONVERT(VARCHAR(6), c.changedate, 112)
JOIN or/and WHERE 子句可以是一个原因。 以下基本推导方法是找出查询的哪一部分给出这样的结果:
首先,消除所有的 WHERE 子句并检查当前 JOIN 是否可以通过这样设置 WHERE 来 return 行:
WHERE 1 = 1
--AND c.Group = 'HR'
--AND c.bFlag IS NULL
--AND s.Report IN ('P', 'N')
--AND CONVERT(VARCHAR(6), c.changedate, 112) IN
-- (SELECT
-- CASE
-- WHEN f.Quarter = 'Q1' THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1) + f.FyMonthNumber
-- WHEN f.Quarter = 'ALL' AND f.FyMonth IN ('OCT', 'NOV', 'DEC') THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1, 112) + f.FyM
-- ELSE CONVERT(VARCHAR(4), YEAR(@f_yr), 112) + f.FyM
-- END AS FY_MONTH
-- FROM fis f
-- WHERE f.Quarter = @qrt)
--AND c.GroupLabel = 'Hr' + @dnum
然后,逐一取消注释 WHERE 语句以确定哪一个过滤行:
WHERE 1 = 1
AND c.Group = 'HR'
--AND c.bFlag IS NULL
--AND s.Report IN ('P', 'N')
--AND CONVERT(VARCHAR(6), c.changedate, 112) IN
-- (SELECT
-- CASE
-- WHEN f.Quarter = 'Q1' THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1) + f.FyMonthNumber
-- WHEN f.Quarter = 'ALL' AND f.FyMonth IN ('OCT', 'NOV', 'DEC') THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1, 112) + f.FyM
-- ELSE CONVERT(VARCHAR(4), YEAR(@f_yr), 112) + f.FyM
-- END AS FY_MONTH
-- FROM fis f
-- WHERE f.Quarter = @qrt)
--AND c.GroupLabel = 'Hr' + @dnum
然后,再声明:
WHERE 1 = 1
AND c.Group = 'HR'
AND c.bFlag IS NULL
--AND s.Report IN ('P', 'N')
--AND CONVERT(VARCHAR(6), c.changedate, 112) IN
-- (SELECT
-- CASE
-- WHEN f.Quarter = 'Q1' THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1) + f.FyMonthNumber
-- WHEN f.Quarter = 'ALL' AND f.FyMonth IN ('OCT', 'NOV', 'DEC') THEN CONVERT(VARCHAR(4), YEAR(@f_yr) - 1, 112) + f.FyM
-- ELSE CONVERT(VARCHAR(4), YEAR(@f_yr), 112) + f.FyM
-- END AS FY_MONTH
-- FROM fis f
-- WHERE f.Quarter = @qrt)
--AND c.GroupLabel = 'Hr' + @dnum
依此类推,直到进入没有行的地步returned
此技术最终会将您带到过滤掉行的查询的一部分(部分)
如果原始数据集 return 的行数太多,在调试过程中检索所有行可能会很昂贵,所以我建议将它们注释掉并改用 COUNT(*) :
SELECT COUNT(*)
/*
c.GroupLabel AS ORG_Code,
CONVERT (VARCHAR(7), FORMAT((CONVERT(DATE, c.changedate)), 'MM-yyyy')) AS [MONTH],
COUNT(DISTINCT CASE s.TestType
WHEN 'IR' THEN c.changedate
ELSE NULL END) AS TEST_DAYS,
COUNT(DISTINCT c.changedate) AS ALLDAYS,
COUNT(s.Id) AS total,
(CASE WHEN (@u_cnt IS NULL) THEN -1
ELSE @u_cnt
END) AS board_cnt,
FORMAT((COUNT(s.Id) / CASE
WHEN (@u_cnt IS NULL) THEN -1
ELSE @u_cnt
END), 'P0') AS pct_tested_text,
CASE WHEN 100 * (COUNT(s.Id) / CASE
WHEN (@u_cnt IS NULL) THEN -1
ELSE @u_cnt
END) >= 15
AND (COUNT(DISTINCT CASE s.TestType
WHEN 'IR' THEN c.changedate
ELSE NULL END)) >= 4
THEN 'Yes'
ELSE 'NO' END
*/
FROM cforms c