1

SQL2005ダイナミックテーブルデザイン(共通のルックアップテーブル)、値

これは私の簡単な例で取得するにはすてきなクエリを必要とする:

(実際にここで40個の以上のテーブルがある、私は2を示しました)

私は3列(ID、説明、varchar型としてテーブル名)で、tb_modulesと呼ばれるテーブルを得た:

1, UserType, tb_usertype 
2, Religion, tb_religion 

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

私はこのようになり、他のテーブルを得た: tb_value(コラム:ID、tb_modules_ID、usertype_OR_religion_ID) 値:

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

ので、私が意味する45、55、123、234は(ユーザータイプや宗教IDの です45、55ユーザータイプ、123、234宗教ID`s)

が判断してはいけない、私はデータベースを設計していなかった

質問 にはどうすればtb_value、プラス1列から*示し、選択することができます その1つの列はTのTITLEになりますtb_religionテーブルのb_usertypeまたはRELIGIONNAME

一般的なことをしたいと思います。 最初は多分文字列を返すSQL関数だと思っていましたが、動的SQLが必要だと思います。

誰かが良いアイデアですか?

+0

私はこれには動的SQLが必要だと思っていますが、私はそれがあなたのクエリでも大丈夫にはならないでしょう。 – Lamak

+1

実際の答えは、「新しい設計を構築する」という特別な操作を呼び出す必要があるということです。 – Thomas

+0

下のKen Downのソリューションをご覧ください。このソリューションは、UNIONビューを使用して構造を本質的に修正します(そして、あなたの「判断しない」要求に従います)。 –

答えて

1

Hm..thereはおそらく利用できる優れたソリューションですが、ここで私の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 

は注意エラー...

+0

私の最大の問題:tb_modulesテーブルに他の "モジュール"を追加すると、クエリに新しい行を追加する必要があります。もっと動的にしたいと思っています... – Ash

+0

それは本当です。アカウントに実際には入れていません。 – Ozzy

+2

@Swoosh別の「モジュール」を追加すると、そのテーブルから選択する必要がある列名をどのように知ることができますか? – Lamak

2

最初はこれがあります。これはかなり面倒です。

alt text

は、クリーンアップするために、私は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 

、それは簡単です

alt text

ようになりましたモデルはここに見えますがクエリを書く

; 
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(またはアプリケーションレベルでのクエリ)を構築する

EDIT

変更線6と7、Xインデックスはtb_modules.id

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

左側に行を追加しています参加する(11行目以降)

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

SomeNametb_modules.descriptionであり、x屈折率が一致しているtb_modules.id

EDIT 2

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

+0

を持つことができます。この問題の問題は、新しい「モジュール」を追加すると、クエリを変更するよりも、 – Ash

+1

@Swoosh - 動的に構築する必要があるということです。 –

+0

@Swoosh。私の答えを読んでください。 「動的」はデータベース用に予約されています。それはmangledファイルでは不可能です。 「顧客」に「ダイナミック」なものを約束しましたか? – PerformanceDBA

1

最初に、現在の設計を使用して唯一合理的な解決策は動的SQLです。中間層には、適切な表名を問い合せ、実行中に問合せを作成するモジュールを作成する必要があります。 T-SQLでそれを達成しようとするのは悪夢です。 T-SQLは文字列作成用に設計されていませんでした。

適切なソリューションは、適切に設計された新しいデータベースを構築し、データを移行して既存の設計をスクラップすることです。あなたの現在のデザインで遭遇する問題は、単に成長するでしょう。新しい開発者が新しいシステムを学ぶのは難しくなります。エラーが発生しやすくなります。データの完全性はありません(例えば、属性「開始日」を日付として解析可能にするなど)。カスタムクエリは、書くなどの面倒な作業になります。最終的には、現在の設計では、システムからの情報の種類が単純に抽出することが困難すぎる日にヒットします。

+0

完璧な世界では、クライアントはあなたにそれを支払うお金を持っていて、それを行う時間を与えるでしょう。 – Ash

+0

@Swoosh。どの先進国でも、Er。あなたがそれらのいずれかにいない場合、十分に公正です。 – PerformanceDBA

+2

@スウォッシュ - 私はその感情に完全に同意しない。既存の設計を続けるために会社の費用がかかるため、将来的には金額が増加します。ニーズに対応できないデータベースを継続して維持することは費用対効果が高く、メンテナンスコストが上昇することはありますか?だから、オプションは本当にあります:今はお金を払い、将来はもっとたくさんのお金を払うか、将来はお金を払うことです。 – Thomas

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例をハードコードビューを定義し、次にあなたが望む特定のモジュールのためのクエリにフィルタを置くことができます。

-1

私はそれが動的SQLで使用されることを意図していると思います。

tb_value.tb_modules_ID行をtb_modules.tablenameという名前の独自の一時表に分割することもできます。

次に、sqlを作成して結合を行うという命名規則(接頭辞または接尾辞)に一致するtempテーブルを繰り返し処理します。

+0

これは "解決策"ではなく、管理、保守などを必要とするまったく新しい問題を生み出します。 – PerformanceDBA

1

最初に貸し手を裏返して、彼らを悲惨さから取り除きます。彼らは人々を傷つけている。それらの無能に

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

  • this_or_that列にFKを定義できないため、参照整合性もありません。あなたのデータは公開されており、おそらくは同じ申請者によって書かれた「コード」になります。これがデッドロックが作成される場所であることに疑いはありません。

  • 「判断」であることは、それがあなたの責任の重大性を理解し、それをあなたのマネージャーに置き換えることを正当化できるようにすることです。

  • SQLは、リレーショナルデータベース用に設計されています。つまり、正規化されたものです。それはmangledファイルには適していません。確かに、いくつかのクエリは他のクエリよりも優れているかもしれませんが(答えを見てください)、その属性を回避する方法はありません.SQLクエリは何も処理されず、Module行が追加されるたびに変更する必要があります。

  • 「ダイナミック」はデータベース用に予約されています。フラットハエでは使用できません。

2つの回答。 1つは、モジュールの行が追加されるたびに既存のクエリを変更するという愚かな行為を止めることです(歓迎します)。あなたの質問に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

From now on, make sure the all queries currently using the undesign, are modified to use the correct View instead. Do not use the Views for Update/Delete/Insert.

Answer

Ok, now for the main question. I can think of other approaches, but this one is the best. You have stated, you want the third column to also be an unnormalised piece of chicken excreta and the supply 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 
This is called a Correlated Scalar Subquery.

  • It works on any version of Sybase since 4.9.2 with no limitations. And SQL 2005 (last time I looked, anyway, Aug 2009). But on MS you will get a StackTrace if the volume of tb_valueが大きいので、WHERE句に条件があることを確認してください。

  • しかし、MSは「新しい」2008コードラインでサーバーを壊してしまったため、すべての状況で機能しません(ファイルが悪化するほど、ファイルがうまく機能しません;データベース設計がうまくいくほどそれが動作します)。そういうわけで、一部のMSの人々は毎日次のサービスパックのために祈り、他の人は決して教会に出席しません。これを行うには

+0

明らかに、これは40個のSELECTsと39個のUNIONより優れています。 – PerformanceDBA

2

動的にあなたはあなたを伝えるDB内の任意の情報を持っていないため、現在、あなたがそれを行うことはできません。この

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 

のように見えるのSQL文を作成できるようにする必要がありますtb_religionとtb_usertypeなどから使用する列。これをtb_moduleの新しいフィールドとして追加できます。

tb_moduleで使用するフィールド名があれば、必要なことをするビューを構築することができます。 そして、tb_modulesテーブルにトリガを追加すると、tb_modulesが変更されるたびにビューが変更されます。そうすれば、クエリを実行するときにクライアントから動的SQLを使用する必要はありません。あなたが心配する必要がある唯一のものは表では、tb_modulesする新しい行を追加する前に、DB内に作成する必要があるということである

トリガー内のコードが動的にALTERビューを構築する必要があるもちろん編集1 ステートメント。

編集2はまたtb_value.extid(usertype_OR_religion_ID)に対して参加するtb_usertypeとtb_religionなどでどのような列に関する情報をフィールドを持っている必要があります。それとも、フィールドは常にid

編集3呼び出されると仮定することができますここでは、ビューv_valuesを変えるtb_moduleにトリガを構築することができる方法です。私はtb_modulesに列としてfieldnameを追加しました。そして、私は関連するテーブルのidフィールドがidと呼ばれると仮定します。単純ですtb_modulesに

追加テーブルとテーブルごとに1つの行:

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.*, '[email protected]+'.'[email protected]+' '+ 
         'from tb_value '+ 
         'inner join '[email protected]+' '+ 
         'on tb_value.extid = '[email protected]+'.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 
+0

うわー。これは面白いアプローチであり、決してこれを考えませんでした。私は本当にトリガーが好きではありませんが、挿入、削除、特定のテーブルの更新でこれを呼び出すことができます... – Ash

1

は、私はあなたがこのような何かをしたいと思います。

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)