diff --git a/lib/private/db/querybuilder/querybuilder.php b/lib/private/db/querybuilder/querybuilder.php
index 02d8ee4344de5a81b4d770180058e1e2e8ca9c42..741da4efc27cf368469994991db21f7c629653a9 100644
--- a/lib/private/db/querybuilder/querybuilder.php
+++ b/lib/private/db/querybuilder/querybuilder.php
@@ -324,6 +324,28 @@ class QueryBuilder implements IQueryBuilder {
 		return $this;
 	}
 
+	/**
+	 * Specifies an item that is to be returned uniquely in the query result.
+	 *
+	 * <code>
+	 *     $qb = $conn->getQueryBuilder()
+	 *         ->selectDistinct('type')
+	 *         ->from('users');
+	 * </code>
+	 *
+	 * @param mixed $select The selection expressions.
+	 *
+	 * @return \OCP\DB\QueryBuilder\IQueryBuilder This QueryBuilder instance.
+	 */
+	public function selectDistinct($select) {
+
+		$this->queryBuilder->addSelect(
+			'DISTINCT ' . $this->helper->quoteColumnName($select)
+		);
+
+		return $this;
+	}
+
 	/**
 	 * Adds an item that is to be returned in the query result.
 	 *
@@ -1024,14 +1046,46 @@ class QueryBuilder implements IQueryBuilder {
 	}
 
 	/**
+	 * Used to get the id of the last inserted element
+	 * @return int
+	 * @throws \BadMethodCallException When being called before an insert query has been run.
+	 */
+	public function getLastInsertId() {
+		$from = $this->getQueryPart('from');
+
+		if ($this->getType() === \Doctrine\DBAL\Query\QueryBuilder::INSERT && !empty($from)) {
+			return (int) $this->connection->lastInsertId($from['table']);
+		}
+
+		throw new \BadMethodCallException('Invalid call to getLastInsertId without using insert() before.');
+	}
+
+	/**
+	 * Returns the table name quoted and with database prefix as needed by the implementation
+	 *
 	 * @param string $table
 	 * @return string
 	 */
-	private function getTableName($table) {
+	public function getTableName($table) {
 		if ($this->automaticTablePrefix === false || strpos($table, '*PREFIX*') === 0) {
 			return $this->helper->quoteColumnName($table);
 		}
 
 		return $this->helper->quoteColumnName('*PREFIX*' . $table);
 	}
+
+	/**
+	 * Returns the column name quoted and with table alias prefix as needed by the implementation
+	 *
+	 * @param string $column
+	 * @param string $tableAlias
+	 * @return string
+	 */
+	public function getColumnName($column, $tableAlias = '') {
+		if ($tableAlias !== '') {
+			$tableAlias .= '.';
+		}
+
+		return $this->helper->quoteColumnName($tableAlias . $column);
+	}
 }
diff --git a/lib/private/db/querybuilder/quotehelper.php b/lib/private/db/querybuilder/quotehelper.php
index 4b62fee6a6c57863ec155f2b966e2178b8ad0bab..5ceb76bbf931c36c2fed76d5127a4cb3fec7bd2c 100644
--- a/lib/private/db/querybuilder/quotehelper.php
+++ b/lib/private/db/querybuilder/quotehelper.php
@@ -61,7 +61,7 @@ class QuoteHelper {
 		}
 
 		if (substr_count($string, '.')) {
-			list($alias, $columnName) = explode('.', $string);
+			list($alias, $columnName) = explode('.', $string, 2);
 
 			if ($columnName === '*') {
 				return $string;
diff --git a/lib/public/db/querybuilder/iquerybuilder.php b/lib/public/db/querybuilder/iquerybuilder.php
index beb922b7feb10fa9d2488306d7a3e18568f08085..dd3ee7da5f5159600b735a2921a49bdb0c81f371 100644
--- a/lib/public/db/querybuilder/iquerybuilder.php
+++ b/lib/public/db/querybuilder/iquerybuilder.php
@@ -256,6 +256,22 @@ interface IQueryBuilder {
 	 */
 	public function selectAlias($select, $alias);
 
+	/**
+	 * Specifies an item that is to be returned uniquely in the query result.
+	 *
+	 * <code>
+	 *     $qb = $conn->getQueryBuilder()
+	 *         ->selectDistinct('type')
+	 *         ->from('users');
+	 * </code>
+	 *
+	 * @param mixed $select The selection expressions.
+	 *
+	 * @return \OCP\DB\QueryBuilder\IQueryBuilder This QueryBuilder instance.
+	 * @since 9.0.0
+	 */
+	public function selectDistinct($select);
+
 	/**
 	 * Adds an item that is to be returned in the query result.
 	 *
@@ -796,4 +812,31 @@ interface IQueryBuilder {
 	 * @since 8.2.0
 	 */
 	public function createFunction($call);
+
+	/**
+	 * Used to get the id of the last inserted element
+	 * @return int
+	 * @throws \BadMethodCallException When being called before an insert query has been run.
+	 * @since 9.0.0
+	 */
+	public function getLastInsertId();
+
+	/**
+	 * Returns the table name quoted and with database prefix as needed by the implementation
+	 *
+	 * @param string $table
+	 * @return string
+	 * @since 9.0.0
+	 */
+	public function getTableName($table);
+
+	/**
+	 * Returns the column name quoted and with table alias prefix as needed by the implementation
+	 *
+	 * @param string $column
+	 * @param string $tableAlias
+	 * @return string
+	 * @since 9.0.0
+	 */
+	public function getColumnName($column, $tableAlias = '');
 }
diff --git a/tests/lib/db/querybuilder/querybuildertest.php b/tests/lib/db/querybuilder/querybuildertest.php
index ca3901ad049524f210b7466ccd8c3cbb49e8a866..c8e029d9e40e57c8be7fafc22835a4503b3032e2 100644
--- a/tests/lib/db/querybuilder/querybuildertest.php
+++ b/tests/lib/db/querybuilder/querybuildertest.php
@@ -48,12 +48,12 @@ class QueryBuilderTest extends \Test\TestCase {
 		$this->queryBuilder = new QueryBuilder($this->connection);
 	}
 
-	protected function createTestingRows() {
+	protected function createTestingRows($appId = 'testFirstResult') {
 		$qB = $this->connection->getQueryBuilder();
 		for ($i = 1; $i < 10; $i++) {
 			$qB->insert('*PREFIX*appconfig')
 				->values([
-					'appid' => $qB->expr()->literal('testFirstResult'),
+					'appid' => $qB->expr()->literal($appId),
 					'configkey' => $qB->expr()->literal('testing' . $i),
 					'configvalue' => $qB->expr()->literal(100 - $i),
 				])
@@ -80,11 +80,11 @@ class QueryBuilderTest extends \Test\TestCase {
 		return $rows;
 	}
 
-	protected function deleteTestingRows() {
+	protected function deleteTestingRows($appId = 'testFirstResult') {
 		$qB = $this->connection->getQueryBuilder();
 
 		$qB->delete('*PREFIX*appconfig')
-			->where($qB->expr()->eq('appid', $qB->expr()->literal('testFirstResult')))
+			->where($qB->expr()->eq('appid', $qB->expr()->literal($appId)))
 			->execute();
 	}
 
@@ -272,6 +272,34 @@ class QueryBuilderTest extends \Test\TestCase {
 		$this->deleteTestingRows();
 	}
 
+	public function testSelectDistinct() {
+		$this->deleteTestingRows('testFirstResult1');
+		$this->deleteTestingRows('testFirstResult2');
+		$this->createTestingRows('testFirstResult1');
+		$this->createTestingRows('testFirstResult2');
+
+		$this->queryBuilder->selectDistinct('appid');
+
+		$this->queryBuilder->from('*PREFIX*appconfig')
+			->where($this->queryBuilder->expr()->in(
+				'appid',
+				[$this->queryBuilder->expr()->literal('testFirstResult1'), $this->queryBuilder->expr()->literal('testFirstResult2')]
+			))
+			->orderBy('appid', 'DESC');
+
+		$query = $this->queryBuilder->execute();
+		$rows = $query->fetchAll();
+		$query->closeCursor();
+
+		$this->assertEquals(
+			[['appid' => 'testFirstResult2'], ['appid' => 'testFirstResult1']],
+			$rows
+		);
+
+		$this->deleteTestingRows('testFirstResult1');
+		$this->deleteTestingRows('testFirstResult2');
+	}
+
 	public function dataAddSelect() {
 		$queryBuilder = new QueryBuilder(\OC::$server->getDatabaseConnection());
 		return [
@@ -1086,6 +1114,31 @@ class QueryBuilderTest extends \Test\TestCase {
 		);
 	}
 
+	public function testGetLastInsertId() {
+		$qB = $this->connection->getQueryBuilder();
+
+		try {
+			$qB->getLastInsertId();
+			$this->fail('getLastInsertId() should throw an exception, when being called before insert()');
+		} catch (\BadMethodCallException $e) {
+			$this->assertTrue(true);
+		}
+
+		$qB->insert('appconfig')
+			->values([
+				'appid' => $qB->expr()->literal('testFirstResult'),
+				'configkey' => $qB->expr()->literal('testing' . 50),
+				'configvalue' => $qB->expr()->literal(100 - 50),
+			])
+			->execute();
+
+		$actual = $qB->getLastInsertId();
+
+		$this->assertNotNull($actual);
+		$this->assertInternalType('int', $actual);
+		$this->assertEquals($this->connection->lastInsertId('*PREFIX*appconfig'), $actual);
+	}
+
 	public function dataGetTableName() {
 		return [
 			['*PREFIX*table', null, '`*PREFIX*table`'],
@@ -1112,7 +1165,27 @@ class QueryBuilderTest extends \Test\TestCase {
 
 		$this->assertSame(
 			$expected,
-			$this->invokePrivate($this->queryBuilder, 'getTableName', [$tableName])
+			$this->queryBuilder->getTableName($tableName)
+		);
+	}
+
+	public function dataGetColumnName() {
+		return [
+			['column', '', '`column`'],
+			['column', 'a', 'a.`column`'],
+		];
+	}
+
+	/**
+	 * @dataProvider dataGetColumnName
+	 * @param string $column
+	 * @param string $prefix
+	 * @param string $expected
+	 */
+	public function testGetColumnName($column, $prefix, $expected) {
+		$this->assertSame(
+			$expected,
+			$this->queryBuilder->getColumnName($column, $prefix)
 		);
 	}
 }