v.db.join.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. #!/usr/bin/env python
  2. ############################################################################
  3. #
  4. # MODULE: v.db.join
  5. # AUTHOR(S): Markus Neteler
  6. # Converted to Python by Glynn Clements
  7. # PURPOSE: Join a table to a map table
  8. # COPYRIGHT: (C) 2007-2009 by Markus Neteler and the GRASS Development Team
  9. #
  10. # This program is free software under the GNU General Public
  11. # License (>=v2). Read the file COPYING that comes with GRASS
  12. # for details.
  13. #
  14. #############################################################################
  15. #%module
  16. #% description: Joins a database table to a vector map table.
  17. #% keyword: vector
  18. #% keyword: attribute table
  19. #% keyword: database
  20. #%end
  21. #%option G_OPT_V_MAP
  22. #% description: Vector map to which to join other table
  23. #% guidependency: layer,column
  24. #%end
  25. #%option G_OPT_V_FIELD
  26. #% description: Layer where to join
  27. #% guidependency: column
  28. #%end
  29. #%option G_OPT_DB_COLUMN
  30. #% description: Identifier column (e.g.: cat) in the vector table to be used for join
  31. #% required : yes
  32. #%end
  33. #%option G_OPT_DB_TABLE
  34. #% key: other_table
  35. #% description: Other table name
  36. #% required: yes
  37. #% guidependency: ocolumn,scolumns
  38. #%end
  39. #%option G_OPT_DB_COLUMN
  40. #% key: other_column
  41. #% description: Identifier column (e.g.: id) in the other table used for join
  42. #% required: yes
  43. #%end
  44. #%option G_OPT_DB_COLUMN
  45. #% key: subset_columns
  46. #% multiple: yes
  47. #% required: no
  48. #% description: Subset of columns from the other table
  49. #%end
  50. import sys
  51. import string
  52. import grass.script as grass
  53. from grass.exceptions import CalledModuleError
  54. def main():
  55. map = options['map']
  56. layer = options['layer']
  57. column = options['column']
  58. otable = options['other_table']
  59. ocolumn = options['other_column']
  60. if options['subset_columns']:
  61. scolumns = options['subset_columns'].split(',')
  62. else:
  63. scolumns = None
  64. f = grass.vector_layer_db(map, layer)
  65. maptable = f['table']
  66. database = f['database']
  67. driver = f['driver']
  68. if driver == 'dbf':
  69. grass.fatal(_("JOIN is not supported for tables stored in DBF format"))
  70. if not maptable:
  71. grass.fatal(_("There is no table connected to this map. Unable to join any column."))
  72. # check if column is in map table
  73. if not grass.vector_columns(map, layer).has_key(column):
  74. grass.fatal(_("Column <%s> not found in table <%s>") % (column, maptable))
  75. # describe other table
  76. all_cols_ot = grass.db_describe(otable, driver = driver, database = database)['cols']
  77. # check if ocolumn is on other table
  78. if ocolumn not in [ocol[0] for ocol in all_cols_ot]:
  79. grass.fatal(_("Column <%s> not found in table <%s>") % (ocolumn, otable))
  80. # determine columns subset from other table
  81. if not scolumns:
  82. # select all columns from other table
  83. cols_to_add = all_cols_ot
  84. else:
  85. cols_to_add = []
  86. # check if scolumns exists in the other table
  87. for scol in scolumns:
  88. found = False
  89. for col_ot in all_cols_ot:
  90. if scol == col_ot[0]:
  91. found = True
  92. cols_to_add.append(col_ot)
  93. break
  94. if not found:
  95. grass.warning(_("Column <%s> not found in table <%s>.") % (scol, otable))
  96. all_cols_tt = grass.vector_columns(map, int(layer)).keys()
  97. select = "SELECT $colname FROM $otable WHERE $otable.$ocolumn=$table.$column"
  98. template = string.Template("UPDATE $table SET $colname=(%s);" % select)
  99. for col in cols_to_add:
  100. # skip the vector column which is used for join
  101. colname = col[0]
  102. if colname == column:
  103. continue
  104. # Sqlite 3 does not support the precision number any more
  105. if len(col) > 2 and driver != "sqlite":
  106. coltype = "%s(%s)" % (col[1], col[2])
  107. else:
  108. coltype = "%s" % col[1]
  109. colspec = "%s %s" % (colname, coltype)
  110. # add only the new column to the table
  111. if colname not in all_cols_tt:
  112. try:
  113. grass.run_command('v.db.addcolumn', map=map,
  114. columns=colspec, layer=layer)
  115. except CalledModuleError:
  116. grass.fatal(_("Error creating column <%s>") % colname)
  117. stmt = template.substitute(table = maptable, column = column,
  118. otable = otable, ocolumn = ocolumn,
  119. colname = colname)
  120. grass.debug(stmt, 1)
  121. grass.verbose(_("Updating column <%s> of vector map <%s>...") % (colname, map))
  122. try:
  123. grass.write_command('db.execute', stdin=stmt, input='-',
  124. database=database, driver=driver)
  125. except CalledModuleError:
  126. grass.fatal(_("Error filling column <%s>") % colname)
  127. # write cmd history
  128. grass.vector_history(map)
  129. return 0
  130. if __name__ == "__main__":
  131. options, flags = grass.parser()
  132. sys.exit(main())