2016-03-15 5 views
11

すべての列(データ型を含む)に関する情報を取得し、どれがPK/FKであるかを知るためのクエリを書く必要がありました。 FKについては、他のテーブルのような追加情報が必要でした。 私はで動作するクエリを持っていますが、少し余計に見えます。SQLのその他の列情報を取得する

これはもっと良い方法ですか? サブクエリの結合が好きではありません。クエリでなければならず、SPで行うことはできません。

私の例では、(私がテストしていたいくつかの追加FK関係を持つ)Northwind

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で処理できないと懸念していますか?それはできません。パフォーマンス?これらは内部カタログ表であるため、多くのことを行うことはできません。リファクタリングオプションは、単一のステートメントが必要であり、SPが存在しないため制限されています。それをインラインテーブル値関数としてラップすると、役立つかもしれませんが、それが間違ってしまうとパフォーマンスが低下する可能性があります。

SQLの表示を明確にしたい場合は、サブクエリをCTEとして記述し、ビュー(または関数)に変換するか、ネストしないようにして、すべての結合が同じインデントレベルになるようにすることができます。後者は、しかし、解明するよりも不明瞭になりがちです。

残念ながら、あなたの最善の希望は、きれいなコード(良いインデント、一貫した名前、合理的なエイリアスなど)を書き、コメントの目的とテクニックを記述することです。あなたが提示したことは、これのほとんどを達成します。

+0

私は同意しますが、このような大きなクエリを複数のクエリに分割し、各クエリの結果を一時テーブルに取り込み、結果を取得するためにテーブルをクエリすることが良いことがあることを追加します。これにより、プロセスが高速化され、読みやすく保守性が向上することがあります。 –

関連する問題