Warum gibt OBJECTPROPERTY NULL zurück?

7

Angenommen, Sie möchten eine Datenbank abfragen, um die darin enthaltenen Auslösertypen zu ermitteln. Eine Möglichkeit, dies zu tun, besteht darin, die Funktion OBJECTPROPERTY für alle Triggerobjekte in der Datenbank zu verwenden.

Manchmal führt die Funktion OBJECTPROPERTY zu einem verwirrenden Ergebnis. Die Ausgabe scheint vom Datenbankkontext abzuhängen.

Die folgende Beispielabfrage gibt eine Zeile für jeden der Sysmail-Trigger in msdb zurück:

SELECT
  object_id,
  name,
  OBJECTPROPERTY(object_id, 'ExecIsInsertTrigger') AS IsInsertTrigger,
  OBJECTPROPERTY(object_id, 'ExecIsUpdateTrigger') AS IsUpdateTrigger,
  OBJECTPROPERTY(object_id, 'ExecIsDeleteTrigger') AS IsDeleteTrigger
FROM msdb.sys.objects
WHERE
  [type] = 'TR' AND
  name LIKE 'trig_sysmail_%';
GO

Die Absicht ist herauszufinden, welche DML-Aktion jeden Trigger auslöst. Beispielsweise IsInsertTriggerenthält die Spalte eine 1, wenn der Trigger definiert ist AFTER INSERT, und andernfalls eine 0.

Wenn ich die Abfrage im Kontext von msdb ausführe, enthält die Ergebnismenge in jeder der berechneten Spalten eine 0 oder eine 1. Es sieht aus wie das:

object_id   name                         IsInsertTrigger IsUpdateTrigger IsDeleteTrigger
----------- ---------------------------- --------------- --------------- ---------------
713105631   trig_sysmail_profile         0               1               0
745105745   trig_sysmail_account         0               1               0
761105802   trig_sysmail_profileaccount  0               1               0
777105859   trig_sysmail_profile_delete  0               0               1
793105916   trig_sysmail_servertype      0               1               0
809105973   trig_sysmail_server          0               1               0
825106030   trig_sysmail_configuration   0               1               0
841106087   trig_sysmail_mailitems       0               1               0
857106144   trig_sysmail_attachments     0               1               0
873106201   trig_sysmail_log             0               1               0

Wenn ich die Abfrage im Kontext des Masters ausführe, enthält die Ergebnismenge in jeder der berechneten Spalten NULL. Es sieht aus wie das:

object_id   name                         IsInsertTrigger IsUpdateTrigger IsDeleteTrigger
----------- ---------------------------- --------------- --------------- ---------------
713105631   trig_sysmail_profile         NULL            NULL            NULL
745105745   trig_sysmail_account         NULL            NULL            NULL
761105802   trig_sysmail_profileaccount  NULL            NULL            NULL
777105859   trig_sysmail_profile_delete  NULL            NULL            NULL
793105916   trig_sysmail_servertype      NULL            NULL            NULL
809105973   trig_sysmail_server          NULL            NULL            NULL
825106030   trig_sysmail_configuration   NULL            NULL            NULL
841106087   trig_sysmail_mailitems       NULL            NULL            NULL
857106144   trig_sysmail_attachments     NULL            NULL            NULL
873106201   trig_sysmail_log             NULL            NULL            NULL

MSDN stellt fest, dass die Funktion OBJECTPROPERTY NULL zurückgibt, wenn:

  1. Der Eigenschaftsname ist ungültig.
  2. Die Objekt-ID ist ungültig.
  3. id ist ein nicht unterstützter Objekttyp für die angegebene Eigenschaft.
  4. Der Aufrufer hat keine Berechtigung zum Anzeigen der Metadaten des Objekts.

Ich kann die Gründe 1 und 3 ausschließen, da die Abfrage im Kontext von msdb das richtige Ergebnis zurückgibt.

Zuerst dachte ich, es könnte sich um ein datenbankübergreifendes Berechtigungsproblem handeln (Grund 4), aber ich bin Systemadministrator auf dem Server.

Damit bleibt Grund 2, der mich mit folgenden Fragen zurücklässt:

Ist die Objekt-ID in einer datenbankübergreifenden Abfrage ungültig?

Welche OBJECTPROPERTY-Funktion der Datenbank wird aufgerufen?

Iain Samuel McLean Elder
quelle

Antworten:

6

OBJECTPROPERTY ist lokal für die Datenbank, in der die Abfrage ausgeführt wird. So ist die object_idübergeben wird aufgelöst gegen master.sys.objects: aber die object_id kommt ausmsdb

Hier haben Sie also Fall 2.

Auf meinem Server habe ich 37 übereinstimmende object_id- Werte zwischen msdbund SomeDBOnMyServer. Aber die Namen sind unterschiedlich.

USE SomeDBOnMyServer
GO
SELECT
  object_id,
  name,
  OBJECT_NAME(object_id)
FROM msdb.sys.objects
WHERE OBJECT_NAME(object_id) <> name

Offensichtlich habe ich viele Zeilen, in denen OBJECT_NAME(object_id)NULL ist, die hier gefiltert werden

gbn
quelle
+1 für die Erklärung, dass die Objekt-ID aus einer Datenbank stammt und in einer anderen Datenbank nachgeschlagen wird. Ich denke, dass die Abfrage keine Zeilen in meiner Datenbank zurückgibt. Es gibt keine gemeinsamen Objekt-IDs.
Iain Samuel McLean Elder
6

Wie von gbn angegeben, müssen Sie diese Abfrage im Kontext der msdb-Datenbank ausführen OBJECTPROPERTY, um sie korrekt aufzulösen. Wenn Sie Ihre Skriptdatenbank agnostisch machen möchten, können Sie eine kompliziertere Abfrage schreiben, um dieselben Informationen zu erhalten:

SELECT 
  t.[object_id], t.name, 
  IsInsertTrigger = MAX(CASE WHEN i.[type] IS NULL THEN 0 ELSE 1 END),
  IsUpdateTrigger = MAX(CASE WHEN u.[type] IS NULL THEN 0 ELSE 1 END),
  IsDeleteTrigger = MAX(CASE WHEN d.[type] IS NULL THEN 0 ELSE 1 END)
FROM msdb.sys.triggers AS t
LEFT OUTER JOIN 
  msdb.sys.trigger_events AS i
  ON t.[object_id] = i.[object_id] AND i.[type] = 1
LEFT OUTER JOIN 
  msdb.sys.trigger_events AS u
  ON t.[object_id] = u.[object_id] AND u.[type] = 2
LEFT OUTER JOIN 
  msdb.sys.trigger_events AS d
  ON t.[object_id] = d.[object_id] AND d.[type] = 3
WHERE t.name LIKE 'trig[_]sysmail[_]%'
GROUP BY t.[object_id], t.name;
Aaron Bertrand
quelle
+1 für die Abfrage! Ich wusste nichts davon sys.trigger_events. Die Dokumentation für sys.triggerserwähnt es nicht, aber es ist eindeutig verwandt.
Iain Samuel McLean Elder
Und danke, dass du den subtilen Fehler in meinem LIKE-Caluse behoben hast.
Iain Samuel McLean Elder
@isme du hättest ein paar ziemlich knorrige Sachen in msdb machen müssen, um davon erwischt zu werden, aber es ist eine Gewohnheit, sorry. :-)
Aaron Bertrand