私は「偶然の」DBAであり、比較的経験が浅く、この問題に困惑しています。
MS SQL Server 2012を実行しています。問題は次のUPDATEステートメントにあります。
UPDATE dbo.tAccts SET
Ticket = 'ARP.ExGE'
, Method = 'smtp'
, AcctOwner = 'r00417819'
, DisplayName = '~AppLight HBSFax-Inactive'
, Destination = '[email protected]'
, UpdatedBy = SYSTEM_USER
, UpdatedOn = CAST(GetDate() AS DATE)
FROM dbo.vReclaimable
WHERE OHR_EmpStatus <> 'A'
どのすべき更新のみ vReclaimableビューによって返されるtAcctsテーブルの行。
VReclaimableビューはtAcctsテーブルに基づいており、tAcctsの行のサブセットを返します。
実行すると、一意のキーエラーで失敗します。
(0 row(s) affected)
Msg 2627, Level 14, State 1, Line 67
Violation of UNIQUE KEY constraint 'UQ__tAccounts_DNIS.Method.Destination.Phones'. Cannot insert duplicate key in object 'dbo.tAccts'. The duplicate key value is (68497, smtp, [email protected], 800-905-8793, none).
The statement has been terminated.
十分に公平ですが、tAcctsテーブルには一意のキー制約があります。
CONSTRAINT [UQ__tAccounts_DNIS.Method.Destination.Phones] UNIQUE NONCLUSTERED
(
[DNIS] ASC,[Method] ASC,[Destination] ASC,[Phone_TF] ASC,[Phone_Local] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
しかし、これは奇妙なことです。これら2つのクエリを実行すると:
select 'tAccts table', dnis, method, destination, phone_tf, phone_local from tAccts where dnis=68497
select 'vReclaimable view', dnis, method, destination, phone_tf, phone_local, daysidle from vReclaimable where dnis=68497
最初は2つの行を返します(期待どおり)。
(No column name) dnis method destination phone_tf phone_local
tAccts table 68497 ftp ftp://faxuser@ap1plm02cige/appliances 800-905-8793 none
tAccts table 68497 unc \\\\for4as01applge\\cfs_portfolio\\cfs_faxdocs 800-905-8793 none
2番目は(期待どおり)0行を返します。
「FROM vReclaimable WHERE OHR_EmpStatus <> ‘A’」が0行を返す場合、UPDATEがDNIS = 68497の行を更新しようとするのはなぜですか?
(私はこれを適切に説明したことを願っています。明らかな何かが欠けているような気がします)
USE [TEST-GEAFax_arley_NEW]
GO
/****** Object: Table [dbo].[tAccts] Script Date: 12/9/2015 1:39:41 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[tAccts](
[Ticket] [varchar](30) NOT NULL,
[Method] [varchar](15) NOT NULL,
[AcctOwner] [varchar](15) NOT NULL,
[DisplayName] [varchar](75) NOT NULL,
[Destination] [varchar](75) NOT NULL,
[DNIS] [varchar](20) NOT NULL,
[DNIS2] [varchar](20) NULL,
[Phone_TF] [varchar](30) NOT NULL,
[Phone_Local] [varchar](30) NOT NULL,
[Phone_PBX] [varchar](255) NOT NULL,
[UpdatedBy] [varchar](50) NOT NULL,
[UpdatedOn] [date] NOT NULL,
[FaxNotes] [varchar](255) NULL,
[TelcomNotes] [varchar](255) NULL,
[AcctID] [int] IDENTITY(0,1) NOT NULL,
CONSTRAINT [PK__tAccounts_AcctID] PRIMARY KEY CLUSTERED
(
[AcctID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
CONSTRAINT [UQ__tAccounts_DNIS.Method.Destination.Phones] UNIQUE NONCLUSTERED
(
[DNIS] ASC,
[Method] ASC,
[Destination] ASC,
[Phone_TF] ASC,
[Phone_Local] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
---------------------------------------------------------------------------------
USE [TEST-GEAFax_arley_NEW]
GO
/****** Object: View [dbo].[vReclaimable] Script Date: 12/9/2015 1:39:57 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
/***********************************************************************
* Written By : N. Arley Dealey (200018252
* Written On :
* Updated By :
* Updated On :
* Description : Returns data from tAccts, vRxAl, vWLT_AllGE
* Notes :
***********************************************************************/
CREATE VIEW [dbo].[vReclaimable] AS
SELECT
a.Ticket
, a.Method
, a.AcctOwner
, a.DisplayName
, a.Destination
, a.DNIS
, a.DNIS2
, a.Phone_TF
, a.Phone_Local
, a.Phone_PBX
, a.UpdatedBy
, a.UpdatedOn
, a.FaxNotes
, a.TelcomNotes
, a.AcctID
, COUNT(jt.JobID) AS 'FaxesRcvd'
, CAST(MIN(jt.TimeStamp_UTC) AS DATE) AS 'FirstRcvd'
, CAST(MAX(jt.TimeStamp_UTC) AS DATE) AS 'LastRcvd'
, DATEDIFF(dd, MAX(jt.TimeStamp_UTC), GETDATE()) AS 'DaysIdle'
, o.OHR_EmpSSO
, o.OHR_EmpStatus
, o.OHR_EmpName
, o.OHR_EmpTitle
, o.OHR_BizIndustryGroup
, o.OHR_BizSegment
, o.OHR_BizUnit
, o.OHR_BizDept
, o.OHR_BizDomain
FROM
dbo.tAccts AS a
LEFT OUTER JOIN dbo.tAccts_Retain AS r ON (a.AcctID = r.AcctID)
LEFT OUTER JOIN dbo.vWLT_AllGE AS o ON (a.AcctOwner = o.OHR_EmpSSO)
LEFT OUTER JOIN dbo.vRxAll AS jt ON (a.DNIS = jt.DNIS)
WHERE ( 1 -- place holder, has no effect
AND r.RetainID IS NULL -- out of scope: in Retain table
AND a.Method = 'smtp' -- out of scope: ftp, unc, cifs, printers
AND a.Phone_Local NOT LIKE '216-%' -- out of scope: NELA numbers
AND a.AcctOwner <> 'r00417819' -- out of scope: reclaimed numbers
AND a.AcctOwner <> 'r00336832' -- out of scope: never assigned numbers
AND a.AcctOwner <> 'r00971729' -- out of scope: invalid numbers
AND a.Destination NOT LIKE 'g%@mail.ad.ge.com' -- out of scope: distribution lists
AND a.Destination NOT LIKE 'r%@mail.ad.ge.com' -- out of scope: shared mailboxes
)
GROUP BY
a.DNIS
-- remaining columns are just for syntax reasons
, a.Ticket, a.Method, a.AcctOwner, a.DisplayName, a.Destination, a.DNIS2, a.Phone_TF, a.Phone_Local, a.Phone_PBX, a.UpdatedBy, a.UpdatedOn, a.FaxNotes, a.TelcomNotes, a.AcctID
, o.OHR_EmpSSO, o.OHR_EmpStatus, o.OHR_EmpName, o.OHR_EmpTitle
, o.OHR_BizIndustryGroup, o.OHR_BizSegment, o.OHR_BizUnit, o.OHR_BizDept, o.OHR_BizDomain
GO
つまり、UPDATE
ステートメントが何をするかです。それは完全に明白ではありませんが、あなたのステートメントはこれと同等です:
UPDATE upd SET
Ticket = 'ARP.ExGE'
, Method = 'smtp'
, AcctOwner = 'r00417819'
, DisplayName = '~AppLight HBSFax-Inactive'
, Destination = '[email protected]'
, UpdatedBy = SYSTEM_USER
, UpdatedOn = CAST(GetDate() AS DATE)
FROM
dbo.tAccts AS upd
CROSS JOIN
dbo.vReclaimable AS v
WHERE OHR_EmpStatus <> 'A' ;
FROM
のdbo.tAccts
テーブルについての言及がなく、テーブルとビューの間の結合またはwhere条件がないため、CROSS
結合と更新の試行が発生します。 テーブルのすべての行(そしてビューからだけでなく)、そしておそらく複数回も!
結合(またはwhere)条件を追加するには、次のようにします。
UPDATE upd SET
Ticket = 'ARP.ExGE'
, Method = 'smtp'
, AcctOwner = 'r00417819'
, DisplayName = '~AppLight HBSFax-Inactive'
, Destination = '[email protected]'
, UpdatedBy = SYSTEM_USER
, UpdatedOn = CAST(GetDate() AS DATE)
FROM
dbo.tAccts AS upd
JOIN
dbo.vReclaimable AS v
ON v.PK = upd.PK -- whatever the PK column is
WHERE OHR_EmpStatus <> 'A' ;
または(お使いのバージョンを使用):
UPDATE dbo.tAccts SET
Ticket = 'ARP.ExGE'
, Method = 'smtp'
, AcctOwner = 'r00417819'
, DisplayName = '~AppLight HBSFax-Inactive'
, Destination = '[email protected]'
, UpdatedBy = SYSTEM_USER
, UpdatedOn = CAST(GetDate() AS DATE)
FROM dbo.vReclaimable
WHERE OHR_EmpStatus <> 'A'
AND vReclaimable.PK = tAccts.PK ;
または、(おそらく)単にビューを更新することもできます。これが機能するためには、ビューが「更新可能なビュー」に関する制限に準拠している必要があります。 MSDNドキュメントの関連する段落を参照してください: CREATE VIEW
、更新可能なビュー :
UPDATE dbo.vReclaimable SET
Ticket = 'ARP.ExGE'
, Method = 'smtp'
, AcctOwner = 'r00417819'
, DisplayName = '~AppLight HBSFax-Inactive'
, Destination = '[email protected]'
, UpdatedBy = SYSTEM_USER
, UpdatedOn = CAST(GetDate() AS DATE)
WHERE OHR_EmpStatus <> 'A' ;
更新クエリのテーブル間に結合がないようです。
UPDATE dbo.tAccts SET
Ticket = 'ARP.ExGE'
, Method = 'smtp'
, AcctOwner = 'r00417819'
, DisplayName = '~AppLight HBSFax-Inactive'
, Destination = '[email protected]'
, UpdatedBy = SYSTEM_USER
, UpdatedOn = CAST(GetDate() AS DATE)
FROM dbo.vReclaimable
WHERE OHR_EmpStatus <> 'A'
where tAccts.id = vReclaimable.idなどのテーブル間の行に一致するものが必要です
これを置く別の方法:
問題は、ステートメントが「vReclaimableビューによって返されるtAcctsテーブルの行のみを更新する必要がある」というあなたの信念です。
そうではありません。 OHR_EmpStatus <> 'A'
(tAccts
の条件)に一致するUPDATE
(WHERE
の直後に記載されているテーブル)のすべての行を更新します。その際、vReclaimable
のデータを使用する場合があります(ただし、そのデータへの参照は一切行いません)。
vReclaimable
にある行だけに制限したい場合は、提示されている他のオプションに加えて、サブクエリを使用できます。
UPDATE dbo.tAccts SET
Ticket = 'ARP.ExGE'
, Method = 'smtp'
, AcctOwner = 'r00417819'
, DisplayName = '~AppLight HBSFax-Inactive'
, Destination = '[email protected]'
, UpdatedBy = SYSTEM_USER
, UpdatedOn = CAST(GetDate() AS DATE)
WHERE OHR_EmpStatus <> 'A' AND tAccts.key IN (SELECT key FROM vReclaimable)
以下のクエリが複数の行を返す場合:
select 'tAccts table', dnis, method, destination, phone_tf, phone_local
from tAccts
where OHR_EmpStatus <> 'A'
次に、同じ値で複数の行を更新しようとしているため、一意性制約に違反しています。
別のオプションは:あなたは必要ありません
FROM dbo.vReclaimable
このテーブルの値をupdateステートメントで使用しないためです。