Frage

Ich weiß, dass das nicht eine Frage ist ... erm sowieso hier die Frage.

Ich habe eine Datenbank geerbt, die 1 (eins) Tabelle hat in so viel wie folgt aussehen. Sein Ziel ist es, welche Arten zu erfassen sind in den verschiedenen (200 ungerade) Ländern.

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

Eine Probe der Daten etwas so sein würde

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

Es scheint mir, ist dies eine typische viele zu viele Situation und ich möchte 3 Tabellen. Spezies, im Land und SpeciesFoundInCountry

Die Verknüpfungstabelle (SpeciesFoundInCountry) habe Fremdschlüssel in beiden Spezies und Land-Tabellen.

(Es ist schwer, das Diagramm zu zeichnen!)

Species
SpeciesID  SpeciesName

Country
CountryID CountryName

SpeciesFoundInCountry
CountryID SpeciesID

Gibt es eine magische Art und Weise ich eine Insert-Anweisung erzeugen kann, die die CountryID aus der neuen Land Tabelle erhalten werden basierend auf den Spaltennamen und die SpeciesID wo es ein 1 in der ursprünglichen Mega-Tabelle ist?

Ich kann es für ein Land (dies ist ein wählen zu zeigen, was ich will raus)

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

(die Mega-Tabelle Spezies genannt)

Aber mit dieser Strategie, die ich brauchen würde, um die Abfrage für jede Spalte in der ursprünglichen Tabelle zu tun.

Gibt es eine Möglichkeit, dies in SQL zu tun?

Ich glaube, ich kann oder eine Last von meinen where-Klauseln zusammen und ein Skript schreiben, um die SQL zu machen, scheint unelegant aber!

Alle Gedanken (oder Klarstellung erforderlich)?

War es hilfreich?

Lösung

Ich würde ein Skript verwenden, um alle Einzelabfragen zu erzeugen, da es sich um eine einmalige Importvorgang.

Einige Programme wie Excel sind gut in verschiedene Dimensionen des Datenmisch (Spaltennamen, um Daten innerhalb Reihen zu vergleichen), aber relationale Datenbanken selten sind.

Allerdings könnten Sie feststellen, dass einige Systeme (wie zB Microsoft Access, überraschend) haben praktische Werkzeuge, die Sie die Daten normalisieren können. Ich persönlich würde es schneller finde das Skript zu schreiben, aber Ihre relativen Fähigkeiten mit Zugang und Skripting könnten Mine unterschiedlich sein.

Andere Tipps

Warum wollen Sie es in SQL zu tun? Schreiben Sie einfach ein kleines Skript, das die Umwandlung der Fall ist.

Wenn ich in diesen laufe schreibe ich ein Skript, um die Konvertierung zu tun, anstatt zu versuchen, es in SQL zu tun. Es ist in der Regel viel schneller und einfacher für mich. Egal auf welche Sprache Sie sind komfortabel mit.

Wenn dieser SQL Server ist, können Sie den Unpivot Befehle verwenden würden, aber wenn man den Tag Sie es für den Zugriff zugewiesen ist - ist ich richtig

Es gibt zwar eine Schwenkbefehl Zugang , gibt es keine Rückwärts Aussage.

Sieht aus wie es mit einem komplexen getan werden kann mitmachen. Sehen Sie sich diese interessanten Artikel für eine lowdown rel="nofollow, wie man Entpivotisierung in einem Auswahlbefehl.

Sie gehen zu wollen, wahrscheinlich Ersatz Tabellen an seinem Platz zu schaffen. Das Skript Art hängt von auf der Skriptsprache zur Verfügung haben, aber Sie sollten die Land-ID-Tabelle einfach durch Auflisten der Spalten der Tabelle haben Sie jetzt erstellen können. Sobald Sie das getan haben, können Sie einige String-Ersetzungen tun durch alle eindeutigen Ländernamen zu gehen und in das speciesFoundInCountry Tabelle, in der die bestimmten Land Spalte nicht null ist.

Sie könnten wahrscheinlich klug erhalten und die Systemtabellen für die Spaltennamen abfragen und dann eine dynamische Abfrage-String bauen auszuführen, aber ehrlich gesagt, dass wahrscheinlich hässlicher als eine schnelle Skript die SQL-Anweisungen für Sie zu generieren.

Hoffentlich Sie nicht zu viel dynamische SQL-Code, der die alten Tabellen in Ihrer Code-Basis begraben zugreift. Das könnte die wirklich harten Teil sein.

In SQL Server wird dies generieren Ihre benutzerdefinierten wählen Sie demonstrieren. Sie können auf einen Einsatz extrapolieren

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'

Wie bei den anderen würde ich wahrscheinlich nur tun es als eine einmalige schnelle Lösung in welcher Weise auch immer für Sie arbeitet.

Mit dieser Art von Umwandlungen, sie sind ein Sondereffekte, schnelle Lösungen, und der Code muss nicht elegant sein, es muss nur arbeiten. Für diese Art von Dingen, die ich habe es viele Arten erfolgen.

Wenn diese SQL Server ist, können Sie die sys.columns Tabelle verwenden, um alle Spalten der ursprünglichen Tabelle zu finden. Dann können Sie dynamische SQL und die Pivot-Befehl verwenden, um zu tun, was Sie wollen. Schauen die Sie sich online für Syntax.

Ich würde auf jeden Fall mit Ihrem Vorschlag zu schreiben, ein kleines Skript zustimmen Ihre SQL mit einer Abfrage für jede Spalte zu erzeugen.

In der Tat Ihr Skript bereits in der Zeit abgeschlossen wurde, könnten Sie haben über diese magische Abfrage verbrachten denken (die Sie nur einmal verwenden würden und dann wegwerfen, so was nützt das alles magicy und perfekt in der Herstellung)

Es tut uns Leid, aber die blutigen Posting-Parser entfernt die Leerzeichen und Formatierung auf meinem Posten. Es macht es ein Protokoll schwerer zu lesen.

@stomp:

über das Feld, in dem Sie die Antwort geben, gibt es mehrere Tasten. Die eine, die 101010 ist, ist ein Code-Beispiel. Sie wählen alle Text, der Code ist, und dann diese Schaltfläche klicken. Dann ist es nicht mit viel verwirrt erhalten.

cout>>"I don't know C"
cout>>"Hello World"

würde ich eine Union-Abfrage verwenden, ganz grob:

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

Sie würden dann eine Ansicht, die zu Ihrem neuen Design angehängt werden können.

Als ich den Titel ‚bad BAD Datenbank-Design‘ las, war ich neugierig, um herauszufinden, wie schlimm es ist. Sie hat mich nicht enttäuscht:)

Wie andere schon erwähnt, würde ein Skript der einfachste Weg sein. Dies kann durch das Schreiben über 15 Zeilen Code in PHP erreicht werden.

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 (...)

Offensichtlich ist diese Pseudo-Code ist und wird nicht funktionieren, wie es ist. Sie können auch die Länder und Arten Tabelle on the fly bevölkern von Insert-Anweisungen hier hinzufügen.

Sorry, ich habe sehr wenig Zugang Programmierung getan, aber ich kann einige Hinweise bieten, die helfen sollen.

Zuerst lässt durch das Problem gehen. Es wird angenommen, dass Sie in der Regel mehr Zeilen in SpeciesFoundInCountry für jede Zeile in der ursprünglichen Tabelle generieren müssen. Mit anderen Worten neigen Arten in mehr als einem Land zu sein. Dies ist eigentlich einfach, mit einem cartesianischen Produkt zu tun, eine Verknüpfung mit keinen Kriterien beizutreten.

ein kartesisches Produkt zu tun, müssen Sie die Ländertabelle erstellen. Die Tabelle sollte die country_id von 1 bis N und Ländernamen (N die Anzahl der einzelnen Länder, 200 oder so zu sein). Um Ihnen das Leben einfach nur die Zahlen 1 bis N in Spaltenreihenfolge verwenden. Das würde Afghanistan 1 und Albanien 2 ... Simbabwe N. Sie sollen in der Lage, die Systemtabellen zu verwenden, um dies zu tun.

Als nächstes eine Tabelle oder eine Ansicht aus der ursprünglichen Tabelle erstellen, die die Art und einen Stich mit einem 0 oder 1 für jedes Land enthält. Sie müssen die null, nicht null auf einen Text 0 oder 1 und verketten alle Werte in einer einzigen Zeichenfolge konvertieren. Eine Beschreibung der Tabelle und ein Texteditor mit regulären Ausdrücken sollte dies einfach machen. Experimentieren Sie zunächst mit einer einzigen Spalte und sobald das funktioniert bearbeiten die Ansicht erstellen / einfügen mit allen Spalten.

Als nächstes kommen Sie mit den beiden Tabellen zusammen mit nicht beitreten Kriterien. Dadurch erhalten Sie einen Datensatz für jede Art in jedem Land, sind Sie fast da.

Alles was Sie jetzt tun müssen, ist die Datensätze herauszufiltern, die nicht gültig sind, werden sie eine Null in der entsprechenden Stelle in der Zeichenfolge haben. Da die country_code Spalte Ländertabelle die Teil Lage hat alles, was Sie tun müssen, um die Datensätze herauszufiltern, wo es 0 ist.

where substring(new_column,country_code) = '1'

Sie müssen noch die Artentabelle erstellen und zu diesem beitreten

where a.species_name = b.species_name

a und b Tabelle Aliase.

Hope this help

OBTW,

Wenn Sie Fragen haben, die bereits gegen die alte Tabelle ausführen können, müssen Sie eine Ansicht erstellen, die die alten Tabellen mit den neuen Tabellen repliziert. Sie müssen eine Gruppe tun, indem die Tabellen denormalize.

Lassen Sie Ihre Benutzer, dass die alte Tabelle / View wird nicht in die Zukunft und alle neuen Abfragen oder Aktualisierungen auf ältere Anfragen unterstützt werden die neuen Tabellen verwenden.

Wenn ich jemals eine Lkw-Ladung von ähnlichen SQL-Anweisungen erstellen müssen, und führen Sie alle von ihnen, finde ich oft Excel sehr praktisch ist. Nehmen Sie Ihre ursprüngliche Abfrage. Wenn Sie eine Länderliste in der Spalte A und die SQL-Anweisung in Spalte B, formatierte als Text (in Anführungszeichen) mit Zellbezug eingefügt, wo das Land wird in der SQL

z. = "INSERT INTO new_table SELECT ... (Art." & A1 & ") = ...));"

dann kopieren Sie einfach die Formel nach unten 200 verschiedene SQL-Anweisungen zu erstellen, kopieren / einfügen um die Spalte zu Ihrem Editor und drücken Sie F5. Sie können dies natürlich tun mit so vielen Variablen, wie Sie wollen.

Wenn ich habe mit ähnlichen Problemen konfrontiert, habe ich finde es bequemer, ein Skript zu generieren, die SQL-Skripte generiert. Hier ist die Probe Sie gab, abstrahiert% PAR1% anstelle von Afghanistan verwendet werden.

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

Auch die Schlüsselwort union wurde als eine Möglichkeit hinzugefügt, alle wählen zu kombinieren.

Als nächstes müssen Sie eine Liste der Länder, generiert aus den vorhandenen Daten:

Afghanistan Albanien . . .

Als Nächstes werden Sie einen Skript benötigen, die durch die Länderliste laufen können, und für jede Iteration, erzeugen eine Ausgabe, die Afghanistan für% PAR1% bei der ersten Iteration, Albanien für die zweite Iteration ersetzt und so weiter. Der Algorithmus ist wie E-Mail-Merge in einem Textverarbeitungsprogramm. Es ist eine wenig Arbeit dieses Skript zu schreiben. Aber, wenn Sie es haben, können Sie es in Dutzenden von Einzelprojekten wie diese verwenden können.

Schließlich müssen Sie manuell die letzte „UNION“ zu einem Semikolon wieder ändern.

Wenn Sie Zugang erhalten können diese riesige Union ausführen, können Sie die Daten erhalten Sie in Form wollen Sie wollen, und es in die neue Tabelle einfügen.

Ich würde es macht einen dreistufiger Prozess mit einer leichten vorübergehenden Änderung Ihrer SpeciesFoundInCountry Tabelle. Ich würde eine Spalte der Tabelle fügen Sie die Ländernamen zu speichern. Dann würden die Schritte wie folgt.

1) Erstellen / Ausführen eines Skripts, die Spalten in der Quelltabelle geht und erstellt einen Datensatz in SpeciesFoundInCountry für jede Spalte, die einen wahren Wert hat. Dieser Datensatz würde den Namen des Landes enthält. 2) Führen Sie eine SQL-Anweisung, die das SpeciesFoundInCountry.CountryID Feld aktualisiert, indem Sie auf Land Namen auf das Land Tabelle verbinden. 3) Cleanup der SpeciesFoundInCountry Tabelle durch die Country Spalte zu entfernen.

Hier ist ein kleiner MS Access VB / VBA Pseudo-Code, der Ihr den Kern geben

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

Danach Sie eine einfache SQL-Anweisung ausführen könnten die CountryID Werte in der SpeciesFoundInCountry Tabelle zu aktualisieren.

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

Schließlich alles, was Sie tun müssen, ist die Bereinigung SpeciesFoundInCountry Tabelle durch die Country Spalte zu entfernen.

**** Randbemerkung: Ich fand es usefull Ländertabellen zu haben, die auch die ISO-Abkürzungen (Ländercodes) umfassen. Gelegentlich werden sie als Fremdschlüssel in anderen Tabellen verwendet, so dass ein auf das Land Tisch sitzen muss nicht in Abfragen aufgenommen werden.

Für weitere Informationen: http://en.wikipedia.org/wiki/Iso_country_codes

Dies ist (hoffentlich) eine einmalige Übung, so dass eine unelegant Lösung vielleicht nicht so schlimm, wie es klingt.

Das Problem (wie ich bin sicher, Sie wissen nur zu gut sind!) Ist, dass man an einem gewissen Punkt in Ihrer Anfrage haben alle diese Spalten aufzulisten. :( Die Frage ist, was ist die eleganteste Art und Weise, dies zu tun? Im Folgenden mein Versuch ist. Es sperrig aussieht, weil es so viele Spalten sind, aber es könnte sein, was Sie nach, oder zumindest könnte es Ihnen in dem Punkt, richtige Richtung.

Mögliche SQL Lösung:

/* 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 

Mein Vorschlag

Ich persönlich würde das nicht tun. Ich würde tun, um eine schnelle und schmutzige Lösung wie die, auf die Sie anspielen, mit der Ausnahme, dass ich würde hart Code des Land-IDs (weil Sie dies nur einmal tun würden, nicht wahr? Und Sie können es richtig nach dem Erstellen des Ländertabelle, so dass Sie wissen, was alle IDs sind):

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 
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top