Saya seorang "kebetulan" DBA, relatif tidak berpengalaman dan bingung dengan masalah ini.
Menjalankan MS SQL Server 2012. Masalahnya adalah dengan pernyataan UPDATE ini:
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'
Yang harus memperbarui hanya baris dalam tabel tAccts yang dikembalikan oleh tampilan vReclaimable.
Tampilan vReclaimable didasarkan pada tabel tAccts dan mengembalikan sebagian dari baris dalam tAccts.
Ketika saya menjalankannya, gagal dengan kesalahan kunci unik:
(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, r00417819@mail.ad.ge.com, 800-905-8793, none).
The statement has been terminated.
Cukup adil, tabel tAccts memang memiliki batasan kunci yang unik:
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)
Tapi ini yang aneh. Jika saya menjalankan dua pertanyaan ini:
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
Yang pertama mengembalikan dua baris (seperti yang diharapkan):
(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
dan yang kedua mengembalikan 0 baris (seperti yang diharapkan).
Jika “FROM vReclaimable WHERE OHR_EmpStatus <> 'A'” mengembalikan 0 baris, mengapa UPDATE mencoba memperbarui baris di mana DNIS = 68497?
(Saya harap saya telah menggambarkan ini dengan memadai. Saya merasa saya kehilangan sesuatu yang jelas)
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
CREATE VIEW
pernyataannya.OHR_EmpStatus
kolom dari tabel, tampilan atau keduanya?Jawaban:
Itu bermuara pada apa
UPDATE
yang dilakukan pernyataan. Tidak sepenuhnya jelas tetapi pernyataan Anda setara dengan yang ini:Karena tidak ada penyebutan
dbo.tAccts
tabel di dalamFROM
dan tidak ada gabungan atau kondisi di mana antara tabel dan tampilan, itu menghasilkanCROSS
gabungan dan upaya untuk memperbarui semua baris tabel (dan bukan hanya dari tampilan), dan mungkin beberapa kali juga!Anda dapat menambahkan kondisi bergabung (atau di mana) dengan:
atau (menggunakan versi Anda):
Atau, Anda dapat (mungkin) cukup memperbarui tampilan. Agar ini berfungsi, tampilan harus sesuai dengan batasan tentang "Tampilan yang Dapat Diupdate" . Lihat paragraf yang relevan dokumentasi MSDN:
CREATE VIEW
, Views Updatable :sumber
tampaknya Anda tidak memiliki gabungan antara tabel dalam kueri pembaruan Anda.
di sini harus ada sesuatu yang cocok dengan baris antara tabel seperti di mana tAccts.id = vReclaimable.id
sumber
Cara lain untuk mengatakan ini:
Masalahnya adalah keyakinan Anda bahwa pernyataan "harus memperbarui hanya baris dalam tabel tAccts yang dikembalikan oleh tampilan vReclaimable".
Bukan itu masalahnya. Ini memperbarui semua baris dari
tAccts
(tabel yang disebutkan setelahUPDATE
) yang cocokOHR_EmpStatus <> 'A'
(kondisi diWHERE
). Mungkin menggunakan data darivReclaimable
dalam melakukannya (tetapi Anda tidak membuat referensi apa pun untuk itu).Jika Anda ingin membatasi untuk baris yang ada
vReclaimable
, selain opsi lain yang disajikan, Anda bisa menggunakan subquery:sumber
Jika kueri di bawah ini mengembalikan lebih dari satu baris:
maka Anda mencoba untuk memperbarui beberapa baris dengan nilai yang sama sehingga melanggar batasan unik.
sumber
Pilihan lain adalah: Anda tidak perlu
DARI dbo.vReclaimable
karena Anda tidak menggunakan nilai apa pun dari tabel ini dalam pernyataan pembaruan Anda.
sumber
vReclaimable
tidak diragukan lagi dimaksudkan untuk memfilter tabel yang sedang diperbarui. Meskipun tidak diperlukan untukSET
klausa, itu secara efektif bagian dariWHERE
klausa.