SQL view好像没有完全从原来的数据中抽象出来?

SQL view seems to not completely abstract data from the original?

创建了一个视图来提取数据并在多个报告中使用,vwRPWIP_POST。

SELECT TOP (100) PERCENT 
    Job, MDescription, MWarehouse, MReference, TrnDate
FROM            
    CompanyE.dbo.WipJobPost AS wjp
WHERE
    (Job LIKE '%P') 
    AND (MWarehouse = 'F') 
    AND (TrnDate > DATEADD(DAY, - 395, GETDATE())) 
    AND (LEFT(MReference, 1) LIKE '[0-9]')

它returns预期数据:

问题是当人们在 MReference 列中输入字母字符时,特别是前三个字符,SQL returns 将这些字母字符与 Julian 日期进行比较时出现错误(例如 203)。

MReference 通常包含 Julian 日期和另一个字母指示符,通常看起来像 203-MU,但将继续被允许保留违规数据。当存在违规数据时,这些记录将直接从报告中删除。

使用 T-SQL LEFT,我将 203 与今天的 Julian 日期进行比较,进行计算并根据该结果构建适当记录的报告。有时 MReference 包含“DUMMY”、“SPACERS”、“RED-MU”等字符串。

因此,我使用 WHERE 子句中的最后一个 AND 子句对 vwRPWIP_POST 进行了修改,仅包含 MReference 中第一列为数字的记录。这行得通,当我编辑 SSMS 中的所有行时,只能看到至少第一个字符是数字的记录。

存储过程在这里:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[usp12DAYRESINREPORT]   
    @parFromDate NVARCHAR(5)
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @FromDate NVARCHAR(5),@Locn NVARCHAR(10) = 'PRES';
    SET @FromDate = @parFromDate;

    SELECT DISTINCT 
        A.Job, A.JobDescription, A.QtyToMake, A.JobDeliveryDate,
        A.MDescription, A.MWarehouse, A.MReference, A.HierHead1,
        A.OperCompleted, A.WorkCentre, 
        B.LocnSummed QtyCompleted
    FROM
        (SELECT 
             wm.Job, wm.JobDescription, wm.JobDeliveryDate, wm.QtyToMake,
             wp.MDescription, wp.MWarehouse, wp.MReference, wal.HierHead1
        , wal.OperCompleted, wal.QtyCompleted, wal.WorkCentre
        , LEFT(wm.JOB,7) AS MID7
    FROM
        TablesCoE.dbo.vwRPWIP_POST wp
    INNER JOIN
        (TablesCoE.dbo.vwRPWIP_ALLLAB wal
        INNER JOIN
            TablesCoE.dbo.vwRPWIP_Master wm
        ON
            wal.Job = wm.Job)
    ON 
        wp.Job = wm.Job
    WHERE wp.MWarehouse = 'F'
        AND LEFT(wp.MReference,3) <= @FromDate
        AND wal.OperCompleted <> 'Y'
        AND (wal.WorkCentre = 'PRES'
            OR wal.WorkCentre = 'VPRS')
    )A
INNER JOIN
(
SELECT LEFT(JobRel,6)Job,SUBSTRING(JobRel,8,2)Rel
    ,LocnRecordsAggregatedSummed LocnSummed
FROM
    (
    SELECT JobRel,SUM(LocnRecordsAggregated)LocnRecordsAggregatedSummed
    FROM
        (
        SELECT LEFT(matl_nbr,9)JobRel,LocnRecordsAggregated
        FROM
            (
                SELECT DISTINCT matl_nbr,LocnRecordsAggregated = 1
                FROM mtrk_CompanyE.dbo.trxn_hstd
                WHERE locn_to = @Locn
            )A
        )B
    GROUP BY B.JobRel
    )C
)B
ON
    (LEFT(A.Job,6) = B.Job COLLATE SQL_Latin1_General_CP1_CI_AS
        AND SUBSTRING(A.Job,7,1) = RIGHT(B.Rel COLLATE SQL_Latin1_General_CP1_CI_AS,1))
WHERE
    LocnSummed <> QtyToMake
    --AND LEFT(MReference,3) <= @FromDate - 10;

END

随着视图的更改,第 18 行和第 23 行不再出错,A 的 where 子句中的 38 "AND LEFT(wp.MReference,3) <= @FromDate" 也不再出错。但是当第 68 行取消注释时 SQL 错误:

Msg 245, Level 16, State 1, Procedure usp12DAYRESINREPORT, Line 11 [Batch Start Line 2]
Conversion failed when converting the varchar value 'P ' to data type int.

它在遇到第一个“P”时失败 MReference,这是视图中没有最后一个 AND 子句的数据,因此我可以提取有问题的数据:

usp12DAYRESINREPORT 中的最后一个 AND 子句似乎能够看穿视图并返回原始数据和记录并在那里进行比较!?

我试图在 Access 报告前端进行最后一次比较,但得到的是#Type!使用 VAL() 将 MReference 字段转换为字符串时出现问题。

为什么最后是“AND LEFT(MReference,3) <= @FromDate - 10;”似乎一路回到 WipJobPost?或者这就是它在做什么?

这是一些有好有坏记录的数据

2000410P    2 5/8" TBI-HEAVY                F   DUMMIES     2020-03-11 00:00:00.000
2033480P    2 5/8" TBI-LIGHT                F   DUMMIES     2020-07-09 00:00:00.000
1939490P    2 5/8" TBI-LIGHT                F   DUMIES      2020-05-19 00:00:00.000
1932751P    2 5/8" TBI-LIGHT                F   DUM         2019-07-24 00:00:00.000
C139930P    2 5/8" TBI-HEAVY W/RESIN        F   C139930P    2020-06-10 00:00:00.000
C139930P    3 7/8" TBI-HEAVY W/RESIN        F   C139930P    2020-06-10 00:00:00.000
1901300P    1 3/4" TBI LAP-LIGHT W/RESIN    F   94-L        2020-04-07 00:00:00.000
2070150P    2 5/8" TBI-HEAVY W/RESIN        F   51-P        2020-02-21 00:00:00.000
RD83870P    2 5/8" ALI-LGT W/RESIN          F   365-P       2020-01-02 00:00:00.000
1935170P    2 5/8" TBI-HEAVY W/RESIN        F   365-P       2020-01-02 00:00:00.000
1970701P    2 5/8" TBI-HEAVY W/RESIN        F   365-P       2020-01-02 00:00:00.000
1970701P    2 5/8" TBI-HEAVY W/RESIN        F   365-P       2020-01-02 00:00:00.000

任何帮助或解释将不胜感激。

编辑应用了修复,感谢 David Browne。

记录集显然比视图更抽象。在临时 table 中选择只有 acceptable 记录的记录集可以完成此操作。这是抽象代码:

IF OBJECT_ID('tempdb..#vwRPWIP_POST') IS NOT NULL
    DROP TABLE #vwRPWIP_POST

SELECT * INTO #vwRPWIP_POST
FROM
(
SELECT TOP (100) PERCENT Job, MDescription, MWarehouse, MReference, TrnDate
FROM CompanyE.dbo.WipJobPost AS wjp
WHERE (Job LIKE '%P') 
AND (MWarehouse = 'F') 
AND (TrnDate > DATEADD(DAY, - 395, GETDATE())) 
AND (MReference LIKE '[0-9][0-9][0-9]%')
)A

更新了 FROM 子句:

    FROM
        #vwRPWIP_POST wp

包括临时 table 在 sp 结束时再次删除检查。

您只确保第一个字母是数字,而不是前 3 个 - 这可能是问题所在吗?

而不是

AND (LEFT(MReference, 1) LIKE '[0-9]')

我会使用类似

的东西
AND MReference LIKE '[0-9][0-9][0-9]%'

或者如果它们可能是 1 到 3 位数字,那么我会写一个小的标量值函数来 return '-' 之前的前 1 到 3 位数字的 INT 值和在视图中使用那个。

考虑

with q as
(
SELECT Job, MDescription, MWarehouse, MReference, TrnDate
FROM            
    CompanyE.dbo.WipJobPost AS wjp
WHERE
    (Job LIKE '%P') 
    AND (MWarehouse = 'F') 
    AND (TrnDate > DATEADD(DAY, - 395, GETDATE())) 
    AND (LEFT(MReference, 1) LIKE '[0-9]')
)
select *
from q
where LEFT(MReference,3) <= 100

这与视图类似。 SQL 服务器可以按任何顺序自由处理 WHERE 子句条件,包括在 CTE/Subquery/view.

之前应用来自外部查询的条件

您需要在临时 table 或 table 变量中实现子查询,或者编写可以重新排序的条件,例如:

case when LEFT(MReference, 1) LIKE '[0-9]' then cast(LEFT(MReference,3) as int) else 0 end <= 100

您可以尝试先评估可能的标准,例如

AND  MReference between '000-' and '999-Z'

但这并不能保证。

我会尝试使用这样的函数提取 Julian 日期:

CREATE FUNCTION ExtractJulianDate(@Reference NVARCHAR(MAX))
RETURNS INT
AS
BEGIN
  IF (@Reference IS NULL) RETURN NULL;
  DECLARE @Token AS NVARCHAR(4);
  DECLARE @DelimiterIndex AS INT;
  SET @Token = LEFT(@Reference, 4);
  SET @DelimiterIndex = CHARINDEX('-', @Token, 2)
  -- Hardcoded to remain fast
  IF (@DelimiterIndex < 2) RETURN NULL;
  IF (@DelimiterIndex = 4) BEGIN
    IF (@Token LIKE '[0-9][0-9][0-9]%') RETURN CAST(LEFT(@Token, 3) AS INT);
    RETURN NULL;
  END
  IF (@DelimiterIndex = 3) BEGIN
    IF (@Token LIKE '[0-9][0-9]%') RETURN CAST(LEFT(@Token, 2) AS INT);
    RETURN NULL;
  END
  IF (@DelimiterIndex = 2) BEGIN
    IF (@Token LIKE '[0-9]%') RETURN CAST(LEFT(@Token, 1) AS INT);
  END
  RETURN NULL;
END

用法:

SELECT Job, MDescription, MWarehouse, MReference, dbo.ExtractJulianDate(MReference) AS JulianDate, TrnDate
FROM dbo.WipJobPost AS wjp

测试:

SELECT 123 AS expected, dbo.ExtractJulianDate('123-Foo') AS actual
UNION ALL 
SELECT 12 AS expected, dbo.ExtractJulianDate('12-Foo') AS actual
UNION ALL 
SELECT 1 AS expected, dbo.ExtractJulianDate('1-Foo') AS actual
UNION ALL 
SELECT NULL AS expected, dbo.ExtractJulianDate(NULL) AS actual
UNION ALL 
SELECT NULL AS expected, dbo.ExtractJulianDate('') AS actual
UNION ALL 
SELECT NULL AS expected, dbo.ExtractJulianDate('-5-Foo') AS actual
UNION ALL 
SELECT NULL AS expected, dbo.ExtractJulianDate('123') AS actual
UNION ALL 
SELECT NULL AS expected, dbo.ExtractJulianDate('Foo') AS actual