数据库对象中的封装查询返回的行太少

时间:2015-09-21 08:12:37

标签: sql sql-server

我的团队成员遇到了一些奇怪的行为,可以在开发环境和系统测试环境MS SQL数据库中重新创建。

如果他直接运行此查询,则返回 517行,这是正确的预期结果:

SELECT 
        p.package_id, la.CODE_KID
    FROM package p with (nolock), Strength s with (nolock),
    ProductCODE la  with (nolock), CODE  a with (nolock)
    where p.Strength_ID = s.Strength_ID
    and la.Product_ID = s.Product_ID
    AND la.CODE_KID = a.CODE_ID
    except 
    select p.package_ID, p.CODE_KID from package p

但是,如果他在视图中放置相同的查询,则错误地返回 311行 - 206行,直到他直接运行查询。

如果我们为直接查询和视图查询运行查询分析器,我们会看到两个查询计划完全不同,但我们不明白为什么。

他还尝试将查询转储到临时表中:

insert into MyDB.CODE_PACKAGE
    SELECT 
            p.package_id, la.CODE_KID
        FROM package p with (nolock), Strength s with (nolock),
        ProductCODE la  with (nolock), CODE  a with (nolock)
        where p.Strength_ID = s.Strength_ID
        and la.Product_ID = s.Product_ID
        AND la.CODE_KID = a.CODE_ID
        except 
        select p.package_ID, p.CODE_KID from package p

,正确创建一个 517行的表格。但是,如果他在存储过程中放入相同的SQL,则会错误地返回 311行

似乎一旦查询被封装在数据库对象中,它就会返回太少的行。

如上所述,他也在其他数据库系统上重新创建了错误。

任何想法会导致这种奇怪的行为?

他也试过以下内容但没有取得任何成功:

  • 删除nolock
  • 将事务隔离级别设置为read uncommitted

更新

我不确定是否使用SSMS向导或模板来创建视图,但如果我选择“脚本视图为 - >创建到 - >新查询编辑器窗口”,那么这就是输出:

USE [TestUtv]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE view [MyDBviews].[CODE_PACKAGE]
as

    SELECT 
            p.package_id, la.CODE_KID
        FROM package p with (nolock), Strength s with (nolock),
        ProductCODE la  with (nolock), CODE  a with (nolock)
        where p.Strength_ID = s.Strength_ID
        and la.Product_ID = s.Product_ID
        AND la.CODE_KID = a.CODE_ID
        except 
        select p.package_ID, p.CODE_KID from package p

GO

这是其中一个使用的表,不幸的是,数据库非常庞大,有数百个表和视图,所以我不能在这里发布所有内容。

CREATE TABLE [dbo].[Package](
    [Package_ID] [uniqueidentifier] NOT NULL,
    [Multiple] [int] NULL,
    [Multiple2] [int] NULL,
    [OutProdnum] [varchar](6) NULL,
    [OutProdnumDate] [datetime] NULL,
    [zzzPackage_KID] [uniqueidentifier] NULL,
    [Strength_ID] [uniqueidentifier] NULL,
    [Indi] [varchar](4096) NULL,
    [CreatedDate] [datetime] NULL,
    [CreatedBy] [varchar](255) NULL,
    [LastChangedDate] [datetime] NULL,
    [LastChangedBy] [varchar](255) NULL,
    [CODE_KID] [uniqueidentifier] NULL,
    [MarkDate] [datetime] NULL,
    [Amount] [int] NULL,
    [KIPackage_ID] [uniqueidentifier] NULL,
    [xyz] [bit] NULL,
    [Ean] [varchar](255) NULL,
    [D_ID] [uniqueidentifier] NULL,
    [abc_ID] [uniqueidentifier] NULL,
    [DDD] [decimal](18, 4) NULL,
    [era_KID] [uniqueidentifier] NULL,
    [uuu] [decimal](18, 4) NULL,
    [ueer_KID] [uniqueidentifier] NULL,
    [abcIdString] [varchar](4095) NULL,
    [ExternalId] [varchar](255) NULL,
    [Dpack_KID] [uniqueidentifier] NULL,
    [tttpacks_KID] [uniqueidentifier] NULL,
 CONSTRAINT [Package_PK] PRIMARY KEY CLUSTERED 
(
    [Package_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

4 个答案:

答案 0 :(得分:1)

尝试在SP和/或函数中填充查询并比较返回的记录数。 您看到的内容可能会受到连接ANSI设置的影响。 SSMS和SQL Server默认在每个连接上设置一些,而像视图这样的对象在创建时设置它们并在执行时保持不变。 检查当前为会话启用的选项: https://www.mssqltips.com/sqlservertip/1415/determining-set-options-for-a-current-session-in-sql-server/
检查视图中保留的选项:

SELECT * FROM sys.sql_modules

答案 1 :(得分:0)

使用JOIN语句尝试相同的查询。对于使用此旧连接技术的查询,您最终可能会得到不同查询计划的不同结果。

SELECT 
    p.package_id, 
    la.CODE_KID
FROM package p with (nolock)
INNER JOIN Strength s with (nolock)
    ON p.Strength_ID = s.Strength_ID
INNER JOIN ProductCODE la with (nolock)
    ON la.Product_ID = s.Product_ID
INNER JOIN CODE a with (nolock)
    ON la.CODE_KID = a.CODE_ID
EXCEPT
SELECT 
    p.package_ID, 
    p.CODE_KID 
FROM package p

答案 2 :(得分:0)

我建议您尝试完成以下语法。我的猜测是在创建存储过程时以某种方式使用中断的旧ANSI JOIN语法。

SELECT 
    p.package_id 
    ,la.CODE_KID
FROM package AS p
JOIN Strength AS s ON p.Strength_ID = s.Strength_ID
JOIN ProductCODE AS la ON la.Product_ID = s.Product_ID
JOIN CODE AS a ON la.CODE_KID = a.CODE_ID
EXCEPT 
SELECT p.package_ID, p.CODE_KID from package p

答案 3 :(得分:0)

真正的问题是,如果将查询封装到视图中,哪些recods会被过滤掉?

所以,正如@Alex之前建议的那样,您应该比较查询中的结果和视图中的相同查询。

SSMS中的

尝试类似:

SELECT *
FROM (
    SELECT p.package_id, la.CODE_KID
    FROM package p with (nolock), Strength s with (nolock),
    ProductCODE la  with (nolock), CODE  a with (nolock)
    where p.Strength_ID = s.Strength_ID
    and la.Product_ID = s.Product_ID
    AND la.CODE_KID = a.CODE_ID
    except 
    select p.package_ID, p.CODE_KID from package p
    ) AS DIRECT_Q
FULL JOIN
    (
    SELECT *
    FROM YOUR_VIEW_CREATED_FROM_QUERY    /* <-- THE NAME OF YOUR VIEW */
    ) AS VIEWED_Q
ON DIRECT_Q.package_id=VIEWED_Q.package_id 
   AND DIRECT_Q.CODE_KID=VIEWED_Q.CODE_KID

通过这种方式,您将看到哪些记录丢失并尝试了解原因(空值,重音符号,特定字符ecc ecc)

我还会检查package.CODE_KID和ProductCODE.CODE_KID的数据类型排序规则是否相同。