2010-05-14 23 views
5

我有一個服務器與供應商應用程序是嚴重依賴數據庫。我需要以自動化的方式對數據庫中的幾個表中的數據進行一些小的更改。只是插入和更新,沒有什麼奇特的。作爲供應商的供應商,在升級過程中,當他們更改數據庫模式時,我永遠無法確定。爲了達到這個目的,我如何以一些腳本化的方式詢問SQL服務器:「嘿,這個表是否還存在?是的,很酷,好吧,但是它有這個列嗎?數據類型和大小是什麼?那是什麼?它是可空的嗎?你可以給我一張表的列表嗎?在這張表中,你能給我列一個列表嗎?那裏有任何主鍵?「我不需要爲整個模式做這件事,只需要對其中的一部分進行操作,只需在數據庫快速檢查之前對其進行檢查即可。如何在SQL Server上進行內省?

我們目前有Microsoft SQL Server 2005,但它可能很容易遷移到Microsoft SQL Server 2008. 我在搜索時可能沒有使用正確的術語。我知道ORM不僅對這類事情有太多的開銷,而且我也沒有機會把它交給我的同事。

回答

5

運行像下面的上市,從中你可以看到一個查詢:

  • 模式名稱
  • 表/視圖名稱
  • 表類型(如:SYSTEM_TABLE,VIEW,SQL_TABLE_VALUED_FUNCTION,USER_TABLE,SQL_INLINE_TABLE_VALUED_FUNCT ION,INTERNAL_TABLE)
  • 列名
  • 列的數據類型(包括長度,精度等)
  • 可空
  • 此列在主鍵
  • 完整主鍵位置,所有PK列連接在一起,如果此列的PK的一部分
  • 身份(種子,遞增,和電流值)
  • 檢查約束定義
  • 計算列defini重刑

需要的SQL Server 2005+運行:

--optional, remove comments on WHERE to use these 
--DECLARE @SchemaNameSearch sysname 
--  ,@TableNameSearch sysname 
--  ,@ColumnNameSearch sysname 
--SELECT @SchemaNameSearch ='YourSchemaName' 
--  ,@TableNameSearch ='YourTableName' 
--  ,@ColumnNameSearch ='YourColumnName' 

SELECT 
    sh.name+'.'+o.name AS ObjectName 
     ,o.type_desc AS ObjectType 
     ,s.name as ColumnName 
     ,CASE 
      WHEN t.name IN ('char','varchar') THEN t.name+'('+CASE WHEN s.max_length<0 then 'MAX' ELSE CONVERT(varchar(10),s.max_length) END+')' 
      WHEN t.name IN ('nvarchar','nchar') THEN t.name+'('+CASE WHEN s.max_length<0 then 'MAX' ELSE CONVERT(varchar(10),s.max_length/2) END+')' 
      WHEN t.name IN ('numeric') THEN t.name+'('+CONVERT(varchar(10),s.precision)+','+CONVERT(varchar(10),s.scale)+')' 
      ELSE t.name 
     END AS DataType 

     ,CASE 
      WHEN s.is_nullable=1 THEN 'NULL' 
      ELSE 'NOT NULL' 
     END AS Nullable 
     ,xc.key_ordinal AS PK_Position 
     ,CASE 
      WHEN xc.key_ordinal IS NOT NULL THEN All_PKs.PrimaryKey 
      ELSE NULL 
     END AS PK 
     ,CASE 
      WHEN ic.column_id IS NULL THEN '' 
      ELSE ' identity('+ISNULL(CONVERT(varchar(10),ic.seed_value),'')+','+ISNULL(CONVERT(varchar(10),ic.increment_value),'')+')='+ISNULL(CONVERT(varchar(10),ic.last_value),'null') 
     END 
     +CASE 
      WHEN sc.column_id IS NULL THEN '' 
      ELSE ' computed('+ISNULL(sc.definition,'')+')' 
     END 
     +CASE 
      WHEN cc.object_id IS NULL THEN '' 
      ELSE ' check('+ISNULL(cc.definition,'')+')' 
     END 
      AS MiscInfo 
    FROM sys.objects       o 
     INNER JOIN sys.schemas    sh on o.schema_id=sh.schema_id 
     INNER JOIN sys.columns     s ON o.object_id=s.object_id 
     INNER JOIN sys.types     t ON s.system_type_id=t.system_type_id and t.is_user_defined=0 
     LEFT OUTER JOIN sys.identity_columns ic ON s.object_id=ic.object_id AND s.column_id=ic.column_id 
     LEFT OUTER JOIN sys.computed_columns sc ON s.object_id=sc.object_id AND s.column_id=sc.column_id 
     LEFT OUTER JOIN sys.check_constraints cc ON s.object_id=cc.parent_object_id AND s.column_id=cc.parent_column_id 
     LEFT OUTER JOIN sys.indexes   x ON o.object_id=x.object_id AND x.is_primary_key=1 
     LEFT OUTER JOIN sys.index_columns  xc ON o.object_id=xc.object_id AND x.index_id=xc.index_id AND s.column_id=xc.column_id 
     LEFT OUTER JOIN (SELECT --build the concatenated PK here 
          oo.object_id 
            ,STUFF(
              (
               SELECT 
                ', '+s.Name 
                FROM sys.objects       o 
                 LEFT OUTER JOIN sys.indexes   x ON o.object_id=x.object_id AND x.is_primary_key=1 
                 LEFT OUTER JOIN sys.index_columns  xc ON o.object_id=xc.object_id AND x.index_id=xc.index_id 
                 LEFT OUTER JOIN sys.columns   s ON o.object_id=s.object_id AND s.column_id=xc.column_id 
               WHERE oo.object_id=o.object_id AND xc.column_id IS NOT NULL 
               ORDER BY o.object_ID,xc.key_ordinal 
               FOR XML PATH('') 
              ) 
              ,1,2, '' 
             ) AS PrimaryKey 
           FROM sys.objects oo 
           -- 
           --REMOVE comments to filter the query 
           --WHERE [email protected] 
           -- 
         )All_PKs ON o.object_id=All_PKs.object_id 
    -- 
    --REMOVE comments to filter the query 
    --WHERE sh.name [email protected] 
    -- AND [email protected] 
    -- AND [email protected] 
    -- 
    ORDER BY sh.name+'.'+o.name,s.column_id 

你可以卸下WHERE評論通過模式/表/列進行過濾。

你也可以只創建一個數據庫觸發器來提醒你的變化:

create this log table first: 

CREATE TABLE YourLogTable (EventID int not null identity(1,1), EventDateTime datetime null, EventDescription varchar(MAX) null) 

USE [TheDatabase] 
GO 
SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 
CREATE TRIGGER [YourDatabaseTrigger] 
ON DATABASE 
FOR DDL_DATABASE_LEVEL_EVENTS --DDL_TABLE_EVENTS --DDL_EVENTS 
AS 

DECLARE @EventData  xml 
DECLARE @Message  varchar(1000) 
SET @EventData=EVENTDATA() 

INSERT INTO YourLogTable 
    (EventDateTime,EventDescription) 
    VALUES (GETDATE(),--SUSER_NAME() 
        --+'; '[email protected]('(/EVENT_INSTANCE/ObjectType)[1]', 'varchar(500)') 
        --+'; '[email protected]('(/EVENT_INSTANCE/ObjectName)[1]', 'varchar(500)') 
        --+'; '[email protected]('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(8000)') 
        CONVERT(varchar(max),@EventData) 
      ) 
RETURN 

GO 
SET ANSI_NULLS OFF 
GO 
SET QUOTED_IDENTIFIER OFF 
GO 
ENABLE TRIGGER [YourDatabaseTrigger] ON DATABASE 

,這將讓你看到對數據庫所做的每一個變化。

+0

這真的很棒。我沒有使用你的代碼,但它爲我打開了很多門,這比純粹的成語和腳本更好。 – MetaHyperBolic 2010-05-18 15:47:44

8
+0

哇!對於這樣一個通用鏈接來說,這是很多的選票,甚至沒有任何代碼來做OP之後的事情。 – 2010-05-14 18:40:00

相關問題