mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-15 12:14:18 +00:00
commit
4c9e4699df
@ -121,6 +121,14 @@ However, you can delete old data using `ALTER TABLE ... DROP PARTITION`.
|
||||
|
||||
To insert a default value instead of `NULL` into a column with not nullable data type, enable [insert_null_as_default](../../operations/settings/settings.md#insert_null_as_default) setting.
|
||||
|
||||
`INSERT` also supports CTE(common table expression). For example, the following two statements are equivalent:
|
||||
|
||||
``` sql
|
||||
INSERT INTO x WITH y AS (SELECT * FROM numbers(10)) SELECT * FROM y;
|
||||
WITH y AS (SELECT * FROM numbers(10)) INSERT INTO x SELECT * FROM y;
|
||||
```
|
||||
|
||||
|
||||
## Inserting Data from a File
|
||||
|
||||
**Syntax**
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <Parsers/ASTIdentifier_fwd.h>
|
||||
#include <Parsers/ASTInsertQuery.h>
|
||||
#include <Parsers/ASTSelectQuery.h>
|
||||
#include <Parsers/ASTSelectWithUnionQuery.h>
|
||||
|
||||
#include <Parsers/CommonParsers.h>
|
||||
@ -7,6 +8,7 @@
|
||||
#include <Parsers/ExpressionListParsers.h>
|
||||
#include <Parsers/ParserSelectWithUnionQuery.h>
|
||||
#include <Parsers/ParserWatchQuery.h>
|
||||
#include <Parsers/ParserWithElement.h>
|
||||
#include <Parsers/ParserInsertQuery.h>
|
||||
#include <Parsers/ParserSetQuery.h>
|
||||
#include <Parsers/InsertQuerySettingsPushDownVisitor.h>
|
||||
@ -58,10 +60,20 @@ bool ParserInsertQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
||||
ASTPtr settings_ast;
|
||||
ASTPtr partition_by_expr;
|
||||
ASTPtr compression;
|
||||
ASTPtr with_expression_list;
|
||||
|
||||
/// Insertion data
|
||||
const char * data = nullptr;
|
||||
|
||||
if (s_with.ignore(pos, expected))
|
||||
{
|
||||
if (!ParserList(std::make_unique<ParserWithElement>(), std::make_unique<ParserToken>(TokenType::Comma))
|
||||
.parse(pos, with_expression_list, expected))
|
||||
return false;
|
||||
if (with_expression_list->children.empty())
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Check for key words `INSERT INTO`. If it isn't found, the query can't be parsed as insert query.
|
||||
if (!s_insert_into.ignore(pos, expected))
|
||||
return false;
|
||||
@ -162,7 +174,7 @@ bool ParserInsertQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
||||
|
||||
tryGetIdentifierNameInto(format, format_str);
|
||||
}
|
||||
else if (s_select.ignore(pos, expected) || s_with.ignore(pos,expected))
|
||||
else if (s_select.ignore(pos, expected) || s_with.ignore(pos, expected))
|
||||
{
|
||||
/// If SELECT is defined, return to position before select and parse
|
||||
/// rest of query as SELECT query.
|
||||
@ -170,6 +182,19 @@ bool ParserInsertQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
||||
ParserSelectWithUnionQuery select_p;
|
||||
select_p.parse(pos, select, expected);
|
||||
|
||||
if (with_expression_list)
|
||||
{
|
||||
const auto & children = select->as<ASTSelectWithUnionQuery>()->list_of_selects->children;
|
||||
for (const auto & child : children)
|
||||
{
|
||||
if (child->as<ASTSelectQuery>()->getExpression(ASTSelectQuery::Expression::WITH, false))
|
||||
throw Exception(ErrorCodes::SYNTAX_ERROR,
|
||||
"Only one WITH should be presented, either before INSERT or SELECT.");
|
||||
child->as<ASTSelectQuery>()->setExpression(ASTSelectQuery::Expression::WITH,
|
||||
std::move(with_expression_list));
|
||||
}
|
||||
}
|
||||
|
||||
/// FORMAT section is expected if we have input() in SELECT part
|
||||
if (s_format.ignore(pos, expected) && !name_p.parse(pos, format, expected))
|
||||
return false;
|
||||
|
20
tests/queries/0_stateless/03248_with_insert.reference
Normal file
20
tests/queries/0_stateless/03248_with_insert.reference
Normal file
@ -0,0 +1,20 @@
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
2025-01-01
|
||||
2026-01-01
|
||||
2027-01-01
|
||||
2028-01-01
|
||||
2029-01-01
|
||||
2030-01-01
|
||||
2031-01-01
|
||||
2032-01-01
|
||||
2033-01-01
|
||||
2034-01-01
|
49
tests/queries/0_stateless/03248_with_insert.sql
Normal file
49
tests/queries/0_stateless/03248_with_insert.sql
Normal file
@ -0,0 +1,49 @@
|
||||
DROP TABLE IF EXISTS x;
|
||||
|
||||
CREATE TABLE x ENGINE = Log AS SELECT * FROM numbers(0);
|
||||
|
||||
SYSTEM STOP MERGES x;
|
||||
|
||||
WITH y AS
|
||||
(
|
||||
SELECT *
|
||||
FROM numbers(10)
|
||||
)
|
||||
INSERT INTO x
|
||||
SELECT *
|
||||
FROM y
|
||||
INTERSECT
|
||||
SELECT *
|
||||
FROM numbers(5);
|
||||
|
||||
WITH y AS
|
||||
(
|
||||
SELECT *
|
||||
FROM numbers(10)
|
||||
)
|
||||
INSERT INTO x
|
||||
SELECT *
|
||||
FROM numbers(5)
|
||||
INTERSECT
|
||||
SELECT *
|
||||
FROM y;
|
||||
|
||||
SELECT * FROM x;
|
||||
|
||||
DROP TABLE x;
|
||||
|
||||
CREATE TABLE x (d date) ENGINE = Log;
|
||||
|
||||
WITH y AS
|
||||
(
|
||||
SELECT
|
||||
number,
|
||||
date_add(YEAR, number, toDate('2025-01-01')) AS new_date
|
||||
FROM numbers(10)
|
||||
)
|
||||
INSERT INTO x
|
||||
SELECT y.new_date FROM y;
|
||||
|
||||
SELECT * FROM x;
|
||||
|
||||
DROP TABLE x;
|
@ -0,0 +1 @@
|
||||
Only one WITH should be presented, either before INSERT or SELECT
|
10
tests/queries/0_stateless/03248_with_insert_with.sh
Executable file
10
tests/queries/0_stateless/03248_with_insert_with.sh
Executable file
@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
CUR_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
# shellcheck source=../shell_config.sh
|
||||
. "$CUR_DIR"/../shell_config.sh
|
||||
|
||||
$CLICKHOUSE_CLIENT -q 'DROP TABLE IF EXISTS x'
|
||||
$CLICKHOUSE_CLIENT -q 'CREATE TABLE x ENGINE = Log AS SELECT * FROM numbers(0)'
|
||||
$CLICKHOUSE_CLIENT -q 'WITH y AS ( SELECT * FROM numbers(10) ) INSERT INTO x WITH y2 AS ( SELECT * FROM numbers(10) ) SELECT * FROM y;' |& grep --max-count 1 -F --only-matching "Only one WITH should be presented, either before INSERT or SELECT"
|
||||
$CLICKHOUSE_CLIENT -q 'DROP TABLE x'
|
Loading…
Reference in New Issue
Block a user