diff --git a/fda-database-service/rest-service/src/main/resources/init/querystore.sql b/fda-database-service/rest-service/src/main/resources/init/querystore.sql
index c98ce27ecf601053d39820a82810958644e0254f..26fc6e54370ec268fa2cfa683f37c825d7cfa81b 100644
--- a/fda-database-service/rest-service/src/main/resources/init/querystore.sql
+++ b/fda-database-service/rest-service/src/main/resources/init/querystore.sql
@@ -1,5 +1,5 @@
-CREATE SEQUENCE `qs_queries_seq`;
-CREATE TABLE `qs_queries`( `id` bigint not null primary key default nextval(`qs_queries_seq`), `created` datetime not null default now(), `executed` datetime not null default now(), `created_by` varchar(255) not null, `query` text not null, `query_normalized` text not null, `is_persisted` boolean not null, `query_hash` varchar(255) not null, `result_hash` varchar(255), `result_number` bigint);
-CREATE PROCEDURE hash_table(IN name VARCHAR(255), OUT hash VARCHAR(255))BEGIN DECLARE _sql TEXT; SELECT CONCAT('SELECT SHA2(GROUP_CONCAT(CONCAT_WS(\'\',', GROUP_CONCAT(CONCAT('`', column_name, '`') ORDER BY column_name), ') SEPARATOR \',\'), 256) AS hash FROM `', name, '` INTO @hash;') FROM `information_schema`.`columns` WHERE `table_schema` = DATABASE() AND `table_name` = name INTO _sql; PREPARE stmt FROM _sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET hash = @hash;END
-CREATE PROCEDURE store_query(IN query TEXT, IN executed DATETIME, OUT queryId BIGINT)BEGIN DECLARE _queryhash varchar(255) DEFAULT SHA2(query, 256); DECLARE _username varchar(255) DEFAULT REGEXP_REPLACE(current_user(), '@.*', ''); DECLARE _query TEXT DEFAULT CONCAT('CREATE OR REPLACE TABLE _tmp AS (', query, ')'); PREPARE stmt FROM _query; EXECUTE stmt; DEALLOCATE PREPARE stmt; CALL hash_table('_tmp', @hash); SELECT COUNT(*) FROM _tmp INTO @count; IF @hash IS NULL THEN INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); ELSE INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); END IF; END
-CREATE DEFINER = 'root' PROCEDURE _store_query(IN _username VARCHAR(255), IN query TEXT, IN executed DATETIME, OUT queryId BIGINT)BEGIN DECLARE _queryhash varchar(255) DEFAULT SHA2(query, 256); DECLARE _query TEXT DEFAULT CONCAT('CREATE OR REPLACE TABLE _tmp AS (', query, ')'); PREPARE stmt FROM _query; EXECUTE stmt; DEALLOCATE PREPARE stmt; CALL hash_table('_tmp', @hash); SELECT COUNT(*) FROM _tmp INTO @count; IF @hash IS NULL THEN INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); ELSE INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); END IF; END
\ No newline at end of file
+CREATE SEQUENCE `qs_queries_seq`; 
+CREATE TABLE `qs_queries` ( `id` bigint not null primary key default nextval(`qs_queries_seq`), `created` datetime not null default now(), `executed` datetime not null default now(), `created_by` varchar(255) not null, `query` text not null, `query_normalized` text not null, `is_persisted` boolean not null, `query_hash` varchar(255) not null, `result_hash` varchar(255), `result_number` bigint );
+CREATE PROCEDURE hash_table(IN name VARCHAR(255), OUT hash VARCHAR(255), OUT count BIGINT) BEGIN DECLARE _sql TEXT; SELECT CONCAT('SELECT SHA2(GROUP_CONCAT(CONCAT_WS(\'\',', GROUP_CONCAT(CONCAT('`', column_name, '`') ORDER BY column_name), ') SEPARATOR \',\'), 256) AS hash, COUNT(*) AS count FROM `', name, '` INTO @hash, @count;') FROM `information_schema`.`columns` WHERE `table_schema` = DATABASE() AND `table_name` = name INTO _sql; PREPARE stmt FROM _sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET hash = @hash; SET count = @count; END;
+CREATE PROCEDURE store_query(IN query TEXT, IN executed DATETIME, OUT queryId BIGINT) BEGIN DECLARE _queryhash varchar(255) DEFAULT SHA2(query, 256); DECLARE _username varchar(255) DEFAULT REGEXP_REPLACE(current_user(), '@.*', ''); DECLARE _query TEXT DEFAULT CONCAT('CREATE OR REPLACE TABLE _tmp AS (', query, ')'); PREPARE stmt FROM _query; EXECUTE stmt; DEALLOCATE PREPARE stmt; CALL hash_table('_tmp', @hash, @count); IF @hash IS NULL THEN INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); ELSE INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); END IF; END;
+CREATE DEFINER = 'root' PROCEDURE _store_query(IN _username VARCHAR(255), IN query TEXT, IN executed DATETIME, OUT queryId BIGINT) BEGIN DECLARE _queryhash varchar(255) DEFAULT SHA2(query, 256); DECLARE _query TEXT DEFAULT CONCAT('CREATE OR REPLACE TABLE _tmp AS (', query, ')'); PREPARE stmt FROM _query; EXECUTE stmt; DEALLOCATE PREPARE stmt; CALL hash_table('_tmp', @hash, @count); IF @hash IS NULL THEN INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` IS NULL); ELSE INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`, `result_number`, `executed`) SELECT _username, query, query, false, _queryhash, @hash, @count, executed WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash); END IF; END;
\ No newline at end of file
diff --git a/fda-database-service/rest-service/src/main/resources/init/querystore_manual.sql b/fda-database-service/rest-service/src/main/resources/init/querystore_manual.sql
index 2762d130a0044c439b41c0215b0d87924bc8f072..5580d0fd260b6ba4fddd24b411a6e74467d151d2 100644
--- a/fda-database-service/rest-service/src/main/resources/init/querystore_manual.sql
+++ b/fda-database-service/rest-service/src/main/resources/init/querystore_manual.sql
@@ -1,6 +1,5 @@
 CREATE SEQUENCE `qs_queries_seq`;
-CREATE TABLE `qs_queries`
-(
+CREATE TABLE `qs_queries` (
     `id`               bigint       not null primary key default nextval(`qs_queries_seq`),
     `created`          datetime     not null             default now(),
     `executed`         datetime     not null             default now(),
@@ -12,13 +11,14 @@ CREATE TABLE `qs_queries`
     `result_hash`      varchar(255),
     `result_number`    bigint
 );
+
 DELIMITER $$
-CREATE PROCEDURE hash_table(IN name VARCHAR(255), OUT hash VARCHAR(255))
+CREATE PROCEDURE hash_table(IN name VARCHAR(255), OUT hash VARCHAR(255), OUT count BIGINT)
 BEGIN
     DECLARE _sql TEXT;
     SELECT CONCAT('SELECT SHA2(GROUP_CONCAT(CONCAT_WS(\'\',',
                   GROUP_CONCAT(CONCAT('`', column_name, '`') ORDER BY column_name),
-                  ') SEPARATOR \',\'), 256) AS hash FROM `', name, '` INTO @hash;')
+                  ') SEPARATOR \',\'), 256) AS hash, COUNT(*) AS count FROM `', name, '` INTO @hash, @count;')
     FROM `information_schema`.`columns`
     WHERE `table_schema` = DATABASE()
       AND `table_name` = name
@@ -27,15 +27,16 @@ BEGIN
     EXECUTE stmt;
     DEALLOCATE PREPARE stmt;
     SET hash = @hash;
-END $$
+    SET count = @count;
+END; $$
+
 DELIMITER $$
 CREATE PROCEDURE store_query(IN query TEXT, IN executed DATETIME, OUT queryId BIGINT)
 BEGIN
     DECLARE _queryhash varchar(255) DEFAULT SHA2(query, 256);
     DECLARE _username varchar(255) DEFAULT REGEXP_REPLACE(current_user(), '@.*', '');
     DECLARE _query TEXT DEFAULT CONCAT('CREATE OR REPLACE TABLE _tmp AS (', query, ')');
-    PREPARE stmt FROM _query; EXECUTE stmt; DEALLOCATE PREPARE stmt; CALL hash_table('_tmp', @hash);
-    SELECT COUNT(*) FROM _tmp INTO @count;
+    PREPARE stmt FROM _query; EXECUTE stmt; DEALLOCATE PREPARE stmt; CALL hash_table('_tmp', @hash, @count);
     IF @hash IS NULL THEN
         INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`,
                                   `result_number`, `executed`)
@@ -49,15 +50,15 @@ BEGIN
         WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash);
         SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash);
     END IF;
-END $$
+END; $$
+
 DELIMITER $$
 CREATE
     DEFINER = 'root' PROCEDURE _store_query(IN _username VARCHAR(255), IN query TEXT, IN executed DATETIME, OUT queryId BIGINT)
 BEGIN
     DECLARE _queryhash varchar(255) DEFAULT SHA2(query, 256);
     DECLARE _query TEXT DEFAULT CONCAT('CREATE OR REPLACE TABLE _tmp AS (', query, ')');
-    PREPARE stmt FROM _query; EXECUTE stmt; DEALLOCATE PREPARE stmt; CALL hash_table('_tmp', @hash);
-    SELECT COUNT(*) FROM _tmp INTO @count;
+    PREPARE stmt FROM _query; EXECUTE stmt; DEALLOCATE PREPARE stmt; CALL hash_table('_tmp', @hash, @count);
     IF @hash IS NULL THEN
         INSERT INTO `qs_queries` (`created_by`, `query`, `query_normalized`, `is_persisted`, `query_hash`, `result_hash`,
                                   `result_number`, `executed`)
@@ -71,5 +72,6 @@ BEGIN
         WHERE NOT EXISTS (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash);
         SET queryId = (SELECT `id` FROM `qs_queries` WHERE `query_hash` = _queryhash AND `result_hash` = @hash);
     END IF;
-END $$
+END; $$
+
 DELIMITER ;
\ No newline at end of file
diff --git a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/View.java b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/View.java
index f75494670fbd8f6c1e3b9dced505028d1b9c2507..09e85f03b7267363bfdda8411642351703cdc61a 100644
--- a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/View.java
+++ b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/View.java
@@ -1,5 +1,6 @@
 package at.tuwien.entities.database;
 
+import at.tuwien.entities.database.table.columns.TableColumn;
 import at.tuwien.entities.user.User;
 import lombok.*;
 import net.sf.jsqlparser.statement.select.FromItem;
@@ -11,6 +12,7 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener;
 
 import javax.persistence.*;
 import java.time.Instant;
+import java.util.List;
 
 @Data
 @Entity
@@ -82,6 +84,21 @@ public class View {
         return this.getInternalName().equals(name);
     }
 
+    @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
+    @JoinTable(name = "mdb_view_columns",
+            joinColumns = {
+                    @JoinColumn(name = "vid", referencedColumnName = "id", insertable = false, updatable = false),
+                    @JoinColumn(name = "vcid", referencedColumnName = "vcid", insertable = false, updatable = false),
+                    @JoinColumn(name = "vdbid", referencedColumnName = "vdbid", insertable = false, updatable = false)
+            },
+            inverseJoinColumns = {
+                    @JoinColumn(name = "cid", referencedColumnName = "id", insertable = false, updatable = false),
+                    @JoinColumn(name = "ctid", referencedColumnName = "tid", insertable = false, updatable = false),
+                    @JoinColumn(name = "cdbid", referencedColumnName = "cdbid", insertable = false, updatable = false)
+            })
+    @OrderColumn(name = "position")
+    private List<TableColumn> columns;
+
     @Column(nullable = false, updatable = false)
     @CreatedDate
     private Instant created;
diff --git a/fda-metadata-db/setup-schema.sql b/fda-metadata-db/setup-schema.sql
index 60b5f3cf502cdadf42d6f7a6e52177e2fb72c37d..8e45d7012c076f0e130117564ae5386f17efa88e 100644
--- a/fda-metadata-db/setup-schema.sql
+++ b/fda-metadata-db/setup-schema.sql
@@ -341,7 +341,22 @@ CREATE TABLE IF NOT EXISTS mdb_view
     created_by    bigint       NOT NULL,
     FOREIGN KEY (created_by) REFERENCES mdb_users (UserID),
     FOREIGN KEY (vdbid) REFERENCES mdb_databases (id),
-    PRIMARY KEY (id, vdbid)
+    PRIMARY KEY (id, vcid, vdbid)
+) WITH SYSTEM VERSIONING;
+
+CREATE TABLE mdb_view_columns
+(
+    id               BIGINT  NOT NULL AUTO_INCREMENT,
+    cid              BIGINT  NOT NULL,
+    ctid             BIGINT  NOT NULL,
+    cdbid            BIGINT  NOT NULL,
+    vid              BIGINT  NOT NULL,
+    vcid             BIGINT  NOT NULL,
+    vdbid            BIGINT  NOT NULL,
+    position         INTEGER NULL,
+    PRIMARY KEY (id),
+    FOREIGN KEY (vid, vcid, vdbid) REFERENCES mdb_view (id, vcid, vdbid),
+    FOREIGN KEY (cid, cdbid, ctid) REFERENCES mdb_columns (ID, cDBID, tID)
 ) WITH SYSTEM VERSIONING;
 
 CREATE TABLE IF NOT EXISTS mdb_identifiers
diff --git a/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/ExportEndpoint.java b/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/ExportEndpoint.java
index 263c3ff8629a4d1d1bd191ee57e49632f9baa427..33a9c761a6ebd7d6ffd065362c5db011faf9483f 100644
--- a/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/ExportEndpoint.java
+++ b/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/ExportEndpoint.java
@@ -53,7 +53,7 @@ public class ExportEndpoint extends AbstractEndpoint {
             throw new NotAllowedException("Missing data export permission");
         }
         final HttpHeaders headers = new HttpHeaders();
-        final ExportResource resource = queryService.findAll(containerId, databaseId, tableId, timestamp, principal);
+        final ExportResource resource = queryService.tableFindAll(containerId, databaseId, tableId, timestamp, principal);
         headers.add("Content-Disposition", "attachment; filename=\"" + resource.getFilename() + "\"");
         log.trace("export table resulted in resource {}", resource);
         return ResponseEntity.ok()
diff --git a/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/QueryEndpoint.java b/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/QueryEndpoint.java
index 05db9d96edbec6859fe89bd718f38e4bf5dca9da..6f4faa2b4197be398b573ea68f76eddc8c42ab8b 100644
--- a/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/QueryEndpoint.java
+++ b/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/QueryEndpoint.java
@@ -108,6 +108,32 @@ public class QueryEndpoint extends AbstractEndpoint {
                 .body(result);
     }
 
+    @GetMapping("/{queryId}/data/count")
+    @Transactional(readOnly = true)
+    @Timed(value = "query.reexecute.count", description = "Time needed to re-execute a query")
+    @Operation(summary = "Re-execute some query", security = @SecurityRequirement(name = "bearerAuth"))
+    public ResponseEntity<Long> reExecuteCount(@NotNull @PathVariable("id") Long containerId,
+                                                    @NotNull @PathVariable("databaseId") Long databaseId,
+                                                    @NotNull @PathVariable("queryId") Long queryId,
+                                                    Principal principal)
+            throws QueryStoreException, QueryNotFoundException, DatabaseNotFoundException, ImageNotSupportedException,
+            QueryMalformedException, TableMalformedException, ColumnParseException, NotAllowedException,
+            DatabaseConnectionException, UserNotFoundException {
+        log.debug("endpoint re-execute query count, containerId={}, databaseId={}, queryId={}, principal={}",
+                containerId, databaseId, queryId, principal);
+        /* check */
+        if (!hasQueryPermission(containerId, databaseId, queryId, "QUERY_RE_EXECUTE", principal)) {
+            log.error("Missing re-execute query permission");
+            throw new NotAllowedException("Missing re-execute query permission");
+        }
+        /* execute */
+        final Query query = storeService.findOne(containerId, databaseId, queryId, principal);
+        final Long result = queryService.reExecuteCount(containerId, databaseId, query, principal);
+        log.trace("re-execute query count resulted in result {}", result);
+        return ResponseEntity.status(HttpStatus.ACCEPTED)
+                .body(result);
+    }
+
     @GetMapping("/{queryId}/export")
     @Transactional(readOnly = true)
     @Timed(value = "query.export", description = "Time needed to export query data")
diff --git a/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/TableDataEndpoint.java b/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/TableDataEndpoint.java
index a1d1e8648268418e1c0efa75efa2faa8379106a5..277e622b6273f66827b116972b8498e30b20dc43 100644
--- a/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/TableDataEndpoint.java
+++ b/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/TableDataEndpoint.java
@@ -14,7 +14,6 @@ import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.security.SecurityRequirement;
 import lombok.extern.log4j.Log4j2;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.HttpHeaders;
 import org.springframework.http.ResponseEntity;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
@@ -148,7 +147,7 @@ public class TableDataEndpoint extends AbstractEndpoint {
                                                  @RequestParam(required = false) String sortColumn)
             throws TableNotFoundException, DatabaseNotFoundException, DatabaseConnectionException,
             ImageNotSupportedException, TableMalformedException, PaginationException, ContainerNotFoundException,
-            QueryStoreException, NotAllowedException, QueryMalformedException, SortException, UserNotFoundException {
+            NotAllowedException, QueryMalformedException, SortException, UserNotFoundException {
         log.debug("endpoint find table data, containerId={}, databaseId={}, tableId={}, principal={}, timestamp={}, page={}, size={}, sortDirection={}, sortColumn={}",
                 containerId, databaseId, tableId, principal, timestamp, page, size, sortDirection, sortColumn);
         /* check */
@@ -157,17 +156,35 @@ public class TableDataEndpoint extends AbstractEndpoint {
             throw new NotAllowedException("Missing data view permission");
         }
         validateDataParams(page, size, sortDirection, sortColumn);
-        /* find */
-        final Long count = queryService.count(containerId, databaseId, tableId, timestamp, principal);
-        log.debug("find table data has produced {} tuples", count);
-        final HttpHeaders headers = new HttpHeaders();
-        headers.set("FDA-COUNT", count.toString());
-        final QueryResultDto response = queryService.findAll(containerId, databaseId, tableId, timestamp, page, size, principal);
+        final QueryResultDto response = queryService.tableFindAll(containerId, databaseId, tableId, timestamp, page, size, principal);
         log.trace("find table data resulted in result {}", response);
         return ResponseEntity.ok()
-                .headers(headers)
                 .body(response);
     }
 
+    @GetMapping("/count")
+    @Timed(value = "data.all.count", description = "Time needed to get count of all data from a table")
+    @Operation(summary = "Find data", security = @SecurityRequirement(name = "bearerAuth"))
+    public ResponseEntity<Long> getCount(@NotNull @PathVariable("id") Long containerId,
+                                                 @NotNull @PathVariable("databaseId") Long databaseId,
+                                                 @NotNull @PathVariable("tableId") Long tableId,
+                                                 @NotNull Principal principal,
+                                                 @RequestParam(required = false) Instant timestamp)
+            throws TableNotFoundException, DatabaseNotFoundException, DatabaseConnectionException,
+            ImageNotSupportedException, TableMalformedException, PaginationException, ContainerNotFoundException,
+            QueryStoreException, NotAllowedException, QueryMalformedException, SortException, UserNotFoundException {
+        log.debug("endpoint find table data, containerId={}, databaseId={}, tableId={}, principal={}, timestamp={}",
+                containerId, databaseId, tableId, principal, timestamp);
+        /* check */
+        if (!hasTablePermission(containerId, databaseId, tableId, "DATA_VIEW", principal)) {
+            log.error("Missing data view permission");
+            throw new NotAllowedException("Missing data view permission");
+        }
+        /* find */
+        final Long count = queryService.tableCount(containerId, databaseId, tableId, timestamp, principal);
+        log.debug("table data count is {} tuples", count);
+        return ResponseEntity.ok()
+                .body(count);
+    }
 
 }
diff --git a/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/ViewEndpoint.java b/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/ViewEndpoint.java
index 244280cac6a6a35723526a9aef867d187e1d9a7c..b5b2bf6954025a38f46c79de4b489067324b0945 100644
--- a/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/ViewEndpoint.java
+++ b/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/ViewEndpoint.java
@@ -92,7 +92,8 @@ public class ViewEndpoint extends AbstractEndpoint {
         }
         final Database database = databaseService.find(containerId, databaseId);
         log.trace("create view for database {}", database);
-        final View view = viewService.create(containerId, databaseId, data, principal);
+        final View view;
+        view = viewService.create(containerId, databaseId, data, principal);
         final ViewBriefDto dto = viewMapper.viewToViewBriefDto(view);
         log.trace("create view resulted in view {}", dto);
         return ResponseEntity.status(HttpStatus.CREATED)
@@ -154,7 +155,7 @@ public class ViewEndpoint extends AbstractEndpoint {
                                                @RequestParam(required = false) Long size)
             throws DatabaseNotFoundException, NotAllowedException, ViewNotFoundException, PaginationException,
             QueryStoreException, DatabaseConnectionException, TableMalformedException, QueryMalformedException,
-            ImageNotSupportedException, ColumnParseException, UserNotFoundException, ContainerNotFoundException {
+            ImageNotSupportedException, ColumnParseException, UserNotFoundException, ContainerNotFoundException, ViewMalformedException {
         log.debug("endpoint find view data, containerId={}, databaseId={}, viewId={}, principal={}, page={}, size={}",
                 containerId, databaseId, viewId, principal, page, size);
         /* check */
@@ -167,12 +168,37 @@ public class ViewEndpoint extends AbstractEndpoint {
         final Database database = databaseService.find(containerId, databaseId);
         log.trace("find view data for database {}", database);
         final View view = viewService.findById(databaseId, viewId, principal);
-        final ExecuteStatementDto statement = ExecuteStatementDto.builder()
-                .statement(view.getQuery())
-                .build();
-        log.trace("find view execute statement {}", statement);
-        final QueryResultDto result = queryService.execute(containerId, databaseId, statement, principal, page, size,
-                null, null);
+        final QueryResultDto result = queryService.viewFindAll(containerId, databaseId, view, page, size, principal);
+        log.trace("execute view {}", view);
+        log.trace("find view data resulted in result {}", result);
+        return ResponseEntity.ok()
+                .body(result);
+    }
+
+    @GetMapping("/{viewId}/data/count")
+    @Transactional(readOnly = true)
+    @Timed(value = "view.data.count", description = "Time needed to retrieve data count from a view")
+    @Operation(summary = "Find view data count", security = @SecurityRequirement(name = "bearerAuth"))
+    public ResponseEntity<Long> count(@NotNull @PathVariable("id") Long containerId,
+                                               @NotNull @PathVariable("databaseId") Long databaseId,
+                                               @NotNull @PathVariable("viewId") Long viewId,
+                                               Principal principal)
+            throws DatabaseNotFoundException, NotAllowedException, ViewNotFoundException, PaginationException,
+            QueryStoreException, DatabaseConnectionException, TableMalformedException, QueryMalformedException,
+            ImageNotSupportedException, ColumnParseException, UserNotFoundException, ContainerNotFoundException, ViewMalformedException {
+        log.debug("endpoint find view data count, containerId={}, databaseId={}, viewId={}, principal={}",
+                containerId, databaseId, viewId, principal);
+        /* check */
+        if (!hasDatabasePermission(containerId, databaseId, "DATA_VIEW", principal)) {
+            log.error("Missing view data in view permission");
+            throw new NotAllowedException("Missing view data in view permission");
+        }
+        /* find */
+        final Database database = databaseService.find(containerId, databaseId);
+        log.trace("find view data for database {}", database);
+        final View view = viewService.findById(databaseId, viewId, principal);
+        final Long result = queryService.viewCount(containerId, databaseId, view, principal);
+        log.trace("execute view {}", view);
         log.trace("find view data resulted in result {}", result);
         return ResponseEntity.ok()
                 .body(result);
diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java
index b369dfe7c4a12c8092a4c747a1620ea7d29dc646..556aa3937d3830d8f2c40b6c679ceb874843190b 100644
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java
+++ b/fda-query-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java
@@ -2411,8 +2411,8 @@ public abstract class BaseUnitTest {
             .exchangeName(DATABASE_1_EXCHANGE)
             .creator(USER_1)
             .owner(USER_1)
-            .tables(List.of()) /* TABLE_1, TABLE_2, TABLE_3 */
-            .views(List.of())
+            .tables(List.of(TABLE_1, TABLE_2, TABLE_3))
+            .views(List.of(VIEW_4))
             .build();
 
     public final static Database DATABASE_2 = Database.builder()
diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/ExportEndpointUnitTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/ExportEndpointUnitTest.java
index f64fc7af437e5ee1dbd5a7a7398032b371b9cfd4..f5126e08b48fb31b936fd2e56d4ab8ff7bd3f685 100644
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/ExportEndpointUnitTest.java
+++ b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/ExportEndpointUnitTest.java
@@ -247,7 +247,7 @@ public class ExportEndpointUnitTest extends BaseUnitTest {
         }
         when(tableRepository.find(containerId, databaseId, tableId))
                 .thenReturn(Optional.of(TABLE_1));
-        when(queryService.findAll(containerId, databaseId, tableId, timestamp, principal))
+        when(queryService.tableFindAll(containerId, databaseId, tableId, timestamp, principal))
                 .thenReturn(resource);
 
         /* test */
diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/TableDataEndpointUnitTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/TableDataEndpointUnitTest.java
index b536d7fe2e3d45589521566b3c6e05a7147f3922..4cf2392ed0a94319043e7738151d0c86123b7cf7 100644
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/TableDataEndpointUnitTest.java
+++ b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/TableDataEndpointUnitTest.java
@@ -20,8 +20,10 @@ import at.tuwien.service.TableService;
 import at.tuwien.service.impl.QueryServiceImpl;
 import com.rabbitmq.client.Channel;
 import lombok.extern.log4j.Log4j2;
-import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.boot.test.mock.mockito.MockBean;
@@ -31,6 +33,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
 
 import java.security.Principal;
 import java.time.Instant;
+import java.util.stream.Stream;
 
 import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.Mockito.*;
@@ -72,490 +75,299 @@ public class TableDataEndpointUnitTest extends BaseUnitTest {
     @Autowired
     private TableDataEndpoint dataEndpoint;
 
-    @Test
-    public void import_publicAnonymous_fails() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_import(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, TABLE_1_ID, TABLE_1, null,
-                    null, null);
-        });
-    }
-
-    @Test
-    public void import_publicRead_fails() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_import(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, TABLE_1_ID, TABLE_1, USER_2_USERNAME,
-                    DATABASE_1_READ_ACCESS, USER_2_PRINCIPAL);
-        });
-    }
-
-    @Test
-    public void import_publicWriteOwn_fails() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_import(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, TABLE_1_ID, TABLE_1, USER_2_USERNAME,
-                    DATABASE_1_WRITE_OWN_ACCESS, USER_2_PRINCIPAL);
-        });
-    }
-
-    @Test
-    public void import_publicWriteAll_succeeds() throws UserNotFoundException, TableNotFoundException,
-            NotAllowedException, TableMalformedException, DatabaseConnectionException, QueryMalformedException,
-            DatabaseNotFoundException, ImageNotSupportedException, ContainerNotFoundException {
-
-        /* test */
-        generic_import(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, TABLE_1_ID, TABLE_1, USER_2_USERNAME,
-                DATABASE_1_WRITE_ALL_ACCESS, USER_2_PRINCIPAL);
-    }
-
-    @Test
-    public void import_publicOwner_succeds() throws UserNotFoundException, TableNotFoundException, NotAllowedException,
-            TableMalformedException, DatabaseConnectionException, QueryMalformedException, DatabaseNotFoundException,
-            ImageNotSupportedException, ContainerNotFoundException {
-
-        /* test */
-        generic_import(CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, TABLE_1_ID, TABLE_1, USER_1_USERNAME,
-                DATABASE_1_WRITE_ALL_ACCESS, USER_1_PRINCIPAL);
-    }
-
-    @Test
-    public void insert_publicAnonymous_fails() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_insert(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, USER_2_USERNAME,
-                    null, TABLE_1_CSV_DTO, null);
-        });
-    }
-
-    @Test
-    public void insert_publicRead_fails() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_insert(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, USER_2_USERNAME,
-                    DATABASE_1_READ_ACCESS, TABLE_1_CSV_DTO, USER_2_PRINCIPAL);
-        });
-    }
-
-    @Test
-    public void insert_publicWriteOwn_fails() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_insert(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, USER_2_USERNAME,
-                    DATABASE_1_WRITE_OWN_ACCESS, TABLE_1_CSV_DTO, USER_2_PRINCIPAL);
-        });
-    }
-
-    @Test
-    public void insert_publicWriteAll_succeeds() throws UserNotFoundException, TableNotFoundException, NotAllowedException,
-            TableMalformedException, DatabaseConnectionException, DatabaseNotFoundException, ImageNotSupportedException,
-            ContainerNotFoundException {
-
-        /* test */
-        generic_insert(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, USER_2_USERNAME,
-                DATABASE_1_WRITE_ALL_ACCESS, TABLE_1_CSV_DTO, USER_2_PRINCIPAL);
-    }
-
-    @Test
-    public void insert_publicOwner_succeeds() throws UserNotFoundException, TableNotFoundException, NotAllowedException,
-            TableMalformedException, DatabaseConnectionException, DatabaseNotFoundException, ImageNotSupportedException,
-            ContainerNotFoundException {
-
-        /* test */
-        generic_insert(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, USER_1_USERNAME,
-                DATABASE_1_WRITE_ALL_ACCESS, TABLE_1_CSV_DTO, USER_1_PRINCIPAL);
-    }
-
-    @Test
-    public void insert_publicOwnerDataNull_succeeds() throws UserNotFoundException, TableNotFoundException,
-            NotAllowedException, TableMalformedException, DatabaseConnectionException, DatabaseNotFoundException,
-            ImageNotSupportedException, ContainerNotFoundException {
-
-        /* test */
-        generic_insert(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, USER_1_USERNAME,
-                DATABASE_1_WRITE_ALL_ACCESS, null, USER_1_PRINCIPAL);
-    }
-
-    @Test
-    public void getAll_publicAnonymous_succeeds() throws TableNotFoundException, DatabaseConnectionException, TableMalformedException,
-            DatabaseNotFoundException, ImageNotSupportedException, PaginationException, ContainerNotFoundException,
-            QueryStoreException, NotAllowedException, QueryMalformedException, SortException, UserNotFoundException {
-
-        /* test */
-        generic_getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, null,
-                null, null, null, null, null, null, null);
-    }
-
-    @Test
-    public void getAll_publicRead_succeeds() throws TableNotFoundException, DatabaseConnectionException, TableMalformedException,
-            DatabaseNotFoundException, ImageNotSupportedException, PaginationException, ContainerNotFoundException,
-            QueryStoreException, NotAllowedException, QueryMalformedException, SortException, UserNotFoundException {
-
-        /* test */
-        generic_getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, USER_2_USERNAME,
-                DATABASE_1_READ_ACCESS, USER_2_PRINCIPAL, null, null, null, null, null);
-    }
-
-    @Test
-    public void getAll_publicWriteOwn_succeeds() throws TableNotFoundException, DatabaseConnectionException, TableMalformedException,
-            DatabaseNotFoundException, ImageNotSupportedException, PaginationException, ContainerNotFoundException,
-            QueryStoreException, NotAllowedException, QueryMalformedException, SortException, UserNotFoundException {
-
-        /* test */
-        generic_getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, USER_2_USERNAME,
-                DATABASE_1_WRITE_OWN_ACCESS, USER_2_PRINCIPAL, null, null, null, null, null);
-    }
-
-    @Test
-    public void getAll_publicWriteAll_succeeds() throws TableNotFoundException, DatabaseConnectionException, TableMalformedException,
-            DatabaseNotFoundException, ImageNotSupportedException, PaginationException, ContainerNotFoundException,
-            QueryStoreException, NotAllowedException, QueryMalformedException, SortException, UserNotFoundException {
-
-        /* test */
-        generic_getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, USER_2_USERNAME,
-                DATABASE_1_WRITE_ALL_ACCESS, USER_2_PRINCIPAL, null, null, null, null, null);
-    }
-
-    @Test
-    public void getAll_publicOwner_succeeds() throws TableNotFoundException, DatabaseConnectionException, TableMalformedException,
-            DatabaseNotFoundException, ImageNotSupportedException, PaginationException, ContainerNotFoundException,
-            QueryStoreException, NotAllowedException, QueryMalformedException, SortException, UserNotFoundException {
-
-        /* test */
-        generic_getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, USER_1_USERNAME,
-                DATABASE_1_WRITE_ALL_ACCESS, USER_1_PRINCIPAL, null, null, null, null, null);
-    }
-
-    @Test
-    public void getAll_publicAnonymousPageNull_fails() {
-        final Long page = null;
-        final Long size = 1L;
-
-        /* test */
-        assertThrows(PaginationException.class, () -> {
-            generic_getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, null,
-                    null, null, null, page, size, null, null);
-        });
-    }
-
-    @Test
-    public void getAll_publicAnonymousSizeNull_fails() {
-        final Long page = 1L;
-        final Long size = null;
-
-        /* test */
-        assertThrows(PaginationException.class, () -> {
-            generic_getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, null,
-                    null, null, null, page, size, null, null);
-        });
-    }
-
-    @Test
-    public void getAll_publicAnonymousPageNegative_fails() {
-        final Long page = -1L;
-        final Long size = 1L;
-
-        /* test */
-        assertThrows(PaginationException.class, () -> {
-            generic_getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, null,
-                    null, null, null, page, size, null, null);
-        });
-    }
-
-    @Test
-    public void getAll_publicAnonymousSizeZero_fails() {
-        final Long page = 0L;
-        final Long size = 0L;
-
-        /* test */
-        assertThrows(PaginationException.class, () -> {
-            generic_getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, null,
-                    null, null, null, page, size, null, null);
-        });
-    }
-
-    @Test
-    public void getAll_publicAnonymousSizeNegative_fails() {
-        final Long page = 0L;
-        final Long size = -1L;
-
-        /* test */
-        assertThrows(PaginationException.class, () -> {
-            generic_getAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, null,
-                    null, null, null, page, size, null, null);
-        });
-    }
-
-    /* ################################################################################################### */
-    /* ## PRIVATE DATABASES                                                                             ## */
-    /* ################################################################################################### */
-
-    @Test
-    public void import_privateAnonymous_fails() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_import(CONTAINER_2_ID, DATABASE_2_ID, DATABASE_2, TABLE_1_ID, TABLE_1, null, null, null);
-        });
-    }
-
-    @Test
-    public void import_privateRead_fails() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_import(CONTAINER_2_ID, DATABASE_2_ID, DATABASE_2, TABLE_1_ID, TABLE_1, USER_2_USERNAME,
-                    DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL);
-        });
-    }
-
-    @Test
-    public void import_privateWriteOwn_fails() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_import(CONTAINER_2_ID, DATABASE_2_ID, DATABASE_2, TABLE_1_ID, TABLE_1, USER_2_USERNAME,
-                    DATABASE_2_WRITE_OWN_ACCESS, USER_2_PRINCIPAL);
-        });
-    }
-
-    @Test
-    public void import_privateWriteAll_succeeds() throws UserNotFoundException, TableNotFoundException,
-            NotAllowedException, TableMalformedException, DatabaseConnectionException, QueryMalformedException,
-            DatabaseNotFoundException, ImageNotSupportedException, ContainerNotFoundException {
-
-        /* test */
-        generic_import(CONTAINER_2_ID, DATABASE_2_ID, DATABASE_2, TABLE_1_ID, TABLE_1, USER_2_USERNAME,
-                DATABASE_2_WRITE_ALL_ACCESS, USER_2_PRINCIPAL);
-    }
-
-    @Test
-    public void import_privateOwner_succeds() throws UserNotFoundException, TableNotFoundException, NotAllowedException,
-            TableMalformedException, DatabaseConnectionException, QueryMalformedException, DatabaseNotFoundException,
-            ImageNotSupportedException, ContainerNotFoundException {
-
-        /* test */
-        generic_import(CONTAINER_2_ID, DATABASE_2_ID, DATABASE_2, TABLE_1_ID, TABLE_1, USER_1_USERNAME,
-                DATABASE_2_WRITE_ALL_ACCESS, USER_1_PRINCIPAL);
-    }
-
-    @Test
-    public void insert_privateAnonymous_fails() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_insert(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
-                    null, TABLE_1_CSV_DTO, null);
-        });
-    }
-
-    @Test
-    public void insert_privateRead_fails() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_insert(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
-                    DATABASE_2_READ_ACCESS, TABLE_1_CSV_DTO, USER_2_PRINCIPAL);
+    public static Stream<Arguments> import_fails_parameters() {
+        return Stream.of(
+                Arguments.arguments("public anonymous", NotAllowedException.class, CONTAINER_1_ID, DATABASE_1_ID,
+                        DATABASE_1,
+                        TABLE_1_ID, TABLE_1, null, null, null),
+                Arguments.arguments("public read", NotAllowedException.class, CONTAINER_1_ID, DATABASE_1_ID,
+                        DATABASE_1, TABLE_1_ID,
+                        TABLE_1, USER_2_USERNAME, DATABASE_1_READ_ACCESS, USER_2_PRINCIPAL),
+                Arguments.arguments("public write-own", NotAllowedException.class, CONTAINER_1_ID, DATABASE_1_ID,
+                        DATABASE_1, TABLE_1_ID,
+                        TABLE_1, USER_2_USERNAME, DATABASE_1_WRITE_OWN_ACCESS, USER_2_PRINCIPAL),
+                Arguments.arguments("private anonymous", NotAllowedException.class, CONTAINER_2_ID, DATABASE_2_ID,
+                        DATABASE_2, TABLE_1_ID, TABLE_1, null, null, null),
+                Arguments.arguments("private read", NotAllowedException.class, CONTAINER_2_ID, DATABASE_2_ID,
+                        DATABASE_2, TABLE_1_ID, TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL),
+                Arguments.arguments("private write-own", NotAllowedException.class, CONTAINER_2_ID, DATABASE_2_ID,
+                        DATABASE_2, TABLE_1_ID, TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_WRITE_OWN_ACCESS, USER_2_PRINCIPAL)
+        );
+    }
+
+    @ParameterizedTest
+    @MethodSource("import_fails_parameters")
+    public <T extends Throwable> void import_fails(String test, Class<T> expectedException, Long containerId,
+                                                   Long databaseId, Database database, Long tableId, Table table,
+                                                   String username, DatabaseAccess access, Principal principal) {
+
+        /* test */
+        assertThrows(expectedException, () -> {
+            generic_import(containerId, databaseId, database, tableId, table, username, access, principal);
         });
     }
 
-    @Test
-    public void insert_privateWriteOwn_fails() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_insert(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
-                    DATABASE_2_WRITE_OWN_ACCESS, TABLE_1_CSV_DTO, USER_2_PRINCIPAL);
+    public static Stream<Arguments> import_succeeds_parameters() {
+        return Stream.of(
+                Arguments.arguments("public write-all", CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, TABLE_1_ID, TABLE_1,
+                        USER_2_USERNAME, DATABASE_1_WRITE_ALL_ACCESS, USER_2_PRINCIPAL),
+                Arguments.arguments("public owner", CONTAINER_1_ID, DATABASE_1_ID, DATABASE_1, TABLE_1_ID, TABLE_1,
+                        USER_1_USERNAME, DATABASE_1_WRITE_ALL_ACCESS, USER_1_PRINCIPAL),
+                Arguments.arguments("private write-all", CONTAINER_2_ID, DATABASE_2_ID, DATABASE_2, TABLE_1_ID,
+                        TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_WRITE_ALL_ACCESS, USER_2_PRINCIPAL),
+                Arguments.arguments("private owner", CONTAINER_2_ID, DATABASE_2_ID, DATABASE_2, TABLE_1_ID, TABLE_1,
+                        USER_1_USERNAME,
+                        DATABASE_2_WRITE_ALL_ACCESS, USER_1_PRINCIPAL)
+        );
+    }
+
+    @ParameterizedTest
+    @MethodSource("import_succeeds_parameters")
+    public void import_succeeds(String test, Long containerId, Long databaseId, Database database, Long tableId,
+                                Table table, String username, DatabaseAccess access, Principal principal) throws UserNotFoundException, TableNotFoundException, NotAllowedException, TableMalformedException, DatabaseConnectionException, QueryMalformedException, DatabaseNotFoundException, ImageNotSupportedException, ContainerNotFoundException {
+
+        /* test */
+        generic_import(containerId, databaseId, database, tableId, table, username, access, principal);
+    }
+
+    public static Stream<Arguments> insert_fails_parameters() {
+        return Stream.of(
+                Arguments.arguments("public anonymous", NotAllowedException.class, CONTAINER_1_ID, DATABASE_1_ID,
+                        TABLE_1_ID,
+                        DATABASE_1, TABLE_1, USER_2_USERNAME, null, TABLE_1_CSV_DTO, null),
+                Arguments.arguments("public read", NotAllowedException.class, CONTAINER_1_ID, DATABASE_1_ID,
+                        TABLE_1_ID, DATABASE_1,
+                        TABLE_1, USER_2_USERNAME, DATABASE_1_READ_ACCESS, TABLE_1_CSV_DTO, USER_2_PRINCIPAL),
+                Arguments.arguments("public write-own", NotAllowedException.class, CONTAINER_1_ID, DATABASE_1_ID,
+                        TABLE_1_ID, DATABASE_1,
+                        TABLE_1, USER_2_USERNAME, DATABASE_1_WRITE_OWN_ACCESS, TABLE_1_CSV_DTO, USER_2_PRINCIPAL),
+                Arguments.arguments("private anonymous", NotAllowedException.class, CONTAINER_2_ID, DATABASE_2_ID,
+                        TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME, null,
+                        TABLE_1_CSV_DTO, null),
+                Arguments.arguments("private read", NotAllowedException.class, CONTAINER_2_ID, DATABASE_2_ID,
+                        TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_READ_ACCESS, TABLE_1_CSV_DTO, USER_2_PRINCIPAL),
+                Arguments.arguments("private write-own", NotAllowedException.class, CONTAINER_2_ID, DATABASE_2_ID,
+                        TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_WRITE_OWN_ACCESS, TABLE_1_CSV_DTO, USER_2_PRINCIPAL)
+        );
+    }
+
+    @ParameterizedTest
+    @MethodSource("insert_fails_parameters")
+    public <T extends Throwable> void insert_fails(String test, Class<T> expectedException, Long containerId,
+                                                   Long databaseId, Long tableId, Database database, Table table,
+                                                   String username, DatabaseAccess access, TableCsvDto data,
+                                                   Principal principal) {
+
+        /* test */
+        assertThrows(expectedException, () -> {
+            generic_insert(containerId, databaseId, tableId, database, table, username, access, data, principal);
         });
     }
 
-    @Test
-    public void insert_privateWriteAll_succeeds() throws UserNotFoundException, TableNotFoundException, NotAllowedException,
-            TableMalformedException, DatabaseConnectionException, DatabaseNotFoundException, ImageNotSupportedException,
-            ContainerNotFoundException {
-
-        /* test */
-        generic_insert(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
-                DATABASE_2_WRITE_ALL_ACCESS, TABLE_1_CSV_DTO, USER_2_PRINCIPAL);
-    }
-
-    @Test
-    public void insert_privateOwner_succeeds() throws UserNotFoundException, TableNotFoundException, NotAllowedException,
-            TableMalformedException, DatabaseConnectionException, DatabaseNotFoundException, ImageNotSupportedException,
-            ContainerNotFoundException {
-
-        /* test */
-        generic_insert(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_1_USERNAME,
-                DATABASE_2_WRITE_ALL_ACCESS, TABLE_1_CSV_DTO, USER_1_PRINCIPAL);
-    }
-
-    @Test
-    public void insert_privateOwnerDataNull_succeeds() throws UserNotFoundException, TableNotFoundException,
+    public static Stream<Arguments> insert_succeeds_parameters() {
+        return Stream.of(
+                Arguments.arguments("public write-all", CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1,
+                        TABLE_1, USER_2_USERNAME,
+                        DATABASE_1_WRITE_ALL_ACCESS, TABLE_1_CSV_DTO, USER_2_PRINCIPAL),
+                Arguments.arguments("public owner", CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1,
+                        USER_1_USERNAME,
+                        DATABASE_1_WRITE_ALL_ACCESS, TABLE_1_CSV_DTO, USER_1_PRINCIPAL),
+                Arguments.arguments("public owner, data null", CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1,
+                        TABLE_1, USER_1_USERNAME,
+                        DATABASE_1_WRITE_ALL_ACCESS, null, USER_1_PRINCIPAL),
+                Arguments.arguments("private write-all", CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2,
+                        TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_WRITE_ALL_ACCESS, TABLE_1_CSV_DTO, USER_2_PRINCIPAL),
+                Arguments.arguments("private owner", CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1,
+                        USER_1_USERNAME,
+                        DATABASE_2_WRITE_ALL_ACCESS, TABLE_1_CSV_DTO, USER_1_PRINCIPAL),
+                Arguments.arguments("private owner, data null", CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2
+                        , TABLE_1, USER_1_USERNAME,
+                        DATABASE_2_WRITE_ALL_ACCESS, null, USER_1_PRINCIPAL)
+        );
+    }
+
+    @ParameterizedTest
+    @MethodSource("insert_succeeds_parameters")
+    public void insert_succeeds(String test, Long containerId, Long databaseId, Long tableId, Database database,
+                                Table table, String username, DatabaseAccess access, TableCsvDto data,
+                                Principal principal) throws UserNotFoundException, TableNotFoundException,
             NotAllowedException, TableMalformedException, DatabaseConnectionException, DatabaseNotFoundException,
             ImageNotSupportedException, ContainerNotFoundException {
 
         /* test */
-        generic_insert(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_1_USERNAME,
-                DATABASE_2_WRITE_ALL_ACCESS, null, USER_1_PRINCIPAL);
-    }
-
-    @Test
-    public void getAll_privateAnonymous_succeeds() {
-
-        /* test */
-        assertThrows(NotAllowedException.class, () -> {
-            generic_getAll(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, null,
-                    null, null, null, null, null, null, null);
-        });
-    }
-
-    @Test
-    public void getAll_privateRead_succeeds() throws TableNotFoundException, DatabaseConnectionException, TableMalformedException,
-            DatabaseNotFoundException, ImageNotSupportedException, PaginationException, ContainerNotFoundException,
-            QueryStoreException, NotAllowedException, QueryMalformedException, SortException, UserNotFoundException {
-
-        /* test */
-        generic_getAll(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
-                DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL, null, null, null, null, null);
-    }
-
-    @Test
-    public void getAll_privateWriteOwn_succeeds() throws TableNotFoundException, DatabaseConnectionException, TableMalformedException,
-            DatabaseNotFoundException, ImageNotSupportedException, PaginationException, ContainerNotFoundException,
-            QueryStoreException, NotAllowedException, QueryMalformedException, SortException, UserNotFoundException {
-
-        /* test */
-        generic_getAll(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
-                DATABASE_2_WRITE_OWN_ACCESS, USER_2_PRINCIPAL, null, null, null, null, null);
-    }
-
-    @Test
-    public void getAll_privateWriteAll_succeeds() throws TableNotFoundException, DatabaseConnectionException, TableMalformedException,
-            DatabaseNotFoundException, ImageNotSupportedException, PaginationException, ContainerNotFoundException,
-            QueryStoreException, NotAllowedException, QueryMalformedException, SortException, UserNotFoundException {
-
-        /* test */
-        generic_getAll(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
-                DATABASE_2_WRITE_ALL_ACCESS, USER_2_PRINCIPAL, null, null, null, null, null);
-    }
-
-    @Test
-    public void getAll_privateOwner_succeeds() throws TableNotFoundException, DatabaseConnectionException, TableMalformedException,
-            DatabaseNotFoundException, ImageNotSupportedException, PaginationException, ContainerNotFoundException,
-            QueryStoreException, NotAllowedException, QueryMalformedException, SortException, UserNotFoundException {
-
-        /* test */
-        generic_getAll(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_1_USERNAME,
-                DATABASE_2_WRITE_ALL_ACCESS, USER_1_PRINCIPAL, null, null, null, null, null);
-    }
-
-    @Test
-    public void getAll_privateReadPageNull_fails() {
-        final Long page = null;
-        final Long size = 1L;
-
-        /* test */
-        assertThrows(PaginationException.class, () -> {
-            generic_getAll(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
-                    DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL, null, page, size, null, null);
-        });
-    }
-
-    @Test
-    public void getAll_privateReadSizeNull_fails() {
-        final Long page = 1L;
-        final Long size = null;
-
-        /* test */
-        assertThrows(PaginationException.class, () -> {
-            generic_getAll(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
-                    DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL, null, page, size, null, null);
-        });
-    }
-
-    @Test
-    public void getAll_privateReadPageNegative_fails() {
-        final Long page = -1L;
-        final Long size = 1L;
-
-        /* test */
-        assertThrows(PaginationException.class, () -> {
-            generic_getAll(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
-                    DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL, null, page, size, null, null);
+        generic_insert(containerId, databaseId, tableId, database, table, username, access, data, principal);
+    }
+
+    public static Stream<Arguments> getAll_fails_parameters() {
+        return Stream.of(
+                Arguments.arguments("public anonymous page null", PaginationException.class, CONTAINER_1_ID,
+                        DATABASE_1_ID, TABLE_1_ID, DATABASE_1,
+                        TABLE_1, null, null, null, null, null, 1L, null, null),
+                Arguments.arguments("public anonymous size null", PaginationException.class, CONTAINER_1_ID,
+                        DATABASE_1_ID, TABLE_1_ID, DATABASE_1,
+                        TABLE_1, null, null, null, null, 1L, null, null, null),
+                Arguments.arguments("public anonymous page negative", PaginationException.class, CONTAINER_1_ID,
+                        DATABASE_1_ID, TABLE_1_ID, DATABASE_1,
+                        TABLE_1, null, null, null, null, -1L, 1L, null, null),
+                Arguments.arguments("public anonymous size zero", PaginationException.class, CONTAINER_1_ID,
+                        DATABASE_1_ID, TABLE_1_ID, DATABASE_1,
+                        TABLE_1, null, null, null, null, 0L, 0L, null, null),
+                Arguments.arguments("public anonymous size negative", PaginationException.class, CONTAINER_1_ID,
+                        DATABASE_1_ID, TABLE_1_ID, DATABASE_1,
+                        TABLE_1, null, null, null, null, 0L, -1L, null, null),
+                Arguments.arguments("private anonymous", NotAllowedException.class, CONTAINER_2_ID, DATABASE_2_ID,
+                        TABLE_1_ID, DATABASE_2, TABLE_1, null, null, null, null,
+                        null, null, null, null),
+                Arguments.arguments("private read, page null", PaginationException.class, CONTAINER_2_ID,
+                        DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL, null, null, 1L, null, null),
+                Arguments.arguments("private read, size null", PaginationException.class, CONTAINER_2_ID,
+                        DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL, null, 1L, null, null, null),
+                Arguments.arguments("private read, page negative", PaginationException.class, CONTAINER_2_ID,
+                        DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL, null, -1L, 1L, null, null),
+                Arguments.arguments("private read, size zero", PaginationException.class, CONTAINER_2_ID,
+                        DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL, null, 0L, 0L, null, null),
+                Arguments.arguments("private read, size negative", PaginationException.class, CONTAINER_2_ID,
+                        DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL, null, 0L, -1L, null, null)
+        );
+    }
+
+    @ParameterizedTest
+    @MethodSource("getAll_fails_parameters")
+    public <T extends Throwable> void getAll_fails(String test, Class<T> expectedException, Long containerId,
+                                                   Long databaseId, Long tableId, Database database, Table table,
+                                                   String username, DatabaseAccess access, Principal principal,
+                                                   Instant timestamp, Long page, Long size, SortType sortDirection,
+                                                   String sortColumn) {
+
+        /* test */
+        assertThrows(expectedException, () -> {
+            generic_getAll(containerId, databaseId, tableId, database, table, username, access, principal, timestamp,
+                    page, size, sortDirection, sortColumn);
         });
     }
 
-    @Test
-    public void getAll_privateReadSizeZero_fails() {
-        final Long page = 0L;
-        final Long size = 0L;
-
-        /* test */
-        assertThrows(PaginationException.class, () -> {
-            generic_getAll(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
-                    DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL, null, page, size, null, null);
-        });
+    public static Stream<Arguments> getAll_succeeds_parameters() {
+        return Stream.of(
+                Arguments.arguments("public anonymous", CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1,
+                        TABLE_1, null, null, null,
+                        null, null, null, null, null),
+                Arguments.arguments("public read", CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1,
+                        USER_2_USERNAME,
+                        DATABASE_1_READ_ACCESS, USER_2_PRINCIPAL, null, null, null, null, null),
+                Arguments.arguments("public write-own", CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1,
+                        TABLE_1, USER_2_USERNAME,
+                        DATABASE_1_WRITE_OWN_ACCESS, USER_2_PRINCIPAL, null, null, null, null, null),
+                Arguments.arguments("public write-all", CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1,
+                        TABLE_1, USER_2_USERNAME,
+                        DATABASE_1_WRITE_ALL_ACCESS, USER_2_PRINCIPAL, null, null, null, null, null),
+                Arguments.arguments("public owner", CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1,
+                        USER_1_USERNAME,
+                        DATABASE_1_WRITE_ALL_ACCESS, USER_1_PRINCIPAL, null, null, null, null, null),
+                Arguments.arguments("private read", CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1,
+                        USER_2_USERNAME,
+                        DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL, null, null, null, null, null),
+                Arguments.arguments("private write-own", CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2,
+                        TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_WRITE_OWN_ACCESS, USER_2_PRINCIPAL, null, null, null, null, null),
+                Arguments.arguments("private write-all", CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2,
+                        TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_WRITE_ALL_ACCESS, USER_2_PRINCIPAL, null, null, null, null, null),
+                Arguments.arguments("private owner", CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1,
+                        USER_1_USERNAME,
+                        DATABASE_2_WRITE_ALL_ACCESS, USER_1_PRINCIPAL, null, null, null, null, null)
+        );
+    }
+
+    @ParameterizedTest
+    @MethodSource("getAll_succeeds_parameters")
+    public void getAll_succeeds(String test, Long containerId, Long databaseId, Long tableId, Database database,
+                                Table table, String username, DatabaseAccess access, Principal principal,
+                                Instant timestamp, Long page, Long size, SortType sortDirection, String sortColumn) throws UserNotFoundException, TableNotFoundException, QueryStoreException, SortException, TableMalformedException, NotAllowedException, DatabaseConnectionException, QueryMalformedException, DatabaseNotFoundException, ImageNotSupportedException, PaginationException, ContainerNotFoundException {
+
+        /* test */
+        generic_getAll(containerId, databaseId, tableId, database, table, username, access, principal, timestamp,
+                page, size, sortDirection, sortColumn);
+    }
+
+    public static Stream<Arguments> getCount_succeeds_parameters() {
+        return Stream.of(
+                Arguments.arguments("public anonymous", CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1,
+                        TABLE_1, null, null, null, null),
+                Arguments.arguments("public read", CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1,
+                        USER_2_USERNAME,
+                        DATABASE_1_READ_ACCESS, USER_2_PRINCIPAL, null),
+                Arguments.arguments("public write-own", CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1,
+                        TABLE_1, USER_2_USERNAME,
+                        DATABASE_1_WRITE_OWN_ACCESS, USER_2_PRINCIPAL, null),
+                Arguments.arguments("public write-all", CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1,
+                        TABLE_1, USER_2_USERNAME,
+                        DATABASE_1_WRITE_ALL_ACCESS, USER_2_PRINCIPAL, null),
+                Arguments.arguments("public owner", CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1,
+                        USER_1_USERNAME,
+                        DATABASE_1_WRITE_ALL_ACCESS, USER_1_PRINCIPAL, null),
+                Arguments.arguments("private read", CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1,
+                        USER_2_USERNAME,
+                        DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL, null),
+                Arguments.arguments("private write-own", CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2,
+                        TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_WRITE_OWN_ACCESS, USER_2_PRINCIPAL, null),
+                Arguments.arguments("private write-all", CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2,
+                        TABLE_1, USER_2_USERNAME,
+                        DATABASE_2_WRITE_ALL_ACCESS, USER_2_PRINCIPAL, null),
+                Arguments.arguments("private owner", CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1,
+                        USER_1_USERNAME,
+                        DATABASE_2_WRITE_ALL_ACCESS, USER_1_PRINCIPAL, null)
+        );
+    }
+
+    @ParameterizedTest
+    @MethodSource("getAll_succeeds_parameters")
+    public void getCount_succeeds(String test, Long containerId, Long databaseId, Long tableId, Database database,
+                                Table table, String username, DatabaseAccess access, Principal principal,
+                                Instant timestamp) throws UserNotFoundException, TableNotFoundException, QueryStoreException, SortException, TableMalformedException, NotAllowedException, DatabaseConnectionException, QueryMalformedException, DatabaseNotFoundException, ImageNotSupportedException, PaginationException, ContainerNotFoundException {
+
+        /* test */
+        generic_getCount(containerId, databaseId, tableId, database, table, username, access, principal, timestamp);
     }
 
-    @Test
-    public void getAll_privateReadSizeNegative_fails() {
-        final Long page = 0L;
-        final Long size = -1L;
-
-        /* test */
-        assertThrows(PaginationException.class, () -> {
-            generic_getAll(CONTAINER_2_ID, DATABASE_2_ID, TABLE_1_ID, DATABASE_2, TABLE_1, USER_2_USERNAME,
-                    DATABASE_2_READ_ACCESS, USER_2_PRINCIPAL, null, page, size, null, null);
-        });
-    }
 
     /* ################################################################################################### */
     /* ## GENERIC TEST CASES                                                                            ## */
     /* ################################################################################################### */
 
     public void generic_import(Long containerId, Long databaseId, Database database, Long tableId, Table table,
-                               String username, DatabaseAccess access, Principal principal)
-            throws DatabaseNotFoundException, TableNotFoundException, NotAllowedException, UserNotFoundException,
-            TableMalformedException, DatabaseConnectionException, QueryMalformedException, ImageNotSupportedException,
-            ContainerNotFoundException {
-        final ImportDto request = ImportDto.builder()
-                .location("test:csv/csv_01.csv")
-                .build();
+                               String username, DatabaseAccess access, Principal principal) throws DatabaseNotFoundException, TableNotFoundException, NotAllowedException, UserNotFoundException, TableMalformedException, DatabaseConnectionException, QueryMalformedException, ImageNotSupportedException, ContainerNotFoundException {
+        final ImportDto request = ImportDto.builder().location("test:csv/csv_01.csv").build();
 
         /* mock */
-        when(databaseService.find(containerId, databaseId))
-                .thenReturn(database);
-        when(tableService.find(containerId, databaseId, tableId))
-                .thenReturn(table);
-        when(accessService.find(databaseId, username))
-                .thenReturn(access);
+        when(databaseService.find(containerId, databaseId)).thenReturn(database);
+        when(tableService.find(containerId, databaseId, tableId)).thenReturn(table);
+        when(accessService.find(databaseId, username)).thenReturn(access);
 
         /* test */
-        final ResponseEntity<?> response = dataEndpoint.importCsv(containerId, databaseId, tableId, request,
-                principal);
+        final ResponseEntity<?> response = dataEndpoint.importCsv(containerId, databaseId, tableId, request, principal);
         assertNotNull(response);
         assertEquals(HttpStatus.ACCEPTED, response.getStatusCode());
     }
 
     public void generic_insert(Long containerId, Long databaseId, Long tableId, Database database, Table table,
-                               String username, DatabaseAccess access, TableCsvDto data, Principal principal)
-            throws DatabaseNotFoundException, TableNotFoundException, NotAllowedException, UserNotFoundException,
-            TableMalformedException, DatabaseConnectionException, ImageNotSupportedException,
-            ContainerNotFoundException {
+                               String username, DatabaseAccess access, TableCsvDto data, Principal principal) throws DatabaseNotFoundException, TableNotFoundException, NotAllowedException, UserNotFoundException, TableMalformedException, DatabaseConnectionException, ImageNotSupportedException, ContainerNotFoundException {
 
         /* mock */
-        when(databaseService.find(containerId, databaseId))
-                .thenReturn(database);
-        when(tableService.find(containerId, databaseId, tableId))
-                .thenReturn(table);
-        when(accessService.find(databaseId, username))
-                .thenReturn(access);
+        when(databaseService.find(containerId, databaseId)).thenReturn(database);
+        when(tableService.find(containerId, databaseId, tableId)).thenReturn(table);
+        when(accessService.find(databaseId, username)).thenReturn(access);
 
         /* test */
         final ResponseEntity<?> response = dataEndpoint.insert(containerId, databaseId, tableId, data, principal);
@@ -565,23 +377,17 @@ public class TableDataEndpointUnitTest extends BaseUnitTest {
 
     public void generic_getAll(Long containerId, Long databaseId, Long tableId, Database database, Table table,
                                String username, DatabaseAccess access, Principal principal, Instant timestamp,
-                               Long page, Long size, SortType sortDirection, String sortColumn)
-            throws UserNotFoundException, TableMalformedException, NotAllowedException, PaginationException,
-            TableNotFoundException, QueryStoreException, SortException, DatabaseConnectionException,
-            QueryMalformedException, DatabaseNotFoundException, ImageNotSupportedException, ContainerNotFoundException {
+                               Long page, Long size, SortType sortDirection, String sortColumn) throws UserNotFoundException, TableMalformedException, NotAllowedException, PaginationException, TableNotFoundException, QueryStoreException, SortException, DatabaseConnectionException, QueryMalformedException, DatabaseNotFoundException, ImageNotSupportedException, ContainerNotFoundException {
 
         /* mock */
-        when(databaseService.find(containerId, databaseId))
-                .thenReturn(database);
-        when(tableService.find(containerId, databaseId, tableId))
-                .thenReturn(table);
-        when(accessService.find(databaseId, username))
-                .thenReturn(access);
-        when(queryService.findAll(containerId, databaseId, tableId, timestamp, page, size, principal))
-                .thenReturn(QUERY_1_RESULT_DTO);
+        when(databaseService.find(containerId, databaseId)).thenReturn(database);
+        when(tableService.find(containerId, databaseId, tableId)).thenReturn(table);
+        when(accessService.find(databaseId, username)).thenReturn(access);
+        when(queryService.tableFindAll(containerId, databaseId, tableId, timestamp, page, size, principal)).thenReturn(QUERY_1_RESULT_DTO);
 
         /* test */
-        final ResponseEntity<QueryResultDto> response = dataEndpoint.getAll(containerId, databaseId, tableId, principal, timestamp, page, size, sortDirection, sortColumn);
+        final ResponseEntity<QueryResultDto> response = dataEndpoint.getAll(containerId, databaseId, tableId,
+                principal, timestamp, page, size, sortDirection, sortColumn);
         assertEquals(HttpStatus.OK, response.getStatusCode());
         assertNotNull(response.getBody());
         assertEquals(QUERY_1_RESULT_ID, response.getBody().getId());
@@ -589,4 +395,21 @@ public class TableDataEndpointUnitTest extends BaseUnitTest {
         assertEquals(QUERY_1_RESULT_RESULT, response.getBody().getResult());
     }
 
+    public void generic_getCount(Long containerId, Long databaseId, Long tableId, Database database, Table table,
+                               String username, DatabaseAccess access, Principal principal, Instant timestamp) throws UserNotFoundException, TableMalformedException, NotAllowedException, PaginationException, TableNotFoundException, QueryStoreException, SortException, DatabaseConnectionException, QueryMalformedException, DatabaseNotFoundException, ImageNotSupportedException, ContainerNotFoundException {
+
+        /* mock */
+        when(databaseService.find(containerId, databaseId)).thenReturn(database);
+        when(tableService.find(containerId, databaseId, tableId)).thenReturn(table);
+        when(accessService.find(databaseId, username)).thenReturn(access);
+        when(queryService.tableCount(containerId, databaseId, tableId, timestamp, principal)).thenReturn(QUERY_1_RESULT_NUMBER);
+
+        /* test */
+        final ResponseEntity<Long> response = dataEndpoint.getCount(containerId, databaseId, tableId,
+                principal, timestamp);
+        assertEquals(HttpStatus.OK, response.getStatusCode());
+        assertNotNull(response.getBody());
+        assertEquals(QUERY_1_RESULT_NUMBER, response.getBody());
+    }
+
 }
diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java
index 6c57a23e676490e617746ce0ca4bca75d085d119..5cf4aadd98085ace3f9bfe569c5d9e0a063c9103 100644
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java
+++ b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java
@@ -321,7 +321,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
     public void data_publicAnonymous_succeeds() throws UserNotFoundException, NotAllowedException,
             DatabaseNotFoundException, ViewNotFoundException, DatabaseConnectionException, QueryMalformedException,
             QueryStoreException, TableMalformedException, ColumnParseException, ImageNotSupportedException,
-            ContainerNotFoundException, PaginationException {
+            ContainerNotFoundException, PaginationException, ViewMalformedException {
 
         /* test */
         data_generic(CONTAINER_1_ID, DATABASE_1_ID, VIEW_1_ID, DATABASE_1, null, null, null);
@@ -332,7 +332,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
     public void data_publicAnonymous2_succeeds() throws UserNotFoundException, NotAllowedException,
             DatabaseNotFoundException, ViewNotFoundException, DatabaseConnectionException, QueryMalformedException,
             QueryStoreException, TableMalformedException, ColumnParseException, ImageNotSupportedException,
-            ContainerNotFoundException, PaginationException {
+            ContainerNotFoundException, PaginationException, ViewMalformedException {
 
         /* test */
         data_generic(CONTAINER_1_ID, DATABASE_1_ID, VIEW_1_ID, DATABASE_1, null, null, null);
@@ -343,7 +343,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
     public void data_publicRead_succeeds() throws UserNotFoundException, NotAllowedException,
             DatabaseNotFoundException, ViewNotFoundException, DatabaseConnectionException, QueryMalformedException,
             QueryStoreException, TableMalformedException, ColumnParseException, ImageNotSupportedException,
-            ContainerNotFoundException, PaginationException {
+            ContainerNotFoundException, PaginationException, ViewMalformedException {
 
         /* test */
         data_generic(CONTAINER_1_ID, DATABASE_1_ID, VIEW_1_ID, DATABASE_1, USER_2_USERNAME, USER_2_PRINCIPAL, DATABASE_1_READ_ACCESS);
@@ -354,7 +354,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
     public void data_publicWriteOwn_succeeds() throws UserNotFoundException, NotAllowedException,
             DatabaseNotFoundException, ViewNotFoundException, DatabaseConnectionException, QueryMalformedException,
             QueryStoreException, TableMalformedException, ColumnParseException, ImageNotSupportedException,
-            ContainerNotFoundException, PaginationException {
+            ContainerNotFoundException, PaginationException, ViewMalformedException {
 
         /* test */
         data_generic(CONTAINER_1_ID, DATABASE_1_ID, VIEW_1_ID, DATABASE_1, USER_2_USERNAME, USER_2_PRINCIPAL, DATABASE_1_WRITE_OWN_ACCESS);
@@ -365,7 +365,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
     public void data_publicWriteAll_succeeds() throws UserNotFoundException, NotAllowedException,
             DatabaseNotFoundException, ViewNotFoundException, DatabaseConnectionException, QueryMalformedException,
             QueryStoreException, TableMalformedException, ColumnParseException, ImageNotSupportedException,
-            ContainerNotFoundException, PaginationException {
+            ContainerNotFoundException, PaginationException, ViewMalformedException {
 
         /* test */
         data_generic(CONTAINER_1_ID, DATABASE_1_ID, VIEW_1_ID, DATABASE_1, USER_2_USERNAME, USER_2_PRINCIPAL, DATABASE_1_WRITE_ALL_ACCESS);
@@ -376,7 +376,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
     public void data_publicOwner_succeeds() throws UserNotFoundException, NotAllowedException,
             DatabaseNotFoundException, ViewNotFoundException, DatabaseConnectionException, QueryMalformedException,
             QueryStoreException, TableMalformedException, ColumnParseException, ImageNotSupportedException,
-            ContainerNotFoundException, PaginationException {
+            ContainerNotFoundException, PaginationException, ViewMalformedException {
 
         /* test */
         data_generic(CONTAINER_1_ID, DATABASE_1_ID, VIEW_1_ID, DATABASE_1, USER_1_USERNAME, USER_1_PRINCIPAL, DATABASE_1_WRITE_ALL_ACCESS);
@@ -387,7 +387,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
     public void data_privateResearcher_succeeds() throws UserNotFoundException, QueryStoreException,
             NotAllowedException, DatabaseConnectionException, TableMalformedException, QueryMalformedException,
             ColumnParseException, DatabaseNotFoundException, ImageNotSupportedException, ContainerNotFoundException,
-            PaginationException, ViewNotFoundException {
+            PaginationException, ViewNotFoundException, ViewMalformedException {
 
         /* test */
         data_generic(CONTAINER_2_ID, DATABASE_2_ID, VIEW_4_ID, DATABASE_2, USER_1_USERNAME, USER_1_PRINCIPAL, null);
@@ -570,7 +570,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
     public void data_privateAnonymous_succeeds() throws UserNotFoundException, NotAllowedException,
             DatabaseNotFoundException, ViewNotFoundException, DatabaseConnectionException, QueryMalformedException,
             QueryStoreException, TableMalformedException, ColumnParseException, ImageNotSupportedException,
-            ContainerNotFoundException, PaginationException {
+            ContainerNotFoundException, PaginationException, ViewMalformedException {
 
         /* test */
         data_generic(CONTAINER_2_ID, DATABASE_2_ID, VIEW_1_ID, DATABASE_2, null, null, null);
@@ -580,7 +580,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
     public void data_privateRead_succeeds() throws UserNotFoundException, NotAllowedException,
             DatabaseNotFoundException, ViewNotFoundException, DatabaseConnectionException, QueryMalformedException,
             QueryStoreException, TableMalformedException, ColumnParseException, ImageNotSupportedException,
-            ContainerNotFoundException, PaginationException {
+            ContainerNotFoundException, PaginationException, ViewMalformedException {
 
         /* test */
         data_generic(CONTAINER_2_ID, DATABASE_2_ID, VIEW_1_ID, DATABASE_2, USER_2_USERNAME, USER_2_PRINCIPAL, DATABASE_2_READ_ACCESS);
@@ -590,7 +590,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
     public void data_privateWriteOwn_succeeds() throws UserNotFoundException, NotAllowedException,
             DatabaseNotFoundException, ViewNotFoundException, DatabaseConnectionException, QueryMalformedException,
             QueryStoreException, TableMalformedException, ColumnParseException, ImageNotSupportedException,
-            ContainerNotFoundException, PaginationException {
+            ContainerNotFoundException, PaginationException, ViewMalformedException {
 
         /* test */
         data_generic(CONTAINER_2_ID, DATABASE_2_ID, VIEW_1_ID, DATABASE_2, USER_2_USERNAME, USER_2_PRINCIPAL, DATABASE_2_WRITE_OWN_ACCESS);
@@ -600,7 +600,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
     public void data_privateWriteAll_succeeds() throws UserNotFoundException, NotAllowedException,
             DatabaseNotFoundException, ViewNotFoundException, DatabaseConnectionException, QueryMalformedException,
             QueryStoreException, TableMalformedException, ColumnParseException, ImageNotSupportedException,
-            ContainerNotFoundException, PaginationException {
+            ContainerNotFoundException, PaginationException, ViewMalformedException {
 
         /* test */
         data_generic(CONTAINER_2_ID, DATABASE_2_ID, VIEW_1_ID, DATABASE_2, USER_2_USERNAME, USER_2_PRINCIPAL, DATABASE_2_WRITE_ALL_ACCESS);
@@ -610,7 +610,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
     public void data_privateOwner_succeeds() throws UserNotFoundException, NotAllowedException,
             DatabaseNotFoundException, ViewNotFoundException, DatabaseConnectionException, QueryMalformedException,
             QueryStoreException, TableMalformedException, ColumnParseException, ImageNotSupportedException,
-            ContainerNotFoundException, PaginationException {
+            ContainerNotFoundException, PaginationException, ViewMalformedException {
 
         /* test */
         data_generic(CONTAINER_2_ID, DATABASE_2_ID, VIEW_1_ID, DATABASE_2, USER_1_USERNAME, USER_1_PRINCIPAL, DATABASE_2_WRITE_ALL_ACCESS);
@@ -742,7 +742,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
                                 Principal principal, DatabaseAccess access) throws DatabaseNotFoundException,
             UserNotFoundException, NotAllowedException, ViewNotFoundException, DatabaseConnectionException,
             QueryMalformedException, QueryStoreException, TableMalformedException, ColumnParseException,
-            ImageNotSupportedException, ContainerNotFoundException, PaginationException {
+            ImageNotSupportedException, ContainerNotFoundException, PaginationException, ViewMalformedException {
         final ExecuteStatementDto statement = ExecuteStatementDto.builder()
                 .statement(VIEW_1_QUERY)
                 .build();
@@ -763,7 +763,7 @@ public class ViewEndpointUnitTest extends BaseUnitTest {
         }
         when(viewService.findById(databaseId, viewId, principal))
                 .thenReturn(VIEW_1);
-        when(queryService.execute(containerId, databaseId, statement, principal, page, size, null, null))
+        when(queryService.viewFindAll(containerId, databaseId, VIEW_1, page, size, principal))
                 .thenReturn(QUERY_1_RESULT_DTO);
 
         /* test */
diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueryServiceIntegrationTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueryServiceIntegrationTest.java
index f05d8edb5febe0045b7db356b6f8f3e58bf94154..421304d117fab2be463d6fd752a080d52a7171cb 100644
--- a/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueryServiceIntegrationTest.java
+++ b/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueryServiceIntegrationTest.java
@@ -138,7 +138,7 @@ public class QueryServiceIntegrationTest extends BaseUnitTest {
                 .thenReturn(Optional.of(TABLE_1));
 
         /* test */
-        final QueryResultDto result = queryService.findAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, Instant.now(),
+        final QueryResultDto result = queryService.tableFindAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, Instant.now(),
                 null, null, USER_1_PRINCIPAL);
         assertEquals(3, result.getResult().size());
         assertEquals(BigInteger.valueOf(1L), result.getResult().get(0).get(COLUMN_1_1_INTERNAL_NAME));
@@ -174,7 +174,7 @@ public class QueryServiceIntegrationTest extends BaseUnitTest {
                 .thenReturn(Optional.of(TABLE_1));
 
         /* test */
-        queryService.findAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, Instant.now(), page, size, USER_1_PRINCIPAL);
+        queryService.tableFindAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, Instant.now(), page, size, USER_1_PRINCIPAL);
     }
 
     @Test
@@ -192,7 +192,7 @@ public class QueryServiceIntegrationTest extends BaseUnitTest {
 
         /* test */
         assertThrows(TableNotFoundException.class, () -> {
-            queryService.findAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, Instant.now(), page, size, USER_1_PRINCIPAL);
+            queryService.tableFindAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, Instant.now(), page, size, USER_1_PRINCIPAL);
         });
     }
 
@@ -209,7 +209,7 @@ public class QueryServiceIntegrationTest extends BaseUnitTest {
 
         /* test */
         assertThrows(DatabaseNotFoundException.class, () -> {
-            queryService.findAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, Instant.now(), page, size, USER_1_PRINCIPAL);
+            queryService.tableFindAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, Instant.now(), page, size, USER_1_PRINCIPAL);
         });
     }
 
@@ -287,7 +287,7 @@ public class QueryServiceIntegrationTest extends BaseUnitTest {
                 .thenReturn(Optional.of(TABLE_1));
 
         /* test */
-        queryService.findAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, null, null, null, USER_1_PRINCIPAL);
+        queryService.tableFindAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, null, null, null, USER_1_PRINCIPAL);
     }
 
     @Test
@@ -305,8 +305,8 @@ public class QueryServiceIntegrationTest extends BaseUnitTest {
                 .thenReturn(Optional.of(TABLE_1));
 
         /* test */
-        queryService.findAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, timestamp, null, null, USER_1_PRINCIPAL);
-        queryService.findAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, timestamp, null, null, USER_1_PRINCIPAL);
+        queryService.tableFindAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, timestamp, null, null, USER_1_PRINCIPAL);
+        queryService.tableFindAll(CONTAINER_1_ID, DATABASE_1_ID, TABLE_1_ID, timestamp, null, null, USER_1_PRINCIPAL);
     }
 
     @Test
diff --git a/fda-query-service/services/src/main/java/at/tuwien/mapper/QueryMapper.java b/fda-query-service/services/src/main/java/at/tuwien/mapper/QueryMapper.java
index 6e8d8d5f3577dffb16827161335ae1f2cb82542e..d85aaa7553b825ee12715bc4e8bb2a1176e865e1 100644
--- a/fda-query-service/services/src/main/java/at/tuwien/mapper/QueryMapper.java
+++ b/fda-query-service/services/src/main/java/at/tuwien/mapper/QueryMapper.java
@@ -6,6 +6,7 @@ import at.tuwien.api.database.table.TableCsvDto;
 import at.tuwien.api.database.table.TableCsvUpdateDto;
 import at.tuwien.api.database.table.TableHistoryDto;
 import at.tuwien.entities.database.Database;
+import at.tuwien.entities.database.View;
 import at.tuwien.entities.database.table.columns.TableColumnType;
 import at.tuwien.exception.QueryMalformedException;
 import at.tuwien.exception.QueryStoreException;
@@ -573,8 +574,8 @@ public interface QueryMapper {
         return selection.toString();
     }
 
-    default PreparedStatement tableToRawCountAllQuery(Connection connection, Table table, Instant timestamp)
-            throws ImageNotSupportedException, QueryMalformedException {
+    default String tableToRawCountAllQuery(Table table, Instant timestamp)
+            throws ImageNotSupportedException {
         log.trace("mapping table to raw count query, table={}, timestamp={}", table, timestamp);
         /* check image */
         if (!table.getDatabase().getContainer().getImage().getRepository().equals("mariadb")) {
@@ -585,25 +586,35 @@ public interface QueryMapper {
             log.trace("timestamp is null, setting it to now");
             timestamp = Instant.now();
         }
+        return columnsToRawCountAllQuery(table.getInternalName(), timestamp);
+    }
+
+    default String viewToRawCountAllQuery(View view)
+            throws ImageNotSupportedException {
+        log.trace("mapping table to raw count query, view={}", view);
+        /* check image */
+        if (!view.getDatabase().getContainer().getImage().getRepository().equals("mariadb")) {
+            log.error("Currently only MariaDB is supported");
+            throw new ImageNotSupportedException("Image not supported.");
+        }
+        return columnsToRawCountAllQuery(view.getInternalName(), null);
+    }
+
+    default String columnsToRawCountAllQuery(String tableName, Instant timestamp) {
         final StringBuilder statement = new StringBuilder("SELECT COUNT(*) FROM `")
-                .append(nameToInternalName(table.getName()))
-                .append("` FOR SYSTEM_TIME AS OF TIMESTAMP '")
-                .append(LocalDateTime.ofInstant(timestamp, ZoneId.of("UTC")))
-                .append("';");
-        try {
-            final PreparedStatement pstmt = connection.prepareStatement(statement.toString());
-            log.trace("mapped raw count query {} to prepared statement {}", statement, pstmt);
-            return pstmt;
-        } catch (SQLException e) {
-            log.error("Failed to prepare statement {}, reason: {}", statement, e.getMessage());
-            throw new QueryMalformedException("Failed to prepare statement", e);
+                .append(nameToInternalName(tableName))
+                .append("`");
+        if(timestamp != null) {
+            statement.append(" FOR SYSTEM_TIME AS OF TIMESTAMP '")
+                    .append(LocalDateTime.ofInstant(timestamp, ZoneId.of("UTC")))
+                    .append("'");
         }
+        statement.append(";");
+        return statement.toString();
     }
 
-    default PreparedStatement queryToRawTimestampedQuery(Connection connection, String query, Database database,
-                                                         Instant timestamp, Boolean selection, Long page, Long size)
-            throws ImageNotSupportedException,
-            QueryMalformedException {
+    default String queryToRawTimestampedQuery(String query, Database database, Instant timestamp, Boolean selection, Long page, Long size)
+            throws ImageNotSupportedException, QueryMalformedException {
         log.trace("mapping query to timestamped query, query={}, database={}, timestamp={}, selection={}, page={}, size={}",
                 query, database, timestamp, selection, page, size);
         /* param check */
@@ -673,17 +684,11 @@ public interface QueryMapper {
                     + LocalDateTime.ofInstant(timestamp, ZoneId.of("UTC"))
                     + "' ");
         }
-        try {
-            log.debug("mapped timestamped query: {}", statement);
-            return connection.prepareStatement(statement.toString());
-        } catch (SQLException e) {
-            log.error("Failed to prepare statement {}, reason: {}", statement, e.getMessage());
-            throw new QueryMalformedException("Failed to prepare statement", e);
-        }
+        return statement.toString();
     }
 
-    default PreparedStatement tableToRawFindAllQuery(Connection connection, Table table, Instant timestamp, Long size, Long page)
-            throws ImageNotSupportedException, QueryMalformedException {
+    default String tableToRawFindAllQuery(Table table, Instant timestamp, Long size, Long page)
+            throws ImageNotSupportedException {
         log.trace("mapping table to find all query, table={}, timestamp={}, size={}, page={}",
                 table, timestamp, size, page);
         /* param check */
@@ -697,18 +702,35 @@ public interface QueryMapper {
         } else {
             log.trace("timestamp provided {}", timestamp);
         }
+        return columnsToRawFindAllQuery(table.getInternalName(), table.getColumns(), timestamp, size, page);
+    }
+
+    default String viewToRawFindAllQuery(View view, Long size, Long page)
+            throws ImageNotSupportedException {
+        log.trace("mapping view to find all query, view={}, size={}, page={}", view, size, page);
+        /* param check */
+        if (!view.getDatabase().getContainer().getImage().getRepository().equals("mariadb")) {
+            log.error("Currently only MariaDB is supported");
+            throw new ImageNotSupportedException("Currently only MariaDB is supported");
+        }
+        return columnsToRawFindAllQuery(view.getInternalName(), view.getColumns(), null, size, page);
+    }
+
+    private String columnsToRawFindAllQuery(String tableName, List<TableColumn> columns, Instant timestamp, Long size, Long page) {
         final int[] idx = new int[]{0};
         final StringBuilder statement = new StringBuilder("SELECT ");
-        table.getColumns()
-                .forEach(column -> statement.append(idx[0]++ > 0 ? "," : "")
+        columns.forEach(column -> statement.append(idx[0]++ > 0 ? "," : "")
                         .append("`")
                         .append(column.getInternalName())
                         .append("`"));
         statement.append(" FROM `")
-                .append(nameToInternalName(table.getName()))
-                .append("` FOR SYSTEM_TIME AS OF TIMESTAMP '")
-                .append(LocalDateTime.ofInstant(timestamp, ZoneId.of("UTC")))
-                .append("'");
+                .append(nameToInternalName(tableName))
+                .append("`");
+        if (timestamp != null) {
+            statement.append(" FOR SYSTEM_TIME AS OF TIMESTAMP '")
+                    .append(LocalDateTime.ofInstant(timestamp, ZoneId.of("UTC")))
+                    .append("'");
+        }
         if (size != null && page != null) {
             log.trace("pagination size/limit of {}", size);
             statement.append(" LIMIT ")
@@ -717,34 +739,8 @@ public interface QueryMapper {
             statement.append(" OFFSET ")
                     .append(page * size)
                     .append(";");
-
-        }
-        try {
-            final PreparedStatement pstmt = connection.prepareStatement(statement.toString());
-            log.trace("mapped timestamped query {} to prepared statement {}", statement, pstmt);
-            return pstmt;
-        } catch (SQLException e) {
-            log.error("Failed to prepare statement {}m reason: {}", statement, e.getMessage());
-            throw new QueryMalformedException("Failed to prepare statement", e);
-        }
-    }
-
-    default QueryResultDto queryTableToQueryResultDto(ResultSet result, Table table) throws DateTimeException,
-            SQLException {
-        final List<Map<String, Object>> queryResult = new LinkedList<>();
-        while (result.next()) {
-            /* map the result set to the columns through the stored metadata in the metadata database */
-            int[] idx = new int[]{1};
-            final Map<String, Object> map = new HashMap<>();
-            for (int i = 0; i < table.getColumns().size(); i++) {
-                map.put(table.getColumns().get(i).getInternalName(), dataColumnToObject(result.getObject(idx[0]++), table.getColumns().get(i)));
-            }
-            queryResult.add(map);
         }
-        log.trace("mapped result {} to query result {}", result, queryResult);
-        return QueryResultDto.builder()
-                .result(queryResult)
-                .build();
+        return statement.toString();
     }
 
     @Transactional(readOnly = true)
diff --git a/fda-query-service/services/src/main/java/at/tuwien/service/QueryService.java b/fda-query-service/services/src/main/java/at/tuwien/service/QueryService.java
index 119d887f3cce8a770db719496c51099d9227d3f3..01924d9fb29b8729987e5621bd6d4a4006cfa04d 100644
--- a/fda-query-service/services/src/main/java/at/tuwien/service/QueryService.java
+++ b/fda-query-service/services/src/main/java/at/tuwien/service/QueryService.java
@@ -5,16 +5,20 @@ import at.tuwien.SortType;
 import at.tuwien.api.database.query.ExecuteStatementDto;
 import at.tuwien.api.database.query.ImportDto;
 import at.tuwien.api.database.query.QueryResultDto;
-import at.tuwien.api.database.query.QueryTypeDto;
 import at.tuwien.api.database.table.TableCsvDeleteDto;
 import at.tuwien.api.database.table.TableCsvDto;
 import at.tuwien.api.database.table.TableCsvUpdateDto;
+import at.tuwien.entities.database.Database;
+import at.tuwien.entities.database.View;
+import at.tuwien.entities.database.table.columns.TableColumn;
 import at.tuwien.exception.*;
 import at.tuwien.querystore.Query;
+import net.sf.jsqlparser.JSQLParserException;
 import org.springframework.stereotype.Service;
 
 import java.security.Principal;
 import java.time.Instant;
+import java.util.List;
 
 @Service
 public interface QueryService {
@@ -71,6 +75,26 @@ public interface QueryService {
             throws QueryMalformedException, DatabaseNotFoundException, ImageNotSupportedException, ColumnParseException,
             DatabaseConnectionException, TableMalformedException, QueryStoreException, UserNotFoundException;
 
+    /**
+     * Re-Executes the count-statement of an arbitrary query on the database container. We allow the user to only view
+     * the data, therefore the default "mariadb" user is allowed read-only access "SELECT".
+     *
+     * @param containerId   The container id.
+     * @param databaseId    The database id.
+     * @param query         The query.
+     * @param principal     The user principal.
+     * @return The result.
+     * @throws QueryStoreException        The query store is not reachable.
+     * @throws QueryMalformedException    The query is malformed.
+     * @throws DatabaseNotFoundException  The database was not found in the metdata database.
+     * @throws ImageNotSupportedException The image is not supported.
+     * @throws TableMalformedException    The table is malformed.
+     * @throws ColumnParseException       The column mapping/parsing failed.
+     */
+    Long reExecuteCount(Long containerId, Long databaseId, Query query, Principal principal)
+            throws QueryMalformedException, DatabaseNotFoundException, ImageNotSupportedException, ColumnParseException,
+            TableMalformedException, QueryStoreException;
+
     /**
      * Select all data known in the database-table id tuple at a given time and return a page of specific size, using
      * Instant to better abstract time concept (JDK 8) from SQL. We use the "mariadb" user for this.
@@ -90,8 +114,8 @@ public interface QueryService {
      * @throws TableMalformedException    The table is malformed.
      * @throws QueryMalformedException    The query is malformed.
      */
-    QueryResultDto findAll(Long containerId, Long databaseId, Long tableId, Instant timestamp,
-                           Long page, Long size, Principal principal) throws TableNotFoundException, DatabaseNotFoundException,
+    QueryResultDto tableFindAll(Long containerId, Long databaseId, Long tableId, Instant timestamp,
+                                Long page, Long size, Principal principal) throws TableNotFoundException, DatabaseNotFoundException,
             ImageNotSupportedException, DatabaseConnectionException, TableMalformedException, PaginationException,
             ContainerNotFoundException, QueryMalformedException, UserNotFoundException;
 
@@ -115,11 +139,34 @@ public interface QueryService {
      * @throws FileStorageException        The file could not be exported.
      * @throws QueryMalformedException     The query is malformed.
      */
-    ExportResource findAll(Long containerId, Long databaseId, Long tableId, Instant timestamp, Principal principal)
+    ExportResource tableFindAll(Long containerId, Long databaseId, Long tableId, Instant timestamp, Principal principal)
             throws TableNotFoundException, DatabaseNotFoundException, ImageNotSupportedException,
             DatabaseConnectionException, TableMalformedException, PaginationException, ContainerNotFoundException,
             FileStorageException, QueryMalformedException, UserNotFoundException;
 
+    /**
+     * Select all data known in the view id tuple and return a page of specific size.
+     * We use the "mariadb" user for this.
+     *
+     * @param containerId The container-database id pair.
+     * @param databaseId  The container-database id pair.
+     * @param view        The view.
+     * @param page        The page.
+     * @param size        The page size.
+     * @param principal   The user principal.
+     * @return The select all data result
+     * @throws ViewNotFoundException     The view was not found in the metadata database.
+     * @throws DatabaseNotFoundException  The database was not found in the metdata database.
+     * @throws ImageNotSupportedException The image is not supported.
+     * @throws ContainerNotFoundException The container was not found in the metadata database.
+     * @throws ViewMalformedException    The table is malformed.
+     * @throws QueryMalformedException    The query is malformed.
+     */
+    QueryResultDto viewFindAll(Long containerId, Long databaseId, View view,
+                               Long page, Long size, Principal principal) throws ViewNotFoundException, DatabaseNotFoundException,
+            ImageNotSupportedException, DatabaseConnectionException, ViewMalformedException, PaginationException,
+            ContainerNotFoundException, QueryMalformedException, UserNotFoundException, TableMalformedException;
+
     /**
      * Finds one query by container-database-query triple.
      *
@@ -156,10 +203,27 @@ public interface QueryService {
      * @throws TableMalformedException    The table columns are messed up what we got from the metadata database.
      * @throws ImageNotSupportedException The image is not supported.
      */
-    Long count(Long containerId, Long databaseId, Long tableId, Instant timestamp, Principal principal)
+    Long tableCount(Long containerId, Long databaseId, Long tableId, Instant timestamp, Principal principal)
             throws ContainerNotFoundException, DatabaseNotFoundException, TableNotFoundException,
             TableMalformedException, ImageNotSupportedException, DatabaseConnectionException, QueryMalformedException, QueryStoreException, UserNotFoundException;
 
+    /**
+     * Count the total tuples for a given table id within a container-database id tuple at a given time.
+     *
+     * @param containerId The container id.
+     * @param databaseId  The database id.
+     * @param view        The view.
+     * @param principal   The user principal.
+     * @return The number of records, if successful
+     * @throws ContainerNotFoundException The container was not found in the metadata database.
+     * @throws DatabaseNotFoundException  The database was not found in the remote database.
+     * @throws TableMalformedException    The view columns are messed up what we got from the metadata database.
+     * @throws ImageNotSupportedException The image is not supported.
+     */
+    Long viewCount(Long containerId, Long databaseId, View view, Principal principal)
+            throws ContainerNotFoundException, DatabaseNotFoundException,
+            TableMalformedException, ImageNotSupportedException, DatabaseConnectionException, QueryMalformedException, QueryStoreException, UserNotFoundException;
+
     /**
      * @param containerId The container id.
      * @param databaseId  The database id.
@@ -232,4 +296,14 @@ public interface QueryService {
      */
     void insert(Long containerId, Long databaseId, Long tableId, ImportDto data, Principal principal) throws ImageNotSupportedException,
             TableMalformedException, DatabaseNotFoundException, TableNotFoundException, ContainerNotFoundException, DatabaseConnectionException, QueryMalformedException, UserNotFoundException;
+
+    /**
+     * Parses the stored columns from a given query.
+     *
+     * @param query    The query.
+     * @param database The database that contains the list of tables with list of columns.
+     * @return List of columns in the order they are referenced in the query.
+     * @throws JSQLParserException The columns could not be extracted from the query.
+     */
+    List<TableColumn> parseColumns(String query, Database database) throws JSQLParserException;
 }
diff --git a/fda-query-service/services/src/main/java/at/tuwien/service/impl/QueryServiceImpl.java b/fda-query-service/services/src/main/java/at/tuwien/service/impl/QueryServiceImpl.java
index 2605fb75ff5333b63fb8c898975b7d23225ff960..a1dc0a91b336c9f1f8485ec7a167a6477487291e 100644
--- a/fda-query-service/services/src/main/java/at/tuwien/service/impl/QueryServiceImpl.java
+++ b/fda-query-service/services/src/main/java/at/tuwien/service/impl/QueryServiceImpl.java
@@ -39,7 +39,6 @@ import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
-import java.time.DateTimeException;
 import java.time.Instant;
 import java.time.format.DateTimeParseException;
 import java.util.ArrayList;
@@ -104,61 +103,147 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService
             log.error("Failed to map/parse columns: {}", e.getMessage());
             throw new ColumnParseException("Failed to map/parse columns: " + e.getMessage(), e);
         }
-        final QueryResultDto dto;
+        final String statement = queryMapper.queryToRawTimestampedQuery(query.getQuery(), database, query.getCreated(), true, page, size);
+        final QueryResultDto dto = executeNonPersistent(containerId, databaseId, statement, columns);
+
+        dto.setId(query.getId());
+        dto.setResultNumber(query.getResultNumber());
+        return dto;
+    }
+
+    @Override
+    @Transactional(readOnly = true)
+    public Long reExecuteCount(Long containerId, Long databaseId, Query query, Principal principal)
+            throws QueryMalformedException, DatabaseNotFoundException, ImageNotSupportedException, ColumnParseException,
+            TableMalformedException, QueryStoreException {
+        /* find */
+        final Database database = databaseService.find(containerId, databaseId);
+        if (!database.getContainer().getImage().getRepository().equals("mariadb")) {
+            throw new ImageNotSupportedException("Currently only MariaDB is supported");
+        }
+        /* run query */
+        try {
+            parseColumns(query.getQuery(), database);
+        } catch (JSQLParserException e) {
+            log.error("Failed to map/parse columns: {}", e.getMessage());
+            throw new ColumnParseException("Failed to map/parse columns: " + e.getMessage(), e);
+        }
+        final String statement = queryMapper.queryToRawTimestampedQuery(query.getQuery(), database, query.getCreated(), false, null, null);
+        return executeCountNonPersistent(containerId, databaseId, statement);
+    }
+
+    private PreparedStatement prepareStatement(Connection connection, String statement) throws QueryMalformedException {
+        try {
+            final PreparedStatement pstmt = connection.prepareStatement(statement);
+            log.trace("mapped timestamped query {} to prepared statement {}", statement, pstmt);
+            return pstmt;
+        } catch (SQLException e) {
+            log.error("Failed to prepare statement {}m reason: {}", statement, e.getMessage());
+            throw new QueryMalformedException("Failed to prepare statement", e);
+        }
+    }
+
+    private QueryResultDto executeNonPersistent(Long containerId, Long databaseId, String statement, List<TableColumn> columns)
+            throws QueryMalformedException, DatabaseNotFoundException, TableMalformedException {
+        /* find */
+        final Database database = databaseService.find(containerId, databaseId);
+        final User root = databaseMapper.containerToPrivilegedUser(database.getContainer());
+        /* run query */
+        final ComboPooledDataSource dataSource = getDataSource(database.getContainer().getImage(),
+                database.getContainer(), database, root);
         try {
             final Connection connection = dataSource.getConnection();
-            final PreparedStatement preparedStatement = queryMapper.queryToRawTimestampedQuery(connection, query.getQuery(),
-                    database, query.getCreated(), true, page, size);
+            final PreparedStatement preparedStatement = prepareStatement(connection, statement);
             final ResultSet resultSet = preparedStatement.executeQuery();
-            dto = queryMapper.resultListToQueryResultDto(columns, resultSet);
+            return queryMapper.resultListToQueryResultDto(columns, resultSet);
         } catch (SQLException e) {
             log.error("Failed to execute and map time-versioned query: {}", e.getMessage());
             throw new TableMalformedException("Failed to execute and map time-versioned query: " + e.getMessage(), e);
         } finally {
             dataSource.close();
         }
-        dto.setId(query.getId());
-        dto.setResultNumber(query.getResultNumber());
-        return dto;
     }
 
-    @Override
-    @Transactional(readOnly = true)
-    public QueryResultDto findAll(Long containerId, Long databaseId, Long tableId, Instant timestamp, Long page,
-                                  Long size, Principal principal) throws TableNotFoundException, DatabaseNotFoundException,
-            ImageNotSupportedException, DatabaseConnectionException, TableMalformedException, PaginationException,
-            ContainerNotFoundException, QueryMalformedException, UserNotFoundException {
+    private Long executeCountNonPersistent(Long containerId, Long databaseId, String statement)
+            throws QueryMalformedException, TableMalformedException, DatabaseNotFoundException, QueryStoreException {
         /* find */
         final Database database = databaseService.find(containerId, databaseId);
-        final Table table = tableService.find(containerId, databaseId, tableId);
         final User root = databaseMapper.containerToPrivilegedUser(database.getContainer());
         /* run query */
         final ComboPooledDataSource dataSource = getDataSource(database.getContainer().getImage(),
                 database.getContainer(), database, root);
-        final QueryResultDto result;
         try {
             final Connection connection = dataSource.getConnection();
-            final PreparedStatement preparedStatement = queryMapper.tableToRawFindAllQuery(connection, table, timestamp, size, page);
+            final PreparedStatement preparedStatement = prepareStatement(connection, statement);
             final ResultSet resultSet = preparedStatement.executeQuery();
-            result = queryMapper.queryTableToQueryResultDto(resultSet, table);
-        } catch (DateTimeException e) {
-            log.error("Failed to parse date from the one stored in the metadata database: {}", e.getMessage());
-            throw new TableMalformedException("Could not parse date from format: " + e.getMessage(), e);
+            return queryMapper.resultSetToNumber(resultSet);
         } catch (SQLException e) {
             log.error("Failed to map object: {}", e.getMessage());
             throw new TableMalformedException("Failed to map object: " + e.getMessage(), e);
         } finally {
             dataSource.close();
         }
-        return result;
     }
 
     @Override
     @Transactional(readOnly = true)
-    public ExportResource findAll(Long containerId, Long databaseId, Long tableId, Instant timestamp, Principal principal)
-            throws TableNotFoundException, DatabaseNotFoundException, ImageNotSupportedException,
-            DatabaseConnectionException, TableMalformedException, PaginationException, ContainerNotFoundException,
-            FileStorageException, QueryMalformedException, UserNotFoundException {
+    public QueryResultDto tableFindAll(Long containerId, Long databaseId, Long tableId, Instant timestamp, Long page,
+                                       Long size, Principal principal) throws TableNotFoundException, DatabaseNotFoundException,
+            ImageNotSupportedException, TableMalformedException, QueryMalformedException {
+        /* find */
+        final Table table = tableService.find(containerId, databaseId, tableId);
+        /* run query */
+        String statement = queryMapper.tableToRawFindAllQuery(table, timestamp, size, page);
+        return executeNonPersistent(containerId, databaseId, statement, table.getColumns());
+    }
+
+    @Override
+    @Transactional(readOnly = true)
+    public QueryResultDto viewFindAll(Long containerId, Long databaseId, View view,
+                                      Long page, Long size, Principal principal) throws DatabaseNotFoundException,
+            ImageNotSupportedException, QueryMalformedException, TableMalformedException {
+        /* find */
+        /* run query */
+        String statement = queryMapper.viewToRawFindAllQuery(view, size, page);
+        return executeNonPersistent(containerId, databaseId, statement, view.getColumns());
+    }
+
+    @Override
+    @Transactional
+    public Long tableCount(Long containerId, Long databaseId, Long tableId, Instant timestamp, Principal principal)
+            throws DatabaseNotFoundException, TableNotFoundException, ImageNotSupportedException,
+            QueryMalformedException, QueryStoreException, TableMalformedException {
+        /* find */
+        final Table table = tableService.find(containerId, databaseId, tableId);
+        final String statement = queryMapper.tableToRawCountAllQuery(table, timestamp);
+        return executeCountNonPersistent(containerId, databaseId, statement);
+    }
+
+    @Override
+    @Transactional
+    public Long viewCount(Long containerId, Long databaseId, View view, Principal principal)
+            throws DatabaseNotFoundException, ImageNotSupportedException,
+            QueryMalformedException, QueryStoreException, TableMalformedException {
+        /* find */
+        final String statement = queryMapper.viewToRawCountAllQuery(view);
+        return executeCountNonPersistent(containerId, databaseId, statement);
+    }
+
+    @Transactional(readOnly = true)
+    public QueryResultDto findAllView(Long containerId, Long databaseId, Long viewId, Instant timestamp, Long page,
+                                      Long size, Principal principal) throws TableNotFoundException, DatabaseNotFoundException,
+            ImageNotSupportedException, TableMalformedException, QueryMalformedException {
+        /* find */
+        final Table table = tableService.find(containerId, databaseId, viewId);
+        /* run query */
+        String statement = queryMapper.tableToRawFindAllQuery(table, timestamp, size, page);
+        return executeNonPersistent(containerId, databaseId, statement, table.getColumns());
+    }
+
+    @Override
+    @Transactional(readOnly = true)
+    public ExportResource tableFindAll(Long containerId, Long databaseId, Long tableId, Instant timestamp, Principal principal)
+            throws TableNotFoundException, DatabaseNotFoundException, FileStorageException, QueryMalformedException {
         final String filename = RandomStringUtils.randomAlphabetic(40) + ".csv";
         /* find */
         final Database database = databaseService.find(containerId, databaseId);
@@ -227,36 +312,11 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService
                 .build();
     }
 
-    @Override
-    @Transactional
-    public Long count(Long containerId, Long databaseId, Long tableId, Instant timestamp, Principal principal)
-            throws DatabaseNotFoundException, TableNotFoundException, ImageNotSupportedException,
-            QueryMalformedException, QueryStoreException, TableMalformedException {
-        /* find */
-        final Database database = databaseService.find(containerId, databaseId);
-        final Table table = tableService.find(containerId, databaseId, tableId);
-        final User root = databaseMapper.containerToPrivilegedUser(database.getContainer());
-        /* run query */
-        final ComboPooledDataSource dataSource = getDataSource(database.getContainer().getImage(),
-                database.getContainer(), database, root);
-        try {
-            final Connection connection = dataSource.getConnection();
-            final PreparedStatement preparedStatement = queryMapper.tableToRawCountAllQuery(connection, table, timestamp);
-            final ResultSet resultSet = preparedStatement.executeQuery();
-            return queryMapper.resultSetToNumber(resultSet);
-        } catch (SQLException e) {
-            log.error("Failed to count raw tuples: {}", e.getMessage());
-            throw new TableMalformedException("Failed to count raw tuples: " + e.getMessage(), e);
-        } finally {
-            dataSource.close();
-        }
-    }
-
     @Override
     @Transactional
     public void update(Long containerId, Long databaseId, Long tableId, TableCsvUpdateDto data, Principal principal)
             throws ImageNotSupportedException, TableMalformedException, DatabaseNotFoundException,
-            TableNotFoundException, QueryMalformedException, UserNotFoundException {
+            TableNotFoundException, QueryMalformedException {
         /* find */
         final Database database = databaseService.find(containerId, databaseId);
         final Table table = tableService.find(containerId, databaseId, tableId);
@@ -395,7 +455,7 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService
      * @throws JSQLParserException The columns could not be extracted from the query.
      */
     @Transactional(readOnly = true)
-    protected List<TableColumn> parseColumns(String query, Database database) throws JSQLParserException {
+    public List<TableColumn> parseColumns(String query, Database database) throws JSQLParserException {
         final List<TableColumn> columns = new ArrayList<>();
         final CCJSqlParserManager parserRealSql = new CCJSqlParserManager();
         final Statement statement = parserRealSql.parse(new StringReader(query));
diff --git a/fda-query-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java b/fda-query-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java
index 830cc6d216c6ded0d7ba54cc1a2eec61203549e5..4a8e6b8408642cfefe968c1c4fc341fc6de5469b 100644
--- a/fda-query-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java
+++ b/fda-query-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java
@@ -3,6 +3,7 @@ package at.tuwien.service.impl;
 import at.tuwien.api.database.ViewCreateDto;
 import at.tuwien.entities.database.Database;
 import at.tuwien.entities.database.View;
+import at.tuwien.entities.database.table.columns.TableColumn;
 import at.tuwien.entities.user.User;
 import at.tuwien.exception.*;
 import at.tuwien.mapper.DatabaseMapper;
@@ -10,10 +11,12 @@ import at.tuwien.mapper.ViewMapper;
 import at.tuwien.repository.elastic.ViewIdxRepository;
 import at.tuwien.repository.jpa.ViewRepository;
 import at.tuwien.service.DatabaseService;
+import at.tuwien.service.QueryService;
 import at.tuwien.service.UserService;
 import at.tuwien.service.ViewService;
 import com.mchange.v2.c3p0.ComboPooledDataSource;
 import lombok.extern.log4j.Log4j2;
+import net.sf.jsqlparser.JSQLParserException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -35,17 +38,19 @@ public class ViewServiceImpl extends HibernateConnector implements ViewService {
     private final ViewRepository viewRepository;
     private final DatabaseService databaseService;
     private final ViewIdxRepository viewIdxRepository;
+    private final QueryService queryService;
 
     @Autowired
     public ViewServiceImpl(ViewMapper viewMapper, UserService userService, DatabaseMapper databaseMapper,
                            ViewRepository viewRepository, DatabaseService databaseService,
-                           ViewIdxRepository viewIdxRepository) {
+                           ViewIdxRepository viewIdxRepository, QueryService queryService) {
         this.viewMapper = viewMapper;
         this.userService = userService;
         this.databaseMapper = databaseMapper;
         this.viewRepository = viewRepository;
         this.databaseService = databaseService;
         this.viewIdxRepository = viewIdxRepository;
+        this.queryService = queryService;
     }
 
     @Override
@@ -118,6 +123,13 @@ public class ViewServiceImpl extends HibernateConnector implements ViewService {
         /* create view */
         final ComboPooledDataSource dataSource = getDataSource(database.getContainer().getImage(),
                 database.getContainer(), database, root);
+        final List<TableColumn> columns;
+        try {
+            columns = queryService.parseColumns(data.getQuery(), database);
+        } catch (JSQLParserException e) {
+            log.error("Failed to map/parse columns: {}", e.getMessage());
+            throw new QueryMalformedException(e.getMessage(), e);
+        }
         try {
             final Connection connection = dataSource.getConnection();
             final PreparedStatement createViewStatement = viewMapper.viewCreateDtoToRawCreateViewQuery(connection, data);
@@ -139,6 +151,7 @@ public class ViewServiceImpl extends HibernateConnector implements ViewService {
                 .query(data.getQuery())
                 .isInitialView(false)
                 .isPublic(data.getIsPublic())
+                .columns(columns)
                 .build();
         final View view = viewRepository.save(entity);
         log.info("Created view with id {}", view.getId());
diff --git a/fda-ui/components/DatabaseList.vue b/fda-ui/components/DatabaseList.vue
index 98e4051b639e52addcb3cb08f77cde0b1868b491..2f85f6a72ed63ff7c776abf354e839b5fc4198c9 100644
--- a/fda-ui/components/DatabaseList.vue
+++ b/fda-ui/components/DatabaseList.vue
@@ -37,6 +37,7 @@
           Start
         </v-btn>
       </v-card-text>
+      <v-divider v-if="idx - 1 === databases.length" class="mx-4" />
     </v-card>
     <v-toolbar v-if="false" flat>
       <v-toolbar-title>
diff --git a/fda-ui/components/query/Builder.vue b/fda-ui/components/query/Builder.vue
index b055f9daa53118c4d738f8154499a66d33848fc7..311aac14f2dce772d544e29c11b558dab57e9e9e 100644
--- a/fda-ui/components/query/Builder.vue
+++ b/fda-ui/components/query/Builder.vue
@@ -330,7 +330,7 @@ export default {
         this.$toast.error(err.response.data.message)
       }
       this.loadingQuery = false
-      await this.$refs.queryResults.reExecute(this.resultId)
+      await Promise.all([this.$refs.queryResults.reExecute(this.resultId), this.$refs.queryResults.reExecuteCount(this.resultId)])
     },
     async buildQuery () {
       if (!this.table) {
diff --git a/fda-ui/components/query/Results.vue b/fda-ui/components/query/Results.vue
index 4d52923b58edcb2e02d63c055ee77dea183b5195..d04b59378614effed3b3a6595bbb912f13c164bc 100644
--- a/fda-ui/components/query/Results.vue
+++ b/fda-ui/components/query/Results.vue
@@ -3,7 +3,7 @@
     flat
     :headers="result.headers"
     :items="result.rows"
-    :loading="loading"
+    :loading="loading > 0"
     :options.sync="options"
     :server-items-length="total" />
 </template>
@@ -18,7 +18,7 @@ export default {
   },
   data () {
     return {
-      loading: false,
+      loading: 0,
       resultId: null,
       id: null,
       result: {
@@ -29,7 +29,7 @@ export default {
         page: 1,
         itemsPerPage: 10
       },
-      total: 0
+      total: -1
     }
   },
   computed: {
@@ -60,7 +60,7 @@ export default {
   },
   methods: {
     async executeFirstTime (parent, sql, timestamp) {
-      this.loading = true
+      this.loading++
       try {
         const res = await this.$axios.post(this.executeUrl, { statement: sql, timestamp }, this.config)
         console.debug('query result', res.data)
@@ -80,7 +80,7 @@ export default {
         }
         this.error = true
       }
-      this.loading = false
+      this.loading--
     },
     buildHeaders (firstLine) {
       return Object.keys(firstLine).map(k => ({
@@ -92,13 +92,16 @@ export default {
     reExecuteUrl (resultId) {
       const page = this.options.page - 1
       const urlParams = `page=${page}&size=${this.options.itemsPerPage}`
-      return `/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}` + (this.type === 'view' ? '/view' : '/query') + `/${resultId}/data?${urlParams}`
+      return `/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/${this.type}/${resultId}/data?${urlParams}`
+    },
+    reExecuteCountUrl (resultId) {
+      return `/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/${this.type}/${resultId}/data/count`
     },
     async reExecute (id) {
       if (id === null) {
         return
       }
-      this.loading = true
+      this.loading++
       try {
         const res = await this.$axios.get(this.reExecuteUrl(id), this.config)
         this.mapResults(res.data)
@@ -107,7 +110,21 @@ export default {
         console.error('failed to execute query', error)
         this.error = true
       }
-      this.loading = false
+      this.loading--
+    },
+    async reExecuteCount (id) {
+      if (id === null) {
+        return
+      }
+      this.loading++
+      try {
+        const res = await this.$axios.get(this.reExecuteCountUrl(id), this.config)
+        this.total = res.data
+      } catch (error) {
+        console.error('failed to execute query count', error)
+        this.error = true
+      }
+      this.loading--
     },
     mapResults (data) {
       if (data.result.length) {
@@ -115,7 +132,9 @@ export default {
       }
       console.debug('query result', data)
       this.result.rows = data.result
-      this.total = data.result_number
+      if (this.total < 0 && data.result_number != null) {
+        this.total = data.result_number
+      }
     }
   }
 }
diff --git a/fda-ui/pages/container/_container_id/database/_database_id/query/_query_id/index.vue b/fda-ui/pages/container/_container_id/database/_database_id/query/_query_id/index.vue
index 4a42f9d4a898e3a7cb5c332c8a11860b2a009ba2..4ca589d1527db7c2bd3eea1a845348c3f3d2d9c9 100644
--- a/fda-ui/pages/container/_container_id/database/_database_id/query/_query_id/index.vue
+++ b/fda-ui/pages/container/_container_id/database/_database_id/query/_query_id/index.vue
@@ -370,6 +370,7 @@ export default {
   methods: {
     loadResult () {
       this.$refs.queryResults.reExecute(this.query.id)
+      this.$refs.queryResults.reExecuteCount(this.query.id)
     },
     async download (mime) {
       if (mime === 'text/csv') {
diff --git a/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/data.vue b/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/data.vue
index 69931d8038a2052ab5548c6c51027429a176c154..17f58d3b1ed4fea81a5bb3f5aee217b26b2df852 100644
--- a/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/data.vue
+++ b/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/data.vue
@@ -23,7 +23,7 @@
       </v-toolbar-title>
     </v-toolbar>
     <v-card tile>
-      <v-progress-linear v-if="loadingData || error" :value="loadProgress" :color="error ? 'error' : 'primary'" />
+      <v-progress-linear v-if="loadingData > 0 || error" :value="loadProgress" :color="error ? 'error' : 'primary'" />
       <v-data-table
         :headers="headers"
         :items="rows"
@@ -51,10 +51,10 @@ export default {
   data () {
     return {
       loading: true,
-      loadingData: true,
+      loadingData: 0,
       loadProgress: 0,
       editTupleDialog: false,
-      total: 0,
+      total: -1,
       footerProps: {
         'items-per-page-options': [10, 20, 30, 40, 50]
       },
@@ -64,6 +64,7 @@ export default {
       selection: [],
       pickVersionDialog: null,
       version: null,
+      lastReload: new Date(),
       tab: null,
       error: false, // XXX: `error` is never changed
       options: {
@@ -165,7 +166,7 @@ export default {
   watch: {
     version (newVersion, oldVersion) {
       console.info('selected new version', newVersion)
-      this.loadData()
+      this.reload()
     },
     options () {
       this.loadData()
@@ -177,7 +178,7 @@ export default {
     }
   },
   mounted () {
-    this.loadData()
+    this.reload()
     this.simulateProgress()
     this.loadProperties()
   },
@@ -254,19 +255,22 @@ export default {
         this.selection = []
       }
       if (success) {
-        this.loadData()
+        this.reload()
       }
     },
+    reload () {
+      this.lastReload = new Date()
+      this.loadData()
+      this.loadCount()
+    },
     async loadData () {
       try {
-        this.loadingData = true
-        let url = `/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/table/${this.$route.params.table_id}/data?page=${this.options.page - 1}&size=${this.options.itemsPerPage}`
+        this.loadingData++
+        const url = `/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/table/${this.$route.params.table_id}/data?page=${this.options.page - 1}&size=${this.options.itemsPerPage}&timestamp=${this.versionISO || this.lastReload.toISOString()}`
         if (this.version !== null) {
           console.info('versioning active', this.version)
-          url += `&timestamp=${this.versionISO}`
         }
         const res = await this.$axios.get(url, this.config)
-        this.total = parseInt(res.headers['fda-count'])
         this.rows = res.data.result.map((row) => {
           for (const col in row) {
             const columnDefinition = this.dateColumns.filter(c => c.internal_name === col)
@@ -294,8 +298,36 @@ export default {
           console.error('Failed to load data', code)
           this.$toast.error('Failed to load data: ' + message)
         }
+      } finally {
+        this.loadingData--
+      }
+    },
+    async loadCount () {
+      try {
+        this.loadingData++
+        const url = `/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/table/${this.$route.params.table_id}/data/count?timestamp=${this.versionISO || this.lastReload.toISOString()}`
+        if (this.version !== null) {
+          console.info('versioning active', this.version)
+        }
+        const res = await this.$axios.get(url, this.config)
+        this.total = res.data
+        console.info('total', this.total)
+      } catch (error) {
+        console.error('Failed to load count', error)
+        this.error = true
+        this.loadProgress = 100
+        const { status, data } = error.response
+        const { message, code } = data
+        if (status === 423) {
+          console.error('Database is offline', code)
+          this.$toast.error('Database is offline: ' + message)
+        } else {
+          console.error('Failed to load data', code)
+          this.$toast.error('Failed to load data: ' + message)
+        }
+      } finally {
+        this.loadingData--
       }
-      this.loadingData = false
     },
     simulateProgress () {
       if (this.loadProgress !== 0) {
diff --git a/fda-ui/pages/container/_container_id/database/_database_id/view/_view_id/index.vue b/fda-ui/pages/container/_container_id/database/_database_id/view/_view_id/index.vue
index 4d9df5a1e7658661fccfd4d2ffea501b54c0fdec..55930ae93e6856d48598213f02e4ded25c69ba24 100644
--- a/fda-ui/pages/container/_container_id/database/_database_id/view/_view_id/index.vue
+++ b/fda-ui/pages/container/_container_id/database/_database_id/view/_view_id/index.vue
@@ -191,6 +191,7 @@ export default {
         return
       }
       this.$refs.queryResults.reExecute(viewId)
+      this.$refs.queryResults.reExecuteCount(viewId)
     },
     formatUTC (timestamp) {
       return formatTimestampUTCLabel(timestamp)