diff --git a/include/caosdb/transaction.h b/include/caosdb/transaction.h
index 002a9d3eaca381732b0c0104cb4f076d6eab2fe6..cc889413a3d377c8798dac6cdb471610bb2a6b44 100644
--- a/include/caosdb/transaction.h
+++ b/include/caosdb/transaction.h
@@ -187,12 +187,19 @@ using google::protobuf::Arena;
 
 class ResultTableImpl;
 
+class ResultTableColumnImpl;
+
 class ResultTableColumn {
 public:
   /**
    * Get the name of the column.
    */
   [[nodiscard]] auto GetName() const noexcept -> const std::string &;
+
+  friend class ResultTable;
+  explicit ResultTableColumn(std::unique_ptr<ResultTableColumnImpl> delegate);
+private:
+  std::unique_ptr<ResultTableColumnImpl> delegate;
 };
 
 class ResultTable {
@@ -216,6 +223,7 @@ private:
   class HeaderIterator : std::iterator<std::output_iterator_tag, ResultTableColumn> {
   public:
     explicit HeaderIterator(const ResultTable *result_table, int index = 0);
+    HeaderIterator(const HeaderIterator &other);
     auto operator*() const -> const ResultTableColumn &;
     auto operator++() -> HeaderIterator &;
     auto operator++(int) -> HeaderIterator;
diff --git a/proto b/proto
index 0b301401cf28d7a3edeb2c55e418f072b83cf5a7..fd60795f62335368255797db43eb0429ec1705fc 160000
--- a/proto
+++ b/proto
@@ -1 +1 @@
-Subproject commit 0b301401cf28d7a3edeb2c55e418f072b83cf5a7
+Subproject commit fd60795f62335368255797db43eb0429ec1705fc
diff --git a/src/caosdb/transaction.cpp b/src/caosdb/transaction.cpp
index 59c94387558f29813c28ad17c487af4513d22d56..ca8ea2f984f443d0f13dfa50840d85fb03c567bd 100644
--- a/src/caosdb/transaction.cpp
+++ b/src/caosdb/transaction.cpp
@@ -53,6 +53,7 @@ using RetrieveResponseCase = caosdb::entity::v1::RetrieveResponse::RetrieveRespo
 using RetrieveResponse = caosdb::entity::v1::RetrieveResponse;
 using ProtoEntity = caosdb::entity::v1::Entity;
 using ProtoSelectQueryResult = caosdb::entity::v1::SelectQueryResult;
+using ProtoSelectQueryColumn = caosdb::entity::v1::SelectQueryColumn;
 using caosdb::entity::v1::EntityRequest;
 using caosdb::utility::ScalarProtoMessageWrapper;
 
@@ -60,13 +61,29 @@ using google::protobuf::Arena;
 using NextStatus = grpc::CompletionQueue::NextStatus;
 using RegistrationStatus = caosdb::entity::v1::RegistrationStatus;
 
+class ResultTableColumnImpl : public ScalarProtoMessageWrapper<ProtoSelectQueryColumn> {
+  explicit ResultTableColumnImpl(ProtoSelectQueryColumn *column);
+  friend class ResultTableColumn;
+  friend class ResultTableImpl;
+};
+
+ResultTableColumnImpl::ResultTableColumnImpl(ProtoSelectQueryColumn *column) : ScalarProtoMessageWrapper<ProtoSelectQueryColumn>(column) {};
+
+ResultTableColumn::ResultTableColumn(std::unique_ptr<ResultTableColumnImpl> delegate) : delegate(std::move(delegate)) {}
+
+auto ResultTableColumn::GetName() const noexcept -> const std::string & {
+  return this->delegate->wrapped->name();
+}
 
 class ResultTableImpl : public ScalarProtoMessageWrapper<ProtoSelectQueryResult> {
   static auto create(ProtoSelectQueryResult *select_result) -> std::unique_ptr<ResultTable>;
   ResultTableImpl();
   explicit ResultTableImpl(ProtoSelectQueryResult *result_table);
+  std::vector<ResultTableColumn> columns;
 
   friend class ResultTable;
+  friend class ResultTable::HeaderIterator;
+  friend class ResultTableColumn;
   friend auto ProcessSelectResponse(ProtoSelectQueryResult *select_result) -> std::unique_ptr<ResultTable>;
 };
 
@@ -74,7 +91,11 @@ auto ResultTableImpl::create(ProtoSelectQueryResult *select_result) -> std::uniq
   return std::unique_ptr<ResultTable>(new ResultTable(std::unique_ptr<ResultTableImpl>(new ResultTableImpl(select_result))));
 }
 
-ResultTableImpl::ResultTableImpl(ProtoSelectQueryResult *result_table) : ScalarProtoMessageWrapper<ProtoSelectQueryResult>(result_table) {}
+ResultTableImpl::ResultTableImpl(ProtoSelectQueryResult *result_table) : ScalarProtoMessageWrapper<ProtoSelectQueryResult>(result_table) {
+  for (auto &column : *this->wrapped->mutable_header()->mutable_columns()) {
+    this->columns.emplace_back(std::unique_ptr<ResultTableColumnImpl>(new ResultTableColumnImpl(&column)));
+  }
+}
 
 ResultTable::ResultTable(std::unique_ptr<ResultTableImpl> delegate) : delegate(std::move(delegate)) {}
 
@@ -83,16 +104,45 @@ auto ResultTable::size() const noexcept -> int {
   return 0;
 }
 
-ResultTable::HeaderIterator::HeaderIterator(const ResultTable *result_table_param, int index) : current_index(index), result_table(result_table_param) {}
-
 auto ResultTable::GetHeader() const noexcept -> const HeaderIterator {
   return HeaderIterator(this, 0);
 }
 
+ResultTable::HeaderIterator::HeaderIterator(const ResultTable *result_table_param, int index) : current_index(index), result_table(result_table_param) {}
+
+ResultTable::HeaderIterator::HeaderIterator(const HeaderIterator &other) : current_index(other.current_index), result_table(other.result_table) {}
+
 auto ResultTable::HeaderIterator::size() const noexcept -> int {
   return this->result_table->delegate->wrapped->header().columns_size();
 }
 
+auto ResultTable::HeaderIterator::operator*() const -> const ResultTableColumn & {
+  return this->result_table->delegate->columns.at(this->current_index);
+}
+
+auto ResultTable::HeaderIterator::operator++() -> HeaderIterator & {
+  current_index++;
+  return *this;
+}
+
+auto ResultTable::HeaderIterator::operator++(int) -> HeaderIterator {
+  HeaderIterator tmp(*this);
+  operator++();
+  return tmp;
+}
+
+auto ResultTable::HeaderIterator::operator!=(const HeaderIterator &rhs) const -> bool {
+  return this->current_index != rhs.current_index;
+}
+
+auto ResultTable::HeaderIterator::begin() const -> HeaderIterator {
+  return HeaderIterator(this->result_table);
+}
+
+auto ResultTable::HeaderIterator::end() const -> HeaderIterator {
+  return HeaderIterator(this->result_table, size());
+}
+
 ResultSet::iterator::iterator(const ResultSet *result_set_param, int index)
   : current_index(index), result_set(result_set_param) {}