Ich bin ein "zufälliger" DBA, relativ unerfahren und von diesem Problem verwirrt.
Ausführen von MS SQL Server 2012. Das Problem liegt bei dieser UPDATE-Anweisung:
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'
Was sollte aktualisiert werden nur die Zeilen in der tAccts Tabelle , die von der vReclaimable Ansicht zurückgegeben werden.
Die vReclaimable-Ansicht basiert auf der Tabelle tAccts und gibt eine Teilmenge der Zeilen in tAccts zurück.
Wenn ich es ausführe, schlägt es mit einem eindeutigen Schlüsselfehler fehl:
(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.
Fairerweise hat die tAccts-Tabelle eine eindeutige Schlüsselbeschränkung:
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)
Aber hier ist das Seltsame. Wenn ich diese beiden Abfragen ausführe:
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
Die erste gibt zwei Zeilen zurück (wie erwartet):
(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
und die zweite gibt 0 Zeilen zurück (wie erwartet).
Wenn "FROM vReclaimable WHERE OHR_EmpStatus <> 'A'" 0 Zeilen zurückgibt, warum versucht das UPDATE, die Zeile mit DNIS = 68497 zu aktualisieren?
(Ich hoffe, ich habe dies angemessen beschrieben. Ich habe das Gefühl, dass mir etwas Offensichtliches fehlt.)
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
Aussage.OHR_EmpStatus
eine Spalte der Tabelle, die Ansicht oder beides?Antworten:
Es
UPDATE
läuft darauf hinaus, was die Aussage bewirkt. Es ist nicht ganz offensichtlich, aber Ihre Aussage entspricht dieser:Da die
dbo.tAccts
Tabelle in derFROM
und keine Verknüpfung oder wo-Bedingung zwischen der Tabelle und der Ansicht nicht erwähnt wird, führt dies zu einerCROSS
Verknüpfung und einem Versuch, alle Zeilen der Tabelle (und nicht nur aus der Ansicht) zu aktualisieren , und wahrscheinlich zu mehreren auch mal!Sie können eine Join-Bedingung (oder eine Where-Bedingung) hinzufügen mit:
oder (mit Ihrer Version):
Alternativ können Sie die Ansicht (wahrscheinlich) einfach aktualisieren. Damit dies funktioniert, muss die Ansicht den Einschränkungen für "Aktualisierbare Ansichten" entsprechen . Siehe den entsprechenden Abschnitt in der MSDN-Dokumentation :
CREATE VIEW
, Aktualisierbare Ansichten :quelle
Es scheint, dass Sie keine Verknüpfung zwischen den Tabellen in Ihrer Aktualisierungsabfrage haben.
Hier muss es etwas geben, das den Zeilen zwischen den Tabellen entspricht, z. B. wo tAccts.id = vReclaimable.id
quelle
Eine andere Art, dies auszudrücken:
Das Problem ist Ihre Überzeugung, dass die Anweisung "nur die Zeilen in der tAccts-Tabelle aktualisieren sollte, die von der vReclaimable-Ansicht zurückgegeben werden".
Das ist nicht der Fall. Es aktualisiert alle Zeilen aus
tAccts
(die direkt danach erwähnte TabelleUPDATE
), die übereinstimmenOHR_EmpStatus <> 'A'
(die Bedingung in derWHERE
). Dabei werden möglicherweise Daten von verwendetvReclaimable
(Sie verweisen jedoch überhaupt nicht darauf).Wenn Sie es
vReclaimable
zusätzlich zu den anderen angezeigten Optionen auf Zeilen beschränken möchten, die sich in befinden , können Sie eine Unterabfrage verwenden:quelle
Wenn die folgende Abfrage mehr als eine Zeile zurückgibt:
Dann versuchen Sie, mehrere Zeilen mit denselben Werten zu aktualisieren, wodurch die eindeutige Einschränkung verletzt wird.
quelle
Eine andere Option ist: Sie brauchen das nicht
FROM dbo.vReclaimable
weil Sie in Ihrer Update-Anweisung keinen Wert aus dieser Tabelle verwenden.
quelle
vReclaimable
zweifellos die zu aktualisierende Tabelle filtern. Obwohl es für dieSET
Klausel nicht benötigt wird , ist es effektiv Teil derWHERE
Klausel.