7

私はそれが問題ではないことを知っています...とにかくここに問題があります。

このような1つのテーブルを持つデータベースを継承しました。その目的は、さまざまな(200の奇数)国で見つかった種を記録することです。

ID 
Species
Afghanistan
Albania
Algeria
American Samoa
Andorra
Angola
....
Western Sahara
Yemen
Zambia
Zimbabwe

データのサンプルは次のようになります

id Species Afghanistan Albania American Samoa
1  SP1         null     null        null
2  SP2          1         1         null
3  SP3         null      null         1

これは典型的な多対多の状況であり、3つのテーブルが必要なようです。種、国、およびSpeciesFoundInCountry

リンクテーブル(SpeciesFoundInCountry)には、speciesテーブルとCountryテーブルの両方に外部キーがあります。

(図を描くのは難しいです!)

Species
SpeciesID  SpeciesName

Country
CountryID CountryName

SpeciesFoundInCountry
CountryID SpeciesID

元のメガテーブルに1がある列名とSpeciesIDに基づいて、新しいCountryテーブルからCountryIDを取得する挿入ステートメントを生成する魔法の方法はありますか?

私は1つの国のためにそれを行うことができます(これは私が欲しいものを示すための選択です)

SELECT Species.ID, Country.CountryID
FROM Country, Species
WHERE (((Species.Afghanistan)=1)) AND (((Country.Country)="Afghanistan"));

(メガテーブルは種と呼ばれます)

ただし、この戦略を使用すると、元のテーブルの各列に対してクエリを実行する必要があります。

SQLでこれを行う方法はありますか?

where句をまとめて、またはSQLを作成するためのスクリプトを作成することはできますが、エレガントではないようです。

何か考え(または説明が必要)?

4

20 に答える 20

8

これは1回限りのインポートプロセスであるため、スクリプトを使用してすべての個別のクエリを生成します。

Excelなどの一部のプログラムは、データのさまざまな次元を混合するのに適していますが(列名を行内のデータと比較する)、リレーショナルデータベースがそうであることはめったにありません。

ただし、一部のシステム(Microsoft Accessなど)には、データを正規化するために使用できる便利なツールがある場合があります。個人的には、スクリプトを書く方が早いと思いますが、Accessとスクリプトに関する相対的なスキルは私のものとは異なる場合があります。

于 2008-09-16T21:00:37.480 に答える
8

なぜSQLでそれをしたいのですか?変換を行う小さなスクリプトを作成するだけです。

于 2008-09-16T20:58:26.033 に答える
3

これらに遭遇したとき、SQLで変換を実行しようとするのではなく、変換を実行するスクリプトを記述します。通常、私にとってははるかに高速で簡単です。使い慣れた言語を選択してください。

于 2008-09-16T21:01:38.380 に答える
2

これが SQL Server の場合、Unpivot コマンドを使用しますが、割り当てたタグを見ると、アクセス用です。そうですか?

access には ピボット コマンドがありますが、reverse ステートメントはありません。

複雑な結合で実行できるようです。選択コマンドでピボットを解除する方法の詳細については、この興味深い記事を確認してください。

于 2008-09-16T21:24:02.760 に答える
1

おそらく、代わりのテーブルを適切に作成する必要があります。スクリプトの種類は、使用可能なスクリプト言語によって異なりますが、現在使用しているテーブルの列を一覧表示するだけで、国IDテーブルを作成できるはずです。それが済んだら、いくつかの文字列置換を実行して、すべての一意の国名を調べ、指定された国の列がnullではないspeciesFoundInCountryテーブルに挿入できます。

于 2008-09-16T20:59:46.233 に答える
1

おそらく賢くなり、システムテーブルで列名をクエリしてから、動的クエリ文字列を作成して実行することもできますが、正直なところ、SQLステートメントを生成するための簡単なスクリプトよりも醜いでしょう。

コードベースに埋め込まれている古いテーブルにアクセスする動的SQLコードが多すぎないことを願っています。それは本当に難しい部分かもしれません。

于 2008-09-16T21:01:43.747 に答える
1

すべての列のクエリを使用してSQLを生成するための小さなスクリプトを作成するというあなたの提案に間違いなく同意します。

実際、この魔法のクエリについて考えた時間内に、スクリプトはすでに完成している可能性があります(1回だけ使用してから破棄するので、すべてを魔法のように完璧にするための用途は何ですか)。

于 2008-09-16T21:10:32.353 に答える
1

申し訳ありませんが、Accessプログラミングはほとんど行っていませんが、役立つガイダンスを提供できます。

まず、問題をウォークスルーしましょう。通常、元のテーブルのすべての行について、SpeciesFoundInCountryに複数の行を生成する必要があると想定されています。言い換えれば、種は複数の国に存在する傾向があります。これは、デカルト積、つまり結合基準のない結合で実際に行うのは簡単です。

デカルト積を実行するには、Countryテーブルを作成する必要があります。テーブルには、1からNまでのcountry_id(Nは一意の国の数である200程度)と国名が含まれている必要があります。生活を楽にするために、列順に1からNまでの数字を使用してください。これにより、アフガニスタン1とアルバニア2...ジンバブエNになります。これを行うにはシステムテーブルを使用できるはずです。

次に、元のテーブルからテーブルまたはビューを作成します。このテーブルには、国ごとに0または1の種と刺し傷が含まれています。nullではなくnullをテキスト0または1に変換し、すべての値を1つの文字列に連結する必要があります。テーブルの説明と正規表現を使用したテキストエディタを使用すると、これが簡単になります。最初に1つの列で実験し、それが機能したら、すべての列でビューの作成/挿入を編集します。

次に、結合基準なしで2つのテーブルを結合します。これはあなたにすべての国のすべての種の記録を与えるでしょう、あなたはほとんどそこにいます。

これで、無効なレコードを除外するだけで、文字列の対応する場所にゼロが表示されます。国テーブルのcountry_code列にはサブストリングの場所があるため、0のレコードをフィルターで除外するだけです。

where substring(new_column,country_code) = '1'

種のテーブルを作成してそれに参加する必要があります

where a.species_name = b.species_name

aとbはテーブルエイリアスです。

この助けを願っています

于 2008-09-16T23:54:20.307 に答える
1

同様の SQL ステートメントを大量に作成し、それらすべてを実行する必要がある場合、Excel が非常に便利であることがよくわかります。元のクエリを取得します。列 A に国のリストがあり、列 B に SQL ステートメントがあり、SQL で国が表示される場所にセル参照が挿入された (引用符で囲まれた) テキストとして書式設定されている場合

例 ="INSERT INTO new_table SELECT ... (species." & A1 & ")= ... ));"

次に、数式をコピーして 200 の異なる SQL ステートメントを作成し、列をエディターにコピーして貼り付け、F5 を押します。もちろん、必要な数の変数を使用してこれを行うことができます。

于 2008-09-23T03:59:26.960 に答える
1

SQL Server では、これにより、デモで示したカスタム選択が生成されます。インサートに外挿できます

select 
  'SELECT Species.ID, Country.CountryID FROM Country, Species WHERE (((Species.' + 
 c.name + 
 ')=1)) AND (((Country.Country)="' +
 c.name + 
 '"))'
from syscolumns c
inner join sysobjects o
on o.id = c.id
where o.name = 'old_table_name'
于 2008-09-16T21:03:02.793 に答える
1

他の人たちと同じように、私はおそらく、あなたにとってどんな方法でも、一度だけの簡単な修正としてそれを行うでしょう.

これらのタイプの変換では、それらは 1 回限りのアイテムであり、迅速な修正であり、コードはエレガントである必要はなく、機能する必要があります。これらのタイプのことについて、私は多くの方法でそれを行ってきました。

于 2008-09-16T21:03:36.210 に答える
1

これが SQL Server の場合、sys.columns テーブルを使用して、元のテーブルのすべての列を検索できます。次に、動的 SQL とピボット コマンドを使用して、必要なことを行うことができます。構文については、オンラインで調べてください。

于 2008-09-16T21:03:46.740 に答える
1

非常に大まかに、ユニオンクエリを使用します。

Dim db As Database
Dim tdf As TableDef

Set db = CurrentDb

Set tdf = db.TableDefs("SO")

strSQL = "SELECT ID, Species, """ & tdf.Fields(2).Name _
    & """ AS Country, [" & tdf.Fields(2).Name & "] AS CountryValue FROM SO "

For i = 3 To tdf.Fields.Count - 1
    strSQL = strSQL & vbCrLf & "UNION SELECT ID, Species, """ & tdf.Fields(i).Name _
    & """ AS Country, [" & tdf.Fields(i).Name & "] AS CountryValue FROM SO "
Next

db.CreateQueryDef "UnionSO", strSQL

これで、新しいデザインに追加できるビューが作成されます。

于 2008-09-16T23:13:02.497 に答える
1

OBTW、

古いテーブルに対して既に実行されているクエリがある場合は、新しいテーブルを使用して古いテーブルを複製するビューを作成する必要があります。テーブルを非正規化するには、group by を実行する必要があります。

古いテーブル/ビューは今後サポートされなくなり、すべての新しいクエリまたは古いクエリの更新では新しいテーブルを使用する必要があることをユーザーに伝えてください。

于 2008-09-17T00:02:16.327 に答える
1

@ストンプ:

答えを入力するボックスの上に、いくつかのボタンがあります。101010 はコードサンプルです。コードであるすべてのテキストを選択し、そのボタンをクリックします。それならあまり混まない。

cout>>"I don't know C"
cout>>"Hello World"
于 2008-09-16T22:51:27.510 に答える
1

SpeciesFoundInCountry テーブルに一時的な変更を加えて、3 ステップのプロセスにします。そのテーブルに列を追加して、国名を格納します。次に、手順は次のようになります。

1) ソース テーブルの列をたどり、真の値を持つ各列の SpeciesFoundInCountry にレコードを作成するスクリプトを作成/実行します。このレコードには国名が含まれます。2) Country Name の Country テーブルに結合して SpeciesFoundInCountry.CountryID フィールドを更新する SQL ステートメントを実行します。3) CountryName 列を削除して、SpeciesFoundInCountry テーブルをクリーンアップします。

要点を説明するための小さな MS Access VB/VBA 疑似コードを次に示します。

Public Sub CreateRelationshipRecords()

  Dim rstSource as DAO.Recordset
  Dim rstDestination as DAO.Recordset
  Dim fld as DAO.Field
  dim strSQL as String
  Dim lngSpeciesID as Long

  strSQL = "SELECT * FROM [ORIGINALTABLE]"
  Set rstSource = CurrentDB.OpenRecordset(strSQL)
  set rstDestination = CurrentDB.OpenRecordset("SpeciesFoundInCountry")

  rstSource.MoveFirst

  ' Step through each record in the original table
  Do Until rstSource.EOF
    lngSpeciesID = rstSource.ID
    ' Now step through the fields(columns). If the field
    ' value is one (1), then create a relationship record
    ' using the field name as the Country Name
    For Each fld in rstSource.Fields
      If fld.Value = 1 then
        with rstDestination
          .AddNew
          .Fields("CountryID").Value = Null
          .Fields("CountryName").Value = fld.Name
          .Fields("SpeciesID").Value = lngSpeciesID
          .Update
        End With
      End IF
    Next fld  
    rstSource.MoveNext
  Loop

  ' Clean up
  rstSource.Close
  Set rstSource = nothing
  ....

End Sub

この後、簡単な SQL ステートメントを実行して、SpeciesFoundInCountry テーブルの CountryID 値を更新できます。

UPDATE SpeciesFoundInCountry INNER JOIN Country ON SpeciesFoundInCountry.CountryName = Country.CountryName SET SpeciesFoundInCountry.CountryID = Country.CountryID;

最後に、CountryName 列を削除して SpeciesFoundInCountry テーブルをクリーンアップするだけです。

****補足: ISO 略語 (国コード) を含む国別表があると便利です。Country テーブルへの結合をクエリに含める必要がないように、これらは他のテーブルの外部キーとして使用されることがあります。

詳細情報: http://en.wikipedia.org/wiki/Iso_country_codes

于 2008-09-16T21:55:51.560 に答える
1

同様の問題に直面したとき、SQL スクリプトを生成するスクリプトを生成すると便利であることがわかりました。これは、アフガニスタンの代わりに %PAR1% を使用するように抽象化された、あなたが提供したサンプルです。

SELECT Species.ID, Country.CountryID
FROM Country, Species
WHERE (((Species.%PAR1%)=1)) AND (((Country.Country)="%PAR1%"))
UNION

また、すべての選択を結合する方法として、キーワード union が追加されました。

次に、既存のデータから生成された国のリストが必要です。

アフガニスタン アルバニア 、 。

次に、国リストを反復処理できるスクリプトが必要です。反復ごとに、最初の反復で %PAR1% をアフガニスタンに置き換え、2 回目の反復でアルバニアに置き換えるなどの出力を生成します。このアルゴリズムは、ワード プロセッサでの差し込み印刷のようなものです。このスクリプトを書くのはちょっとした作業です。ただし、一度取得すると、このような 1 回限りのプロジェクトで何十回も使用できます。

最後に、最後の「UNION」を手動でセミコロンに戻す必要があります。

Access でこの巨大な和集合を実行できれば、必要なデータを必要な形式で取得し、それを新しいテーブルに挿入できます。

于 2008-10-22T11:59:56.013 に答える
1

申し訳ありませんが、血まみれの投稿パーサーが私の投稿の空白とフォーマットを削除しました。ログが読みにくくなります。

于 2008-09-16T21:57:48.903 に答える
1

「まずい BAD データベース設計」というタイトルを読んだとき、それがどれほど悪いのか知りたいと思いました。あなたは私を失望させませんでした:)

他の人が言ったように、スクリプトが最も簡単な方法です。これは、PHP で約 15 行のコードを記述することで実現できます。

SELECT * FROM ugly_table;
while(row)
foreach(row as field => value)
if(value == 1)
SELECT country_id from country_table WHERE country_name = field;

if(field == 'Species')
SELECT species_id from species_table WHERE species_name = value;

INSERT INTO better_table (...)

明らかにこれは疑似コードであり、そのままでは機能しません。ここに挿入ステートメントを追加することで、国と種のテーブルをオンザフライで入力することもできます。

于 2008-09-16T23:30:41.097 に答える
1

これは (願わくは) 1 回限りの演習であるため、洗練されていないソリューションは、思ったほど悪くはないかもしれません。

問題は (あなたもお気づきだと思いますが!)、クエリのある時点で、これらすべての列をリストしなければならないことです。:( 問題は、これを行うための最もエレガントな方法は何ですか?以下は私の試みです。非常に多くの列があるため扱いにくいように見えますが、それはあなたが求めているものかもしれませんし、少なくともそれはあなたを正しい方向。

考えられる SQL ソリューション:

/* if you have N countries */
CREATE TABLE Country
(id    int, 
 name  varchar(50)) 

INSERT Country
      SELECT 1, 'Afghanistan'
UNION SELECT 2, 'Albania', 
UNION SELECT 3, 'Algeria' ,
UNION SELECT 4, 'American Samoa' ,
UNION SELECT 5, 'Andorra' ,
UNION SELECT 6, 'Angola' ,
...
UNION SELECT N-3, 'Western Sahara', 
UNION SELECT N-2, 'Yemen', 
UNION SELECT N-1, 'Zambia', 
UNION SELECT N, 'Zimbabwe', 



CREATE TABLE #tmp
(key        varchar(N),  
 country_id int) 
/* "key" field needs to be as long as N */  


INSERT #tmp 
SELECT '1________ ... _', 'Afghanistan' 
/* '1' followed by underscores to make the length = N */

UNION SELECT '_1_______ ... ___', 'Albania'
UNION SELECT '__1______ ... ___', 'Algeria'
...
UNION SELECT '________ ... _1_', 'Zambia'
UNION SELECT '________ ... __1', 'Zimbabwe'

CREATE TABLE new_table
(country_id int, 
species_id int) 

INSERT new_table
SELECT species.id, country_id
FROM   species s , 
       #tmp    t
WHERE  isnull( s.Afghanistan, ' ' ) +  
       isnull( s.Albania, ' ' ) +  
       ... +  
       isnull( s.Zambia, ' ' ) +  
       isnull( s.Zimbabwe, ' ' ) like t.key 

私のおすすめ

個人的には、私はこれをしません。国IDをハードコードすることを除いて、あなたがほのめかしているような手っ取り早い解決策を実行します(これは一度しか実行しないためですよね?そして、作成した直後に実行できます国テーブル、すべての ID が何であるかがわかります):

INSERT new_table SELECT Species.ID, 1 FROM Species WHERE Species.Afghanistan = 1 
INSERT new_table SELECT Species.ID, 2 FROM Species WHERE Species.Albania= 1 
...
INSERT new_table SELECT Species.ID, 999 FROM Species WHERE Species.Zambia= 1 
INSERT new_table SELECT Species.ID, 1000 FROM Species WHERE Species.Zimbabwe= 1 
于 2008-10-13T14:07:44.683 に答える