0

我正在为下面的报告编写一个复杂的视图:

SELECT     TOP (100) PERCENT dbo.tbl_SFCWRK_SQL_NF.ID, dbo.tbl_SFCWRK_SQL_NF.STD_LBR_HRS, dbo.tbl_SFCWRK_SQL_NF.CUSTNAME, 
                  dbo.tbl_SFCWRK_SQL_NF.JOBNBR, CASE WHEN dbo.tbl_SFCWRK_SQL_NF.COMPQTY IS NULL THEN 0 ELSE CONVERT(decimal(10, 5), 
                  dbo.tbl_SFCWRK_SQL_NF.COMPQTY) END AS COMPQTY, CASE WHEN dbo.tbl_SFCWRK_SQL_NF.ORDQTY IS NULL THEN 0 ELSE CONVERT(decimal(10, 5), 
                  dbo.tbl_SFCWRK_SQL_NF.ORDQTY) END AS ORDQTY, dbo.tbl_SFCWRK_SQL_NF.PLAN_CD, dbo.tbl_SFCWRK_SQL_NF.PLANQTY, 
                  dbo.tbl_SFCWRK_SQL_NF.ITEMNBR, dbo.tbl_ITEMMAST_NF.ITEM_NBR, dbo.tbl_SFCWRK_SQL_NF.WODUEDT, tbl_WORK_CENTR_NF.WRK_CENTER_DESC, 
                  tbl_WORK_CENTR_NF.LABOR_CAPACITY, dbo.tbl_SFCWRK_SQL_NF.STD_SETUP_HRS, dbo.tbl_WIPOPER_NF.STD_LBR_HOURS, 
                  dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE, dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR, dbo.tbl_WIPOPER_NF.OPER_STATUS, 
                  dbo.tbl_WIPOPER_NF.OPERATION_NBR, tbl_WORK_CENTR_NF.WAREHOUSE, 
                  CASE WHEN dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20005' THEN 1 WHEN dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20010' THEN 2 WHEN dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR
                   = '20020' THEN 3 WHEN dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20030' THEN 4 WHEN dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20040' THEN 5 WHEN
                   dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20050' THEN 6 WHEN dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20110' THEN 7 ELSE dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR
                   END AS WCOrder, DATEADD(dd, 7 - DATEPART(dw, dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE), dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE) AS WeekEnd, 
                  DATEPART(wk, dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE) AS WkNum, 
                  CASE WHEN dbo.tbl_SFCWRK_SQL_NF.COMPQTY <> 0 THEN ((dbo.tbl_SFCWRK_SQL_NF.STD_LBR_HRS / dbo.tbl_SFCWRK_SQL_NF.ORDQTY) 
                  * (dbo.tbl_SFCWRK_SQL_NF.ORDQTY - dbo.tbl_SFCWRK_SQL_NF.COMPQTY)) 
                  * 2 ELSE ((dbo.tbl_SFCWRK_SQL_NF.STD_LBR_HRS / dbo.tbl_SFCWRK_SQL_NF.ORDQTY) * (dbo.tbl_SFCWRK_SQL_NF.ORDQTY)) * 2 END AS RmnLabor, 
                  CASE WHEN dbo.tbl_SFCWRK_SQL_NF.COMPQTY <> 0 THEN ((dbo.tbl_SFCWRK_SQL_NF.STD_SETUP_HRS / tbl_SFCWRK_SQL_NF.ORDQTY) 
                  * (dbo.tbl_SFCWRK_SQL_NF.ORDQTY - dbo.tbl_SFCWRK_SQL_NF.COMPQTY)) 
                  / 100 ELSE ((dbo.tbl_SFCWRK_SQL_NF.STD_SETUP_HRS / dbo.tbl_SFCWRK_SQL_NF.ORDQTY) * (dbo.tbl_SFCWRK_SQL_NF.ORDQTY)) 
                  / 100 END AS RmnSetup
FROM         dbo.tbl_ITEMMAST_NF INNER JOIN
                  dbo.tbl_SFCWRK_SQL_NF ON dbo.tbl_ITEMMAST_NF.CPN =  dbo.tbl_SFCWRK_SQL_NF.CPN_NO INNER JOIN
                  dbo.tbl_WORK_CENTR_NF AS tbl_WORK_CENTR_NF ON dbo.tbl_SFCWRK_SQL_NF.WC_NBR = tbl_WORK_CENTR_NF.ID INNER JOIN
                  dbo.tbl_WIPOPER_NF ON dbo.tbl_SFCWRK_SQL_NF.ID = dbo.tbl_WIPOPER_NF.ID
WHERE     (dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE <= DATEADD(m, 2, GETDATE())) AND (dbo.tbl_WIPOPER_NF.OPER_STATUS <> 'C' OR
                  dbo.tbl_WIPOPER_NF.OPER_STATUS IS NULL OR
                  dbo.tbl_WIPOPER_NF.OPER_STATUS = '') AND (tbl_WORK_CENTR_NF.WAREHOUSE = '02') AND (dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR IN ('20005', '20010', 
                  '20020', '20030', '20040', '20060', '20110')) AND (NOT (dbo.tbl_ITEMMAST_NF.ITEM_NBR LIKE 'A%')) AND (CASE WHEN tbl_SFCWRK_SQL_NF.ORDQTY IS NULL 
                  THEN 0 ELSE CONVERT(decimal(10, 5), tbl_SFCWRK_SQL_NF.ORDQTY) END <> 0) AND (CASE WHEN tbl_SFCWRK_SQL_NF.ORDQTY IS NULL 
                  THEN 0 ELSE CONVERT(decimal(10, 5), tbl_SFCWRK_SQL_NF.ORDQTY) END <> 0)
ORDER BY dbo.tbl_SFCWRK_SQL_NF.WODUEDT DESC

我想让这个运行更有效率。我也很好奇我正在做的是否是编写视图的正确方法以及是否应该重构它......??

瑞安

4

3 回答 3

2

这对我来说毫无意义

where      
(CASE 
      WHEN tbl_SFCWRK_SQL_NF.ORDQTY IS NULL THEN 0 
      ELSE CONVERT(decimal(10, 5), tbl_SFCWRK_SQL_NF.ORDQTY) END 
       <> 0)

如果为空,则返回假。
但是任何与 null 的比较都会返回 false。

它必须是数字类型才能成功转换为十进制。
与任何数字类型 <> 0 相同。

很确定可以减少到

where tbl_SFCWRK_SQL_NF.ORDQTY <> 0

使用您的语法,您可以取消在该列上使用索引

<> 'c' or = '' 也是多余的

看到评论说 tbl_SFCWRK_SQL_NF.ORDQTY 是 varchar。
那只是一团糟。
如果任何 varchar 值不是十进制,则该转换将失败。
我只是假设它必须是某种类型的数字。

于 2013-08-01T15:41:36.513 回答
1

首先,最佳实践views是不包含ORDER BY. 所以去掉TOP (100) PERCENTandORDER BY dbo.tbl_SFCWRK_SQL_NF.WODUEDT DESC语句。接下来格式化您的查询,使其易于阅读。我在下面做了这个,但如果你有不同的格式,你更喜欢使用它。这一切都是为了让你和你的队友/最终替换它可读。

格式化后,我可以告诉你,你应该检查以下索引。

  • tbl_ITEMMAST_NF(CPN,ITEM_NBR)
  • tbl_SFCWRK_SQL_NF(CPN_NO,WC_NBR,ID,ORDQTY)
  • tbl_WIPOPER_NF(ID,SCHED_COMP_DATE,OPER_STATUS)

这些是基于您在JOINs 和WHERE子句中使用的列的起始位置。它们可能不是最佳的,但可能总比没有好。您还可以检查执行计划并查看优化器是否提出建议。如果它确实检查了您现有的索引并查看它是否适合它们,如果适合,则添加它。如果不是,则可以修改您现有的索引之一以涵盖它所要求的内容。

例如,假设您创建了上面的索引,但优化器需要以下索引。

tbl_WIPOPER_NF(ID, SCHED_COMP_DATE, OPER_STATUS) INCLUDE WORK_CENTER_NBR

不要只是添加新索引。修改旧的以包含INCLUDEed 列。或者优化器可能希望您更改索引中列的顺序。如果这是您使用该索引的唯一地方(您添加它是因为我建议它)然后修改它。不要添加新的。与您已有的索引相比,我上面的建议也是如此。

至于查询本身。看起来不错。还有一些其他的方法来处理事情,例如在子句中使用ISNULL而不是你CASE的语句WHERE。但是你拥有它的方式应该可以正常工作。

SELECT --TOP (100) PERCENT 
    dbo.tbl_SFCWRK_SQL_NF.ID, dbo.tbl_SFCWRK_SQL_NF.STD_LBR_HRS, 
    dbo.tbl_SFCWRK_SQL_NF.CUSTNAME, dbo.tbl_SFCWRK_SQL_NF.JOBNBR, 
    CASE WHEN dbo.tbl_SFCWRK_SQL_NF.COMPQTY IS NULL THEN 0 
        ELSE CONVERT(decimal(10, 5), dbo.tbl_SFCWRK_SQL_NF.COMPQTY) END AS COMPQTY, 
    CASE WHEN dbo.tbl_SFCWRK_SQL_NF.ORDQTY IS NULL THEN 0 
        ELSE CONVERT(decimal(10, 5), dbo.tbl_SFCWRK_SQL_NF.ORDQTY) END AS ORDQTY, 
    dbo.tbl_SFCWRK_SQL_NF.PLAN_CD, dbo.tbl_SFCWRK_SQL_NF.PLANQTY, 
    dbo.tbl_SFCWRK_SQL_NF.ITEMNBR, dbo.tbl_ITEMMAST_NF.ITEM_NBR, 
    dbo.tbl_SFCWRK_SQL_NF.WODUEDT, tbl_WORK_CENTR_NF.WRK_CENTER_DESC, 
    tbl_WORK_CENTR_NF.LABOR_CAPACITY, dbo.tbl_SFCWRK_SQL_NF.STD_SETUP_HRS, 
    dbo.tbl_WIPOPER_NF.STD_LBR_HOURS, dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE, 
    dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR, dbo.tbl_WIPOPER_NF.OPER_STATUS, 
    dbo.tbl_WIPOPER_NF.OPERATION_NBR, tbl_WORK_CENTR_NF.WAREHOUSE, 
    CASE WHEN dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20005' THEN 1 
        WHEN dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20010' THEN 2 
        WHEN dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20020' THEN 3 
        WHEN dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20030' THEN 4 
        WHEN dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20040' THEN 5 
        WHEN dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20050' THEN 6 
        WHEN dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20110' THEN 7 
        ELSE dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR END AS WCOrder, 
    DATEADD(dd, 7 - DATEPART(dw, dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE), 
    dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE) AS WeekEnd, DATEPART(wk, dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE) AS WkNum, 
    CASE WHEN dbo.tbl_SFCWRK_SQL_NF.COMPQTY <> 0 
        THEN ((dbo.tbl_SFCWRK_SQL_NF.STD_LBR_HRS / dbo.tbl_SFCWRK_SQL_NF.ORDQTY) *
            (dbo.tbl_SFCWRK_SQL_NF.ORDQTY - dbo.tbl_SFCWRK_SQL_NF.COMPQTY)) * 2 
        ELSE ((dbo.tbl_SFCWRK_SQL_NF.STD_LBR_HRS / dbo.tbl_SFCWRK_SQL_NF.ORDQTY) * 
            (dbo.tbl_SFCWRK_SQL_NF.ORDQTY)) * 2 END AS RmnLabor, 
    CASE WHEN dbo.tbl_SFCWRK_SQL_NF.COMPQTY <> 0 
        THEN ((dbo.tbl_SFCWRK_SQL_NF.STD_SETUP_HRS / tbl_SFCWRK_SQL_NF.ORDQTY) * 
            (dbo.tbl_SFCWRK_SQL_NF.ORDQTY - dbo.tbl_SFCWRK_SQL_NF.COMPQTY)) / 100 
        ELSE ((dbo.tbl_SFCWRK_SQL_NF.STD_SETUP_HRS / dbo.tbl_SFCWRK_SQL_NF.ORDQTY) * 
            (dbo.tbl_SFCWRK_SQL_NF.ORDQTY)) / 100 END AS RmnSetup
FROM dbo.tbl_ITEMMAST_NF 
INNER JOIN dbo.tbl_SFCWRK_SQL_NF 
    ON dbo.tbl_ITEMMAST_NF.CPN =  dbo.tbl_SFCWRK_SQL_NF.CPN_NO 
INNER JOIN dbo.tbl_WORK_CENTR_NF AS tbl_WORK_CENTR_NF 
    ON dbo.tbl_SFCWRK_SQL_NF.WC_NBR = tbl_WORK_CENTR_NF.ID 
INNER JOIN dbo.tbl_WIPOPER_NF 
    ON dbo.tbl_SFCWRK_SQL_NF.ID = dbo.tbl_WIPOPER_NF.ID
WHERE (dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE <= DATEADD(m, 2, GETDATE())) 
  AND (dbo.tbl_WIPOPER_NF.OPER_STATUS <> 'C' OR
        dbo.tbl_WIPOPER_NF.OPER_STATUS IS NULL OR
        dbo.tbl_WIPOPER_NF.OPER_STATUS = '') 
  AND (tbl_WORK_CENTR_NF.WAREHOUSE = '02') 
  AND (dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR IN ('20005', '20010', '20020', '20030', 
                                                '20040', '20060', '20110')) 
  AND (NOT (dbo.tbl_ITEMMAST_NF.ITEM_NBR LIKE 'A%')) 
  AND (CASE WHEN tbl_SFCWRK_SQL_NF.ORDQTY IS NULL THEN 0 
        ELSE CONVERT(decimal(10, 5), tbl_SFCWRK_SQL_NF.ORDQTY) END <> 0) 
  AND (CASE WHEN tbl_SFCWRK_SQL_NF.ORDQTY IS NULL THEN 0 
        ELSE CONVERT(decimal(10, 5), tbl_SFCWRK_SQL_NF.ORDQTY) END <> 0)
--ORDER BY dbo.tbl_SFCWRK_SQL_NF.WODUEDT DESC
于 2013-08-01T15:41:45.233 回答
1

我对查询进行了一些小的更新和格式化,这可能会有所帮助;IS NULL通过使用COALESCE而不是 withCASE语句来检查和清空字符串。详情见下文。我不确定这些是否会影响性能,但您可以尝试一下。

请注意,您的最后一个标准被列出了两次。我不确定这是否是故意的,或者它是否会对性能产生影响。让我知道。如果没有,那么我将删除此答案。

SELECT
    dbo.tbl_SFCWRK_SQL_NF.ID,
    dbo.tbl_SFCWRK_SQL_NF.STD_LBR_HRS,
    dbo.tbl_SFCWRK_SQL_NF.CUSTNAME,
    dbo.tbl_SFCWRK_SQL_NF.JOBNBR,
    --CASE WHEN dbo.tbl_SFCWRK_SQL_NF.COMPQTY IS NULL THEN 0 ELSE CONVERT(decimal(10,   5), dbo.tbl_SFCWRK_SQL_NF.COMPQTY) END AS COMPQTY,
    COALESCE(CONVERT(decimal(10, 5), dbo.tbl_SFCWRK_SQL_NF.COMPQTY), 0) AS COMPQTY
    --CASE WHEN dbo.tbl_SFCWRK_SQL_NF.ORDQTY IS NULL THEN 0 ELSE CONVERT(decimal(10,    5), dbo.tbl_SFCWRK_SQL_NF.ORDQTY) END AS ORDQTY,
    COALESCE(CONVERT(decimal(10, 5), dbo.tbl_SFCWRK_SQL_NF.ORDQTY), 0) AS ORDQTY
    dbo.tbl_SFCWRK_SQL_NF.PLAN_CD,
    dbo.tbl_SFCWRK_SQL_NF.PLANQTY,
    dbo.tbl_SFCWRK_SQL_NF.ITEMNBR,
    dbo.tbl_ITEMMAST_NF.ITEM_NBR,
    dbo.tbl_SFCWRK_SQL_NF.WODUEDT,
    tbl_WORK_CENTR_NF.WRK_CENTER_DESC,
    tbl_WORK_CENTR_NF.LABOR_CAPACITY,
    dbo.tbl_SFCWRK_SQL_NF.STD_SETUP_HRS,
    dbo.tbl_WIPOPER_NF.STD_LBR_HOURS,
    dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE,
    dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR,
    dbo.tbl_WIPOPER_NF.OPER_STATUS,
    dbo.tbl_WIPOPER_NF.OPERATION_NBR,
    tbl_WORK_CENTR_NF.WAREHOUSE,
    CASE
        WHEN
            dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20005'
        THEN
            1
        WHEN
            dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20010'
        THEN
            2
        WHEN
            dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR  = '20020'
        THEN
            3
        WHEN
            dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20030'
        THEN
            4
        WHEN
            dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20040'
        THEN
            5
        WHEN
            dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20050'
        THEN
            6
        WHEN
            dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20110'
        THEN
            7
        ELSE
            dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR
        END
            AS WCOrder,
    DATEADD(dd, 7 - DATEPART(dw, dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE), dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE) AS WeekEnd,
    DATEPART(wk, dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE) AS WkNum,
    CASE
        WHEN
            dbo.tbl_SFCWRK_SQL_NF.COMPQTY <> 0
        THEN
            ((dbo.tbl_SFCWRK_SQL_NF.STD_LBR_HRS / dbo.tbl_SFCWRK_SQL_NF.ORDQTY) * (dbo.tbl_SFCWRK_SQL_NF.ORDQTY - dbo.tbl_SFCWRK_SQL_NF.COMPQTY)) * 2
        ELSE
            ((dbo.tbl_SFCWRK_SQL_NF.STD_LBR_HRS / dbo.tbl_SFCWRK_SQL_NF.ORDQTY) * (dbo.tbl_SFCWRK_SQL_NF.ORDQTY)) * 2
        END AS RmnLabor,
    CASE
        WHEN
            dbo.tbl_SFCWRK_SQL_NF.COMPQTY <> 0
        THEN
            ((dbo.tbl_SFCWRK_SQL_NF.STD_SETUP_HRS / tbl_SFCWRK_SQL_NF.ORDQTY) * (dbo.tbl_SFCWRK_SQL_NF.ORDQTY - dbo.tbl_SFCWRK_SQL_NF.COMPQTY)) / 100
        ELSE
            ((dbo.tbl_SFCWRK_SQL_NF.STD_SETUP_HRS / dbo.tbl_SFCWRK_SQL_NF.ORDQTY) * (dbo.tbl_SFCWRK_SQL_NF.ORDQTY)) / 100
        END AS RmnSetup
FROM
    dbo.tbl_ITEMMAST_NF INNER JOIN dbo.tbl_SFCWRK_SQL_NF
        ON
            dbo.tbl_ITEMMAST_NF.CPN = dbo.tbl_SFCWRK_SQL_NF.CPN_NO INNER JOIN dbo.tbl_WORK_CENTR_NF AS tbl_WORK_CENTR_NF
                ON
                    dbo.tbl_SFCWRK_SQL_NF.WC_NBR = tbl_WORK_CENTR_NF.ID INNER JOIN dbo.tbl_WIPOPER_NF
                        ON
                            dbo.tbl_SFCWRK_SQL_NF.ID = dbo.tbl_WIPOPER_NF.ID
WHERE
    dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE <= DATEADD(m, 2, GETDATE())
        AND
    (
        dbo.tbl_WIPOPER_NF.OPER_STATUS <> 'C'
            OR
        --dbo.tbl_WIPOPER_NF.OPER_STATUS IS NULL OR dbo.tbl_WIPOPER_NF.OPER_STATUS = ''
        --Replace the above statement with the following...
        COALESCE(dbo.tbl_WIPOPER_NF.OPER_STATUS, N'') = N''
    )
        AND
    tbl_WORK_CENTR_NF.WAREHOUSE = '02'
        AND
    dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR IN ('20005', '20010', '20020', '20030', '20040', '20060','20110')
        AND
    dbo.tbl_ITEMMAST_NF.ITEM_NBR NOT LIKE 'A%'
        AND
    --CASE WHEN tbl_SFCWRK_SQL_NF.ORDQTY IS NULL THEN 0 ELSE CONVERT(decimal(10, 5), tbl_SFCWRK_SQL_NF.ORDQTY) END <> 0
    --I would change the above statement to this...
    COALESCE(tbl_SFCWRK_SQL_NF.ORDQTY, 0) <> 0

        --AND
    --CASE WHEN tbl_SFCWRK_SQL_NF.ORDQTY IS NULL THEN 0 ELSE CONVERT(decimal(10, 5), tbl_SFCWRK_SQL_NF.ORDQTY) END <> 0
    --The above statement is a duplicate!
ORDER BY
    dbo.tbl_SFCWRK_SQL_NF.WODUEDT DESC
于 2013-08-01T15:50:09.980 回答