[英]Encapsulated query within a database object returns too few rows
我的團隊成員已經獲得了一些奇怪的行為,可以在開發環境和系統測試環境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
更新
我不確定是否使用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]
嘗試在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
使用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
我建議您嘗試完成以下語法。 我的猜測是在創建存儲過程時以某種方式使用中斷的舊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
真正的問題是,如果將查詢封裝到視圖中,哪些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的數據類型和排序規則是否相同。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.