1

sql2005

これは私の単純化された例です:(実際にはここには40以上のテーブルがあり、2つしか示していません)

3つの列(id、description、varcharとしてのtablename)を持つtb_modulesというテーブルを取得しました。

 1, UserType, tb_usertype
 2, Religion, tb_religion

(最後の列は実際には別のテーブルの名前です)

次のような別のテーブルを取得しました:tb_value(columns:id、tb_modules_ID、usertype_OR_religion_ID)values:

 1111, 1, 45
 1112, 1, 55
 1113, 2, 123
 1114, 2, 234

つまり、45、55、123、234はユーザータイプまたは宗教ID(45、55ユーザータイプ、123、234宗教ID)です

判断しないでください、私はデータベースを設計しませんでした

質問tb_valueからの*と1つの列を表示して選択を行うにはどうすればよいですか?その1つの列はtb_usertypeからのTITLEまたはtb_religionテーブルからのRELIGIONNAMEになります

一般的なことをしたいと思います。最初は文字列を返すSQL関数について考えていましたが、動的SQLが必要になると思いますが、これは関数では問題ありません。

誰かより良いアイデア?

4

8 に答える 8

2

これを動的に行うには、次のようなSQLステートメントを作成できる必要があります

select tb_value.*, tb_usertype.title as Descr
from tb_value
    inner join tb_usertype
        on tb_value.extid = tb_usertype.id
where tb_value.tb_module_id = 1
union all
select tb_value.*, tb_religion.religionname as Descr
from tb_value
    inner join tb_religion
        on tb_value.extid = tb_religion.id
where tb_value.tb_module_id = 2
-- union 40 other tables

現在、データベースにtb_religionやtb_usertypeなどから使用する列を示す情報がないため、これを行うことはできません。これをtb_moduleの新しいフィールドとして追加できます。

tb_moduleで使用するフィールド名がある場合は、必要な処理を実行するビューを作成できます。また、テーブルtb_modulesにトリガーを追加して、tb_modulesが変更されるたびにビューを変更することができます。そうすれば、クエリを実行するときにクライアントから動的SQLを使用する必要がありません。心配する必要があるのは、tb_modulesに新しい行を追加する前にデータベースにテーブルを作成する必要があることだけです。

編集1 もちろん、トリガーのコードは、alterviewステートメントを動的に作成する必要があります。

編集2また、tb_value.extid(usertype_OR_religion_ID)に対して結合するには、tb_usertypeやtb_religionなどのどの列に関する情報を含むフィールドが必要です。または、フィールドが常に呼び出されると想定できますid

編集3これは、ビューのv_valuesを変更するトリガーをtb_moduleで作成する方法です。tb_modulesの列としてfieldnameを追加しましたが、関連するテーブルのidフィールドはidと呼ばれていると思います。

create trigger tb_modules_change on tb_modules after insert, delete, update
as 

declare @sql nvarchar(max)
declare @moduleid int
declare @tablename varchar(50)
declare @fieldname varchar(50)

set @sql = 'alter view v_value as '

declare mcur cursor for
  select id, tablename, fieldname
  from tb_modules

open mcur
fetch next from mcur into @moduleid, @tablename, @fieldname
while @@FETCH_STATUS = 0
begin
    set @sql = @sql + 'select tb_value.*, '+@tablename+'.'+@fieldname+' '+
                      'from tb_value '+
                      'inner join '+@tablename+' '+
                        'on tb_value.extid = '+@tablename+'.id '+
                      'where tb_value.tb_module_id = '+cast(@moduleid as varchar(10))  
  fetch next from mcur into @moduleid, @tablename, @fieldname

  if @@FETCH_STATUS = 0
  begin
    set @sql = @sql + ' union all '
  end
end
close mcur
deallocate mcur

exec sp_executesql @sql
于 2011-01-22T11:12:13.893 に答える
2

デザインが不安定であることに全員が同意しているので、それについてのコメントはスキップします。クエリのパターンは次のとおりです。

-- Query 1
select tb_value.*,tb_religion.religion_name as ANY_DESCRIPTION
  from tb_value 
  JOIN tb_religion on tb_value.ANY_KIND_OF_ID = tb_religion.id
 WHERE tb_value.module_id = 2
-- combine it with...
UNION ALL
-- ...Query 2
select tb_value.*,tb_religion.title as ANY_DESCRIPTION
  from tb_value 
  JOIN tb_userType on tb_value.ANY_KIND_OF_ID = tb_userType.id
 WHERE tb_value.module_id = 1
-- combine it with...
UNION ALL
-- ...Query 3
select  lather, rinse, repeat for 40 tables!

40のケースすべてをハードコードするビューを実際に定義してから、必要な特定のモジュールのクエリにフィルターを適用できます。

于 2011-01-20T15:22:12.237 に答える
2

最初はこれがありますが、これは非常に面倒です。

代替テキスト

少しクリーンアップするために、2 つのビューとシノニムを追加します。

create view v_Value as
select
      ID                      as ValueID
    , tb_modules_ID           as ModuleID
    , usertype_OR_religion_ID as RemoteID
from tb_value ;
go

create view v_Religion as
select
      ID
    , ReligionName as Title
from tb_religion ;
go

create synonym v_UserType for tb_UserType ;
go

そして今、モデルは次のようになります

代替テキスト

クエリの記述が簡単になりました

;
with 
q_mod as (
    select
          m.ID                          as ModuleID
        , coalesce(x1.ID    , x2.ID)    as RemoteID
        , coalesce(x1.Title , x2.Title) as Title
        , m.Description                 as ModuleType
    from      tb_Modules as m
    left join v_UserType as x1 on m.TableName = 'tb_UserType'
    left join v_Religion as x2 on m.TableName = 'tb_Religion'
)
select
      a.ModuleID
    , v.ValueID
    , a.RemoteID
    , a.ModuleType
    , a.Title
from q_mod   as a
join v_Value as v on (v.ModuleID = a.ModuleID and v.RemoteID = a.RemoteID) ;

このクエリには明らかなパターンがあるため、別のモジュール タイプのテーブルを追加する必要がある場合は、動的 SQL として作成できます。別のテーブルを追加するときは、IDTitleを使用して、ビューを使用する必要がないようにします。

編集

動的 SQL (またはアプリケーション レベルでのクエリ) を構築するには

6 行目と 7 行目を変更すると、x-index は次のようになります。tb_modules.id

coalesce(x1. , x2. , x3. ..) 

左の結合に行を追加します (行 11 の下)

left join v_SomeName as x3  on m.TableName = 'tb_SomeName'

SomeNameistb_modules.descriptionと x-index が一致しているtb_modules.id

編集2

おそらく最も簡単なのは、上記のクエリをビューにパッケージ化し、スキーマが動的に変更されるたびにクレートして実行することALTER VIEWです。このようにして、クエリはアプリケーションの時点から変更されません。

于 2011-01-19T16:03:28.787 に答える
1

私はあなたがこのようなものが欲しいと思います:

テーブルとテーブルごとに 1 つの行を tb_modules に追加するのは簡単です。

SET NOCOUNT ON
if OBJECT_ID('tb_modules') > 0 drop table tb_modules;
if OBJECT_ID('tb_value') > 0 drop table tb_value;
if OBJECT_ID('tb_usertype') > 0 drop table tb_usertype;
if OBJECT_ID('tb_religion') > 0 drop table tb_religion;
go

create table dbo.tb_modules (
    id int, 
    description varchar(20), 
    tablename varchar(255)
);

insert into tb_modules values (  1, 'UserType', 'tb_usertype');
insert into tb_modules values (  2, 'Religion', 'tb_religion');

create table dbo.tb_value(
    id int,
    tb_modules_ID int,
    usertype_OR_religion_ID int
);
insert into tb_value values (   1111, 1, 45);
insert into tb_value values (   1112, 1, 55);
insert into tb_value values (   1113, 2, 123);
insert into tb_value values (   1114, 2, 234);

create table dbo.tb_usertype(
    id int,
    UserType varchar(30)
);

insert into tb_usertype values ( 45, 'User_type_45');
insert into tb_usertype values ( 55, 'User_type_55');

create table dbo.tb_religion(
    id int,
    Religion varchar(30)
);

insert into tb_religion values ( 123, 'Religion_123');
insert into tb_religion values ( 234, 'Religion_234');

-- start of query

declare @sql varchar(max) = null

Select @sql = case when @sql is null then '          ' else @sql + char(10) + 'union all '  end 
    + 'Select ' + str(id) + ' type, id, ' + description + ' description from '  + tablename  from   tb_modules 

set @sql = 'select  v.id, tb_modules_ID , usertype_OR_religion_ID , t.description
from tb_value v
    join ( ' + @sql + ') as t
on v.tb_modules_ID = t.type and v.usertype_OR_religion_ID = t.id
'

Print @sql
exec( @sql)
于 2011-01-23T22:53:39.690 に答える
1

まず、現在の設計を使用する唯一の合理的なソリューションは、動的 SQL です。適切なテーブル名を照会し、その場でクエリを構築するモジュールを中間層に記述する必要があります。T-SQL でそれを達成しようとするのは悪夢です。T-SQL は、文字列の構築用に設計されていません。

正しい解決策は、適切に設計された新しいデータベースを構築し、データを移行して既存の設計を廃止することです。現在の設計で遭遇する問題は単純に大きくなります。新しい開発者が新しいシステムを習得するのは難しくなります。エラーが発生しやすくなります。データの整合性はありません (たとえば、属性「開始日」を強制的に日付として解析可能にするなど)。カスタム クエリを作成するのは面倒です。最終的には、現在の設計では、システムから必要な種類の情報を抽出するのが非常に困難になる日が来るでしょう。

于 2011-01-19T16:38:17.310 に答える
1

うーん..おそらくより良い解決策が利用可能ですが、ここに私の5セントがあります:

SELECT 
id,tb_modules_ID,usertype_OR_religion_ID,
COALESCE(
 (SELECT TITLE FROM tb_usertype WHERE Id = usertype_OR_religion_ID),
 (SELECT RELIGIONNAME FROM tb_religion WHERE Id = usertype_OR_religion_ID),
 'N/A'
) AS SourceTable
FROM tb_valuehere

現在、ステートメントをチェックする可能性がないことに注意してください。そのため、構文エラーが発生しないように予約しています...

于 2011-01-12T14:03:27.197 に答える
1

まず、デザイナーではない人を追い出し、悲惨な状況から解放します。彼らは人々を傷つけています。

  • モジュールにを追加するたびに、それを使用するすべてのクエリを変更する必要があります。www.dailywtf.com に適しています。

  • this_or_that 列に FK を定義できないため、参照整合性もありません。あなたのデータは、おそらく同じ設計者によって書かれた「コード」にさらされています。ここでデッドロックが発生することを認識していることは間違いありません。

  • それが「判断」であること、つまり、設計解除の重大性を理解し、それを置き換えることを正当化できるようにするためです。

  • SQL はリレーショナル データベース用に設計されました。つまり、正規化されています。壊れたファイルには適していません。確かに、一部のクエリは他のクエリよりも優れている場合があります (回答を見てください) が、未設​​計を回避する方法はありません。SQL クエリは機能しなくなり、モジュール行が追加されるたびに変更する必要があります。

  • 「動的」はデータベース用に予約されており、フラット ハエには使用できません。

2つの答え。モジュール行が追加されるたびに既存のクエリを変更するという馬鹿げたことをやめるためのもの (どういたしまして)。2番目にあなたの質問に答えます。

安全な未来のクエリ

CREATE VIEW UserReligion_vw AS
    SELECT  [XxxxId]     = id,    -- replace Xxxx
            [ReligionId] = usertype_OR_religion_ID
        FROM  tb_value
        WHERE tb_modules_ID = 1

CREATE VIEW UserReligion_vw AS SELECT [XxxxId] = id, [ReligionId] = usertype_OR_religion_ID FROM tb_value WHERE tb_modules_ID = 2

これからは、現在 undesign を使用しているすべてのクエリが、代わりに正しいビューを使用するように変更されていることを確認してください。ビューを更新/削除/挿入に使用しないでください。

答え

さて、主な質問です。他のアプローチも考えられますが、これがベストです。あなたは、3 番目の列も正規化されていない鶏の排泄物とTitle[EITHER_Religion_OR_UserType_OR_This_OR_That] の供給にしたいと述べました。そうですね、ユーザーにも混乱するように教えています。モジュールの数が増えると、列に何が含まれているかを理解するのがとても楽しくなります。はい、問題は常に複雑になります。

    SELECT  [XxxxId]   = id,
            [Whatever] = CASE tb_modules_ID
                WHEN 1 THEN ( SELECT name      -- title, whatever
                    FROM  tb_religion
                    WHERE id = V.usertype_OR_religion_ID 
                    )
                WHEN 2 THEN ( SELECT name      -- title, whatever
                    FROM  tb_usertype
                    WHERE id = V.usertype_OR_religion_ID 
                    )
                ELSE "(UnknownModule)"         -- do not remove the brackets
                END
        FROM  tb_value V
        WHERE conditions...                    -- you need something here
これは、相関スカラー サブクエリと呼ばれます。

  • 4.9.2 以降のすべてのバージョンの Sybase で制限なく動作します。そして SQL 2005 (最後に見たのは、とにかく、2009 年 8 月)。tb_valueただし、MS では、ボリュームが大きい場合は StackTrace を取得するため、WHERE句にいくつかの条件があることを確認してください。

  • しかし、MS は「新しい」2008 コードラインでサーバーを壊したため、すべての状況で機能するとは限りません (破損したファイルが悪いほど機能する可能性は低くなり、データベース設計が優れているほど機能する可能性が高くなります)。そのため、次のサービス パックのために毎日祈る MS の人々もいれば、教会にまったく出席しない人々もいます。

于 2011-01-22T11:07:32.747 に答える
-1

動的SQLで使用することを意図していると思います。

おそらく、各 tb_value.tb_modules_ID 行を、tb_modules.tablename で名前を付けた独自の一時テーブルに分割します。

次に、命名規則(接頭辞または接尾辞による)に一致する一時テーブルを繰り返し処理して、SQLを構築し、結合を実行します。

于 2011-01-21T21:54:37.643 に答える