【问题标题】:What can I use in a SQL query to help me determine why my query is not returning any data results我可以在 SQL 查询中使用什么来帮助我确定查询未返回任何数据结果的原因
【发布时间】:2019-01-16 16:35:14
【问题描述】:

有人可以帮助我解决我的 SQL 查询问题,以了解为什么它没有返回任何结果,只返回列别名?

我已将其分解,显然组合在一起的所有部分分别返回预期数据。感谢您提前提供任何指导/帮助。以下是我的脚本:

...

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');

【问题讨论】:

  • INNER JOINWHERE 将限制记录返回。我怀疑问题出在AND CONVERT(VARCHAR(6), c.changedate, 112) 部分。它很复杂,并且在格式化中实现了某种时间逻辑。我敢打赌它不会像你期望的那样工作。尝试在 IN 部分为初学者硬编码一些值。
  • 这就是 CTE 的力量所在。不是技术处理能力,而是开发人员的可读性能力。创建平面数据的 CTE(即没有 GROUP BY),应用您的 CASE 语句并提取 MONTH 和 YEAR 的 DATEPART,给字段名称起别名等。然后,当所有丑陋的工作完成后,从该 CTE 中选择聚合.

标签: sql-server sql-server-2016 ssms-2016


【解决方案1】:

可能会限制您的数据的所有内容都在下面代码的这一部分中。我把它拆开,并在 whywhere 它们受到限制时添加了 cmets。我认为你的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 语句,因为它没有连字符。首先要更改的是从字符串连接中删除连字符。在您编辑过的帖子中,您已经做到了,非常干得好。接下来,问题可能是当您尝试将您的+f.FyMonthNumber 组合时,它没有被视为加法而不是串联。如果f.FyMonthNumberint,那么它将添加它。

DECLARE @f_yr DATE;
SET @f_yr = '2002-05-20';

SELECT CONVERT(VARCHAR(4), YEAR(@f_yr) - 1) + 02

在这里,您希望它返回 200102,但它返回 2003,因为它正在执行加法。您可以将其转换为 varcharchar 来解决此问题。

SELECT CONVERT(VARCHAR(4), YEAR(@f_yr) - 1) + cast('02' as varchar)

最后,您可能遇到的一个问题是,如果f.FyMonthNumber 存储为int,它将没有前导零。因此,对于 1 月,它将表示为 1 而不是 01,这也将在 10 月之前的任何月份返回零行。您可以使用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');

【讨论】:

  • 我对您指出的那些区域进行了更改,但仍然没有结果。这真的难倒我......
  • 嗯,这是我指出的领域之一。没有其他地方可以过滤。全部删除,然后一一添加,直到找到罪魁祸首
  • @suffa 我对我的帖子进行了编辑。从 EDIT 向下阅读,如果您有任何问题,请告诉我。
【解决方案2】:

尝试改成这个(看看第一个转换):

...
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) 并且您的内部选择返回 yyyy-mm

【讨论】:

  • 我会再试一次。在上面添加时,我可能在发布时复制和粘贴错误。但是,我小心翼翼地注意这一点(格式化)。我已经更改了无数次,尽一切努力返回数据。
  • 下一次尝试进一步回答
【解决方案3】:

JOIN 或/和 WHERE 子句可能是一个原因。 以下基本推导方法是找出查询的哪一部分给出了这样的结果:

首先,去掉所有的 WHERE 子句,检查当前的 JOIN 是否可以通过设置 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 语句一一取消注释,以确定哪个过滤行:

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

以此类推,直到您进入没有返回行的地步

这种技术最终会带您进入查询的一部分(部分),它会过滤掉行

如果原始数据集返回的行数过多,则在调试期间检索所有行可能会很昂贵,因此我建议将它们注释掉并改用 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 

【讨论】:

    【解决方案4】:

    我已经用备注重新格式化了您的代码:

    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.FyMonthNumbervarchar(2) 还是 char(2) 并且将一月表示为 '01' 而不是 '1' >?

    【讨论】:

    • 它产生的结果与我得到的结果相同:没有数据!这很奇怪;单独运行时,转换块按预期工作。
    【解决方案5】:

    您的主要问题是为什么您没有获取给定查询的数据? 所以你要调试并检查问题出在哪里。

    所以对于给定的参数,

    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')
    

    注意 cmets 部分,它是否返回数据,如果是,则取消注释 AND c.bFlag IS NULL 并且这样取消其他部分。

    您确定是INNER JOINLEFt JOIN 吗?

    将周期子查询放在临时表中,虽然这不是主要原因,如果它返回的记录较少,那么你也可以使用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
    
    1. 检查用于谓词的列中的空格 (LTRIM and RTRIM)。
    2. 在你的case语句中避免被0除
    3. 如果是真的,INNER JOIN 然后使用EXISTS 子句因为你不需要spitems sp 列。
    4. ORDER BY 1 是什么? GroupLabel ?那么您在 Order 子句中不需要它们,因为所有行都是 'HR'+'43234'
    5. 最重要的是,您根本不需要Order by,因为Group By 会为您排序,这是唯一的要求。
    6. 彻底检查#tempperiod数据,格式是否与

      CONVERT(VARCHAR(6), c.changedate, 112)

    【讨论】:

      【解决方案6】:

      我赌的是不同的列定义

      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)
      

      也许我们可以试试这个 sql 看看每个条件都有一些行

      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
      

      也许是时候遵循@scsimon 的建议了,一次添加一个条件,看看哪个会阻塞所有行

      --  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'
      

      【讨论】:

      • 在Schema中,f.Quarter被定义为varchar(3),而不是null
      • 您可以尝试在脚本中添加尾随空白 SET @qrt = 'Q2';
      • 谢谢。我还注意到有时 HR 是全部大写,有时 Hr 是上限和更低。那是对的吗?另外,内部 Select... From FY 的行数(和一些样本数据)是多少?当仅该部分单独运行时。
      • 啊哈。 AND CONVERT(VARCHAR(6), c.changedate, 112) IN 给出 YYYYMM。但是内部选择提供带有连字符的 YYYY-MM。因此,在里面没有找到。
      • 返回一年中的特定季度 Q1,Q2...(以 3 个月表示:例如 Q1= 01/2002, 02/ 2002, 03/2002)
      猜你喜欢
      • 1970-01-01
      • 2011-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-30
      • 1970-01-01
      相关资源
      最近更新 更多