2016-03-15 41 views
11

我需要編寫一個查詢,以獲取有關所有列(包含數據類型)的信息,並知道哪些列是PK/FK。對於FK,需要額外的信息,比如來自哪個表。 我收到的作品的查詢,但看起來有點矯枉過正。SQL查詢以獲取其他列信息

這可以做得更好嗎? 我不喜歡它的子查詢連接。它必須是一個查詢,不能通過SP完成。

我的例子是對Northwind(有一些額外的FK關係,我是測試)

SELECT 
    t.name AS TableName, 
    t.object_id AS TableObjectId, 
    tCols.column_name AS ColumnName, 
    tCols.data_type AS ColumnDataType, 
    ISNULL(tCols.numeric_scale, 0) AS ColumnDecimalPlaces, 
    CASE tConstraints.CONSTRAINT_TYPE 
     WHEN 'PRIMARY KEY' 
      THEN '1' 
      ELSE '0' 
    END AS ISPK, 
    CASE tConstraints.CONSTRAINT_TYPE 
     WHEN 'FOREIGN KEY' 
      THEN '1' 
      ELSE '0' 
    END AS ISFK, 
    tConstraints.CONSTRAINT_TYPE, 
    tConstraints.CONSTRAINT_NAME, 
    fkInfo.FK_name, 
    fkInfo.PK_column, 
    fkInfo.PK_table, 
    fkInfo.PK_name 
FROM sys.objects t 
LEFT JOIN information_schema.columns tCols ON tCols.TABLE_NAME = t.name 
LEFT JOIN (
    SELECT 
     tc.CONSTRAINT_NAME, 
     tc.TABLE_NAME, 
     tc.CONSTRAINT_TYPE, 
     kcu.COLUMN_NAME 
    FROM information_schema.table_constraints tc 
    INNER JOIN information_schema.key_column_usage AS kcu ON tc.constraint_name = kcu.constraint_name 
) AS tConstraints 
    ON t.name = tConstraints.TABLE_NAME 
    AND tCols.column_name = tConstraints.COLUMN_NAME 
LEFT JOIN (
    SELECT 
     o1.name AS FK_table, 
     c1.name AS FK_column, 
     fk.name AS FK_name, 
     o2.name AS PK_table, 
     c2.name AS PK_column, 
     pk.name AS PK_name 
    FROM sys.objects o1 
    INNER JOIN sys.foreign_keys fk 
     ON o1.object_id = fk.parent_object_id 
    INNER JOIN sys.foreign_key_columns fkc 
     ON fk.object_id = fkc.constraint_object_id 
    INNER JOIN sys.columns c1 
     ON fkc.parent_object_id = c1.object_id 
     AND fkc.parent_column_id = c1.column_id 
    INNER JOIN sys.columns c2 
     ON fkc.referenced_object_id = c2.object_id 
     AND fkc.referenced_column_id = c2.column_id 
    INNER JOIN sys.objects o2 
     ON fk.referenced_object_id = o2.object_id 
    INNER JOIN sys.key_constraints pk 
     ON fk.referenced_object_id = pk.parent_object_id 
     AND fk.key_index_id = pk.unique_index_id 
) AS fkInfo ON t.name = fkInfo.FK_table 
    AND tCols.column_name = fkInfo.FK_column 
WHERE t.name = 'Products' 
ORDER BY 3 

This is the output

+2

這是需要什麼做*所有你想要的。您可以通過將其存儲到存儲過程中來隱藏複雜性。 – wallyk

+0

@wallyk這是一個用於客戶端豐富的網格控制的通用軟件。所以SP選項不起作用。好的評論,但我會在這個問題上加上。 – Yahya

+1

你不應該按姓名加入。 –

回答

7

試試我的查詢(我已經分開列PK_NAME和FK_NAME,所以不需要如此),它是對系統的看法,這是快:

with 
    pk as (select pki.object_id, pki.column_id, _pk.name 
     from sys.index_columns pki 
     join sys.key_constraints _pk 
     on _pk.unique_index_id = pki.index_id and _pk.parent_object_id = pki.object_id 
     where 1=1), 
    fk as (select fkc.parent_object_id, fkc.parent_column_id, fk.name name, pkt.name pk_table, pkc.name pk_column, pkc.object_id, pkc.column_id 
    from sys.foreign_keys as fk 
    join sys.tables pkt 
    on pkt.object_id = fk.referenced_object_id 
    join sys.foreign_key_columns as fkc 
    on fkc.constraint_object_id = fk.object_id 
    join sys.columns as pkc 
    on pkc.object_id = fkc.referenced_object_id and pkc.column_id = fkc.referenced_column_id 
    where 1=1) 
select t.name TableName 
, t.object_id TableObjectId 
, c.column_id CId 
, c.name AS ColumnName 
, typ.name AS ColumnDataType 
, c.is_identity 
, c.precision 
, c.scale 
, pk.name pk_name 
, fk.name fk_name 
, fk.pk_table 
, fk.pk_column 
, fkpk.name pk_for_fk 
from sys.tables as t 
inner join sys.columns as c on t.object_id = c.object_id 
inner join sys.types as typ on typ.user_type_id = c.user_type_id 
left join pk on pk.object_id = t.object_id and pk.column_id = c.column_id 
left join fk on fk.parent_object_id = c.object_id and fk.parent_column_id = c.column_id 
left join pk as fkpk on fkpk.object_id = fk.object_id and fkpk.column_id = fk.column_id 
WHERE t.name = 'Products' 
5

,但它看起來有點大材小用

如果你想從很多表中拉出很多值,那麼你將最終得到一個大的查詢。這就是它的工作原理。隨着這些事情的發展,這一個並不是那麼大。

您擔心SQL Server無法處理它嗎?不要,它可以。性能?因爲這些是內部目錄表,所以你不能做很多。重構選項是有限的,因爲你需要一個單一的聲明和SPs出局。將它作爲內聯表值函數包裝可能會有所幫助,但如果出錯,可能會損害性能。

如果您只是希望SQL的表示清晰,則可以將子查詢寫爲CTE,轉換爲視圖(或函數,但不要)或不存在,因此所有聯接都處於相同的縮進級別。然而,後者更容易模糊而不是闡明。總而言之,我認爲您最好的希望是編寫乾淨的代碼 - 縮進,一致命名,合理的別名等 - 並在評論中描述目標和技巧。你所呈現的大部分都是這樣。

+0

我同意,但會補充說,有時將這樣的大型查詢拆分爲多個查詢,使用每個查詢的結果填充臨時表,然後查詢表以獲取結果是很好的做法。這有時可以加快流程,並使其更具可讀性和可維護性。 –