data import von Excel in PostgreSQL Datenbank

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
juergenkemeter
User
Beiträge: 11
Registriert: Sonntag 20. November 2005, 22:33

Hi!

ich muss alle Daten aus einem Excel workbook in eine PostgreSQL - Datenbank importieren.

Ich exportiere dazu in Excel die spreadsheets als .csv - Dateien.

Mein momentanes Python Skript importiert dann eine einzelne spreadsheet-csv-Datei, und generiert PostgreSQL Dateien.
Die .psql Dateien beinhalten dann entsprechende SQL Anweisungen, mit denen die Daten aus dem spreadsheet in die Datenbank importiert werden.

Mein Problem momentan:
Das Excel-Workbook beinhaltet mehrere spreadsheets. Diese sind untereinander durch Hyperlinks verbunden, und enthalten manchmal Kommentare in den Zellen.
Wie kann ich mit Python Hyperlinks, und Kommentare in Zellen aus einem spreadsheet auslesen, und in einer Tabelle (Ziel: PostgreSQL-Datenbank) speichern?

Ich kann gerne das Excel workbook bzw. eine Beispiel- .csv-Datei eines spreadsheets per email schicken, falls meine Fragestellung unklar ist!

Hier mein momentanes Python Script:

Code: Alles auswählen

#
# This script prepares a number of psql files to bootstrap data into the
# samson database , from the samples spreadsheet
#
#
#	Gene	Full Name	Abbreviations and Alternative Names	Order	Cellular localisation	Functional Classification	Magnitude of Change	Cycle Stage	Follicular Localisation	Human Chromosome	Weighted Score	Count
#												
#
#	142	Unknown	-	207	Unknown	Unknown	-	-	-	-	30	2
#	143	Unknown	-	207	Unknown	Unknown	-	-	-	-	30	2
#	A2B1	Heterogeneous nuclear ribonucleoproteins A2/B1 	 hnRNP A2 / hnRNP B1, HNRPA2B1	128	Nuclear	Structural	-	-	-	07p15	110	2
#	ABC7	ATP-binding cassette, sub-family B (MDR/TAP), member 7	ABC7, ABCB7, ASAT, Atm1p	108	Cytoplasmic	Transporter	-	-	-	Xq12-q13	125	2
#	ACLY	ATP citrate lyase	ACLY	162	Cytoplasmic	Lipid Metabolism	-	-	-	17q12-q21	75	2
#
#
#Gene ---> geneticOb.geneticObName , geneticOb.obkeywords
#Full Name -->  geneticOb.geneticObDescription
#Abbreviations..   --> geneticOb.geneticObSymbols, geneticOb.obkeywords
#order ---> geneticFact.AttributeName/Value
#Cellular localisation ----> geneticExpressionFact.cellularLocalisation
#Functional Classification ----> geneticFunctionFact.functionComment
#Magnitude of Change ---> geneticFact.AttributeName/Value
#FollicularLocalisation ----> geneticFact.Attribute/Value
#Chromosome -----> GeneticLocationFact.species ,.chromosome, cytopos
#WeightedScore -----> GeneticFact.attribute/Value
#Count ----> geneticFact.count

import csv
from sets import Set


infilename = "../data/SamsonGenes.csv";

def main():
    genGeneBootstrap()

def writeHeader(outfilename):
    outfile = open(outfilename,"w")
    outfile.write("""
/*
* script generated by gengeneticlocusbootstrap.py
*/
""")
    return outfile


def writeFooter(outfile):
    outfile.write("""
/*
* **** done **** 
*/
""")
    outfile.close()

    
def genGeneBootstrap():

    geneSQLDict={}
    samsonSQLDict={}
    expressionSQLDict={}
    functionSQLDict={}
    locationSQLDict={}
    geneinfoSQLDict={}
    
    
    reader = csv.reader(open(infilename, "rb"))
    cols = ("Gene","Full Name","Abbreviations and Alternative Names",
            "Order","Cellular localisation","Functional Classification",
            "Magnitude of Change","Cycle Stage",
            "Follicular Localisation","Human Chromosome",
            "Weighted Score","Count")
    coldict={}
    ucols = [item.upper() for item in cols]

    for row in reader:
        #print row
        #get column positions if necessary
        if len(coldict) == 0 :
            ucrow = [item.upper() for item in row]
            #print ucrow
            try :
                for ucitem in ucols :
                    coldict[ucitem]=ucrow.index(ucitem)
            except ValueError:
                None

        #construct SQL if we have the gene column
        #GENE
        #FULL NAME
        #ABBREVIATIONS
        #ORDER
        #CELLULAR LOCALISATION
        #FUNCTIONAL CLASSIFICATION
        #MAGNITUDE OF CHANGE
        #FOLLICULARLOCALISATION
        #CHROMOSOME
        #WEIGHTEDSCORE
        #COUNT
        if coldict.has_key('GENE'):
            if (not geneSQLDict.has_key(row[coldict['GENE']])) and \
               row[coldict['GENE']] != 'Gene' and \
               len(row[coldict['GENE']].split()) > 0:

                # geneticOb insert
                print "adding ",row[coldict['GENE']]
                geneSQLDict[row[coldict['GENE']]] = "insert into geneticOb(geneticobname,xreflsid,geneticobtype,geneticobdescription,geneticobsymbols,obkeywords) "
                geneSQLDict[row[coldict['GENE']]] = geneSQLDict[row[coldict['GENE']]] + \
                    "values('" + row[coldict['GENE']] + "','http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?db=gene&cmd=search&term="  + \
                    row[coldict['GENE']] + "','Gene','" + row[coldict['FULL NAME']] + " (from SAMSON database)','" + row[coldict['GENE']] + " " + \
                    row[coldict['ABBREVIATIONS AND ALTERNATIVE NAMES']] + "','" +  row[coldict['GENE']] + " " + row[coldict['ABBREVIATIONS AND ALTERNATIVE NAMES']] + " SAMSON');"


                if len(row[coldict["COUNT"]].strip()) == 0:
                    row[coldict["COUNT"]] = "null"

                #samsonGeneticFact insert
                samsonSQLDict[row[coldict['GENE']]] = "insert into samsonGeneticFact(geneticob,genesummaryorder,"
                samsonSQLDict[row[coldict['GENE']]] = samsonSQLDict[row[coldict['GENE']]] + \
                        "changemagnitude,follicularlocalisation,genesummaryweightedscore,genesummarycount) select obid," +\
                        row[coldict['ORDER']] + ",'" + row[coldict['MAGNITUDE OF CHANGE']] + "','" + \
                        row[coldict["FOLLICULAR LOCALISATION"]] + "'," + row[coldict["WEIGHTED SCORE"]] + "," + \
                        row[coldict["COUNT"]] + " from geneticob where geneticObName = '" + row[coldict['GENE']] +"';"

                samsonSQLDict[row[coldict['GENE']]] = samsonSQLDict[row[coldict['GENE']]].replace(",,",",null,")
                samsonSQLDict[row[coldict['GENE']]] = samsonSQLDict[row[coldict['GENE']]].replace(",#N/A,",",null,")

                #GeneticExpressionFact insert
                expressionSQLDict[row[coldict['GENE']]] = "insert into geneticExpressionFact(geneticob,cellularlocalisation,lifecyclestage) " + \
                        "select obid,'" + row[coldict['CELLULAR LOCALISATION']] + "','" + row[coldict['CYCLE STAGE']] + \
                        "' from geneticob where geneticObName = '" + row[coldict['GENE']] +"';"

                #GeneticFunctionFact insert
                if row[coldict['FUNCTIONAL CLASSIFICATION']].strip().upper() != "UNKNOWN":
                    functionSQLDict[row[coldict['GENE']]] = "insert into geneticFunctionFact(geneticob,functionComment) " + \
                        "select obid,'" + row[coldict['FUNCTIONAL CLASSIFICATION']] + \
                        "' from geneticob where geneticObName = '" + row[coldict['GENE']] +"';"

                #GeneticLocationFact insert
                cytopos=row[coldict['HUMAN CHROMOSOME']].strip()
                if cytopos != "-" and len(cytopos) > 0 :
                    xreflsid= "'http://genome.ucsc.edu/cgi-bin/hgTracks?org=Human&db=hg17&position=" + cytopos + "'"
                    cytopos="'" + cytopos + "'"
                    species="'Homo Sapiens'"
                    
                    locationSQLDict[row[coldict['GENE']]] = "insert into geneticLocationFact(geneticob,xreflsid,cytopos,speciesname) " + \
                        "select obid," + xreflsid + "," +cytopos + "," + species + \
                          " from geneticob where geneticObName = '" + row[coldict['GENE']] +"';"

                #generate SQL that when executed on the Oracle database, will generate
                #Postgres updates of the GeneticFunction and Location tables. Example Oracle SQL :
                """                    
select
   /*+ RULE */
   'insert into geneticfact(ob,factnamespace,attributename,attributevalue) ' || 
   'select obid, ''EntrezGene'',''Summary'',''<dd>Geneid=' ||
   to_char(geneid) || ' Symbol='||
   symbol || ' Synonyms=' ||
   synonyms || '<dd>Description='||
   description || ' <dd>GOdescription=' ||
   pubplsqlutils.getGoString(geneid) || ' <dd>Map=' ||
   g.chromosome||':'||g.map_location || ''' from geneticob where obname = ''CRP1'''
from
   pubstore.geneinfo g
where
   (symbol='CRP1' or 
    synonyms like 'CRP1|' or 
    synonyms like '%|CRP1|%' or
    synonyms like '%|CRP1') and taxid = 9606
    
                #example pgsql :

insert into geneticfact(ob,factnamespace,attributename,attributevalue) select obid, 'EntrezGene','Summary','<dd>Geneid=1053 Symbol=CEBPE Synonyms=C/EBP-epsilon|CRP1<dd>Description=CCAAT/enhancer binding protein (C/EBP), epsilon <dd>GOdescription=DNA binding ; defense response ; nucleus ; regulation of transcription, DNA-dependent ; transcription <dd>Map=14:14q11.2' from geneticob where obname = 'CRP1'
insert into geneticfact(ob,factnamespace,attributename,attributevalue) select obid, 'EntrezGene','Summary','<dd>Geneid=1396 Symbol=CRIP1 Synonyms=CRHP|CRIP|CRP1<dd>Description=cysteine-rich protein 1 (intestinal) <dd>GOdescription=antimicrobial humoral response (sensu Vertebrata) ; cell proliferation ; cytoplasm ; metal ion binding ; zinc ion binding <dd>Map=14:14q32.33' from geneticob where obname = 'CRP1'
insert into geneticfact(ob,factnamespace,attributename,attributevalue) select obid, 'EntrezGene','Summary','<dd>Geneid=1465 Symbol=CSRP1 Synonyms=CRP|CRP1|CSRP|CYRP|D1S181E|DKFZp686M148<dd>Description=cysteine and glycine-rich protein 1 <dd>GOdescription=metal ion binding ; nucleus ; zinc ion binding <dd>Map=1:1q32' from geneticob where obname = 'CRP1'
                if cytopos != "-" and len(cytopos) > 0 :                     """
                                        
                                
    outfile=writeHeader("../bin/bootstrapgenes.psql")
    # SQL to set up SAMSON project list of genes
    outfile.write("insert into GeneticObList(listName,maxmembership,listComment) values('SAMSON Database of Hair Follicle Genes',25000,'SAMSON Gene Project List. This List contains GeneticOb objects in the SAMSON database project');\n");

    # SQL to insert genes
    for value in geneSQLDict.values():
        outfile.write(value)
        outfile.write('\n')

    # SQL to populate projects list
    outfile.write("insert into geneticOblistMembershipLink(geneticObList,geneticOb) \
         select l.obid,g.obid from \
         geneticOb g, geneticObList l \
         where l.listName = 'SAMSON Database of Hair Follicle Genes' and \
         g.geneticObDescription like '%from SAMSON database%'; \n")
                     
    writeFooter(outfile)

    outfile=writeHeader("../bin/bootstrapgenesamson.psql")
    for value in samsonSQLDict.values():
        outfile.write(value)
        outfile.write('\n')
    writeFooter(outfile)

    outfile=writeHeader("../bin/bootstrapgeneexpression.psql")
    for value in expressionSQLDict.values():
        outfile.write(value)
        outfile.write('\n')
    writeFooter(outfile)

    outfile=writeHeader("../bin/bootstrapgenefunction.psql")
    for value in functionSQLDict.values():
        outfile.write(value)
        outfile.write('\n')
    writeFooter(outfile)

    outfile=writeHeader("../bin/bootstrapgenelocation.psql")
    for value in locationSQLDict.values():
        outfile.write(value)
        outfile.write('\n')
    writeFooter(outfile)        
    

    print coldict



if __name__ == "__main__":
   main()
Gruesse,
Juergen
juergenkemeter
User
Beiträge: 11
Registriert: Sonntag 20. November 2005, 22:33

Hi,
evtl. war meine Problemschilderung nicht ausreichend.
Unter Export der Excel - Hyperlinks bzw Zellkommentare meine ich eine Moeglichkeit, diese in eine .CSV - Datei auszulesen und zu speichern.
Bei den Hyperlinks sollte der komplette Link ausgelesen werden.

Ciao
Juergen
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

juergenkemeter hat geschrieben: Unter Export der Excel - Hyperlinks bzw Zellkommentare meine ich eine Moeglichkeit, diese in eine .CSV - Datei auszulesen und zu speichern.
Bei den Hyperlinks sollte der komplette Link ausgelesen werden.
Hi Juergen!

Bei Zellkommentaren weiß ich ja noch, was damit gemeint sein kann, aber bei Hyperlinks???

Wenn du Excel automatisieren oder Daten auslesen bzw. schreiben möchtest, dann musst du immer vorher herausfinden, wie das im Excel mit VBA (Visual Basic for Applications) funktioniert.

Sobald du das herausgefunden hast, brauchst du diese Befehle nur noch ins Python zu übertragen. Hier ein paar Klammern dazu da ein wenig an der Syntax ändern und immer nur einen Schritt nach dem anderen probieren. Wenn Excel nicht mehr richtig oder komisch reagiert, dann kann das beim Testen daran liegen, dass Excel noch im Hintergrund (ohne sichtbarem Fenster) offen ist. Das passiert gerne, wenn beim Testen das Skript abbricht. Dann musst du es beinhart über den TaskManager rausschmeißen, bevor du wieder probierst.

Um herauszufinden, wie man zu den Kommentaren kommt, ist es recht nützlich, im Excel ein Makro aufzuzeichnen, während man ein Kommentar erstellt. Dann im Excel mit der Codevervollständigung herausfinden, wie man auf den soeben erstellten Kommentar zugreifen kann, dürfte dann nicht mehr schwer sein. (Zu finden unter: Extras->Makro->Makros->Bearbeiten)

So habe ich eben herausgefunden, wie man auf die Kommentare zugreift.

Damit du nicht ganz in der Luft da stehst, stelle ich hier das Ergebnis meines Tests ab.

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-

import win32com.client
import win32ui

# Zum Excel verbinden
app = win32com.client.Dispatch("Excel.Application")
app.visible = True

# Neue Arbeitsmappe
workbook = app.Workbooks.Add()

# Zum Arbeitsblatt verbinden
sheet = workbook.Sheets[0]

# Kommentare hinzufügen
sheet.Range("A1").AddComment()
sheet.Range("A1").Comment.Text("Hallo")

sheet.Range("B2").AddComment()
sheet.Range("B2").Comment.Text("Welt")

# Kommentare auslesen und anzeigen
win32ui.MessageBox(
    "Kommentar in A1: %s" % sheet.Range("A1").Comment.Text()
)
win32ui.MessageBox(
    "Kommentar in B2: %s" % sheet.Range("B2").Comment.Text()
)

# Variablen löschen und damit die Verbindung zu Excel lösen
del sheet
del app
Das Ganze wurde mit Excel 2000 getestet.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
juergenkemeter
User
Beiträge: 11
Registriert: Sonntag 20. November 2005, 22:33

Hi Gerold.

Danke fuer deine ausfuehrliche Antwort, die mir in Bezug auf generelles Skript erstellen und Kommentare weitergeholfen hat!
Ich hab erst vor ca. 3 Wochen angefangen, mich in Python einzuarbeiten.

Deinen Pythoncode hab ich ausprobiert. Vielleicht liegt es an meiner Python Version (2.3.5), da folgende Fehlermeldung kommt:

Code: Alles auswählen

Traceback (most recent call last):
  File "//ifile/kemeterj$/Work_Python/Development/exportHyperlinksAndCommentsToCSV/ExportComments.py", line 4, in -toplevel-
    import win32com.client
ImportError: No module named win32com.client
[\code]


Zu den Hyperlinks:
Wenn man in einer Excelzelle einen Hyperling stehen hat, z.B. mit anzuzeigendem Text 'testlink', und der Addresse 'C:\Data\test\Hair.Gene.DB\Gene.File.Lists\0002.File.Lists.xls'.
Bei Klick auf die Zelle in Excel oeffnet sich dann praktisch die entsprechende Datei.


Dann muesste ich die Adresse dieses Hyperlinks irgendwie auslesen und in eine csv - datei speichern, in dem Fall 'C:\Data\test\Hair.Gene.DB\Gene.File.Lists\0002.File.Lists.xls'. Idealerweise auch noch den angezeigten Text in der Zelle, in dem Fall 'testlink'.

Wenns nicht klarer ist, kann ich auch eine Beispieldatei schicken.
Wenn ich draufgekommen bin wies geht sag ich Bescheid.

Gruesse
Juergen
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

juergenkemeter hat geschrieben:ImportError: No module named win32com.client
Dann hast du wahrscheinlich nicht Python Win32 Extensions installiert, was?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
tabellar
User
Beiträge: 186
Registriert: Mittwoch 4. September 2002, 15:28

Hi Jürgen,

musst Du unbedingt über die .csv Datei gehen?
Wenn nicht, würde ich vom Pythonprogramm die
Daten von Excel direkt in Postgres einlesen lassen ... :)


Tabellar
juergenkemeter
User
Beiträge: 11
Registriert: Sonntag 20. November 2005, 22:33

Hi,
@gerold:
dein Code funktioniert, nachdem ich das win32com Modul installiert habe.

@tabellar, and all others:
csv ist nicht unbedingt noetig.
Fuers direkte Auslesen - gibts da Beispiele im Internet o.ae.?
Vielleicht gibt es eine Methode in win32com fuers Auslesen und speichern von Kommentaren und Links in Excel - Zellen.
Welches Modul muss man dann fuer die Datenbank - Connection verwenden?

Wichtig dabei ist, dass man fuer eine einzelne Zelle max. drei verschiedene Informationen hat: Value, Comment, Link.
Fuers Speichern in verschiedene CSV Dateien (eine fuer Value, eine fuer Links und eine fuer Comments) sollte man, um spaeter den Bezug zwischen den richtigen Zellen wieder herstellen zu koennen (z.B. fuer SQL - INSERTS in eine Datenbank - Tabelle), einen gemeinsamen Schluessel verwenden.

Vielleicht hat ja jemand hier schon mal Erfahrung in dem Bereich gesammelt.

Juergen
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

juergenkemeter hat geschrieben:Fuers direkte Auslesen - gibts da Beispiele im Internet o.ae.?
Hi Juergen!

Such in diesem Forum mal nach "Excel". Da solltest du einige Beispiele finden, wie man nicht nur ein Kommentar, sondern auch den Wert einer Zelle auslesen kann. Was du als Link bezeichnest, dürfte evt. auch nur der Wert der Zelle sein, der evt. nur anders dargestellt wird.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

juergenkemeter hat geschrieben:Welches Modul muss man dann fuer die Datenbank - Connection verwenden?
Hi Juergen!

http://www.python-forum.de/viewtopic.ph ... postgresql
http://www.python-forum.de/viewtopic.ph ... postgresql

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
juergenkemeter
User
Beiträge: 11
Registriert: Sonntag 20. November 2005, 22:33

Hi,
gibt es im Internet eine Seite wo ich mich ueber win32com - interface - methoden informieren kann?

hier eine genaue Beschreibung meiner Situation:
- ich habe einen Haupt Ordner, mit einer 'Startdatenbank.xls'-Hauptdatei. Dieses Workbook enthaelt Links zu weiterfuerhenden Workbooks (.xls), die sich in Unterordnern des Hauptordners befinden.
- Jeder (Unter-)ordner enthaelt ein oder mehrere Workbooks.
- Jedes Workbook enthaelt ein oder mehrere Spreadsheets
- Die Workbooks beinhalten einige Zellen, die Links enthalten, die zu anderen, verlinkten Workbooks fuehren.
- Einige Zellen enthalten Kommentare, die auch exportiert werden sollen.

Mein Ziel ist es, alle Daten der Workbooks, d.h. Zell Werte, Hyperlink Adressen und Kommentare in Zellen, in eine entsprechende PostgreSQL datenbank - Tabelle zu exportieren.
Prinzipiell sind dann pro Zelle bis zu drei verschiedene Datentypen moeglich (Wert, Hyperlink-Adresse, Kommentar).

Hier mein bisheriger Ansatz.
Eine For-Schleife, die durch alle (Unter-)ordner geht, in jeden Ordner schaut, dann in jedes Spreadsheet eines Workbooks schaut.
Fuer jedes Spreadsheet, alle Zellwerte, Zell-Hyperlink-Adressen (falls vorhanden), und Zellkommentare (falls vorhanden) ausliest.
@Gerold- dein win32 - code duerfte dafuer nuetzlich sein.

Dann soll eine PostgreSQL Dattenbank Connection geoeffnet werden, und alle Zellwerte, Hyperlinks und Kommentar - Strings n eine entsprechend benannte tabelle gespeichert werden.
Sollen dabei die tabellen schon vorher Kreiert werden oder kann man das mit Python machen?

So, soviel mal zu meinem Projekt - hoert sich fuer eine Python Beginner nach viel Spass an - jede Hilfe wird akzeptiert.

Wie man Zellkommentare und Hyperlink-Adressen mit VBA auslesen kan, hab ich schon rausgefunden, aber wie man das alles im Python Script kombiniert (inklisuve Datenbank-Connection und v.a. der for-Schleife fuer die Ordner) bisher noch nicht:

Code: Alles auswählen

'----------------------------------------------------------------------------
'Extract the text from a cell comment
'----------------------------------------------------------------------------

Function GetCommentText(rCommentCell As Range)
Dim strGotIt As String
    On Error Resume Next
    	strGotIt = WorksheetFunction.Clean _
              (rCommentCell.Comment.Text)
    		GetCommentText = strGotIt
    On Error GoTo 0
End Function

'----------------------------------------------------------------------------
'Extract the underlying address from a cell containing a Hyperlink
'----------------------------------------------------------------------------
Function GetAddress(HyperlinkCell As Range)
    GetAddress = Replace _
    (HyperlinkCell.Hyperlinks(1).Address, "mailto:", "")
End Function

Cheers
Juergen
Antworten