WITH insert_cte AS ( insert into test_table (id) values (1) on conflict do nothing )
select * from insert_cte
union all
select id from test_table where id = 1; | - Не работает:
- Это union - один statement:
- select не увидит результат текущего insert.
- select не увидит результаты параллельных транзакций (если
- Без флага.
- 1 result set.
| |
WITH insert_cte AS ( insert into test_table (id) values (1) on conflict do nothing returning id, true as is_new )
select * from insert_cte
union all
select id, false as is_new from test_table where id = 1; | - Не работает:
- Это union - один statement:
- select не увидит результаты параллельных транзакций (если текущая транзакция будет ожидать блокировку на insert)
- Возвращает флаг.
- 1 result set.
- Возвращается 1 строка т.к. один statement и мы видим либо только результат insert-returning, либо только результат select.
| |
insert into test_table (id) values (1) on conflict do nothing returning id, true as is_new;
select id, false as is_new from test_table where id = 1; | - Работает.
- Возвращает флаг.
- 2 result set
((нужно делать 2 DbCommand) или (multiple result sets)).
| NpgsqlBatch await using (var batch = new NpgsqlBatch(...) { var insertCommand = new NpgsqlBatchCommand( $@" insert into test_table (id) values (1) on conflict do nothing returning id, true as is_new;" ); var selectCommand = new NpgsqlBatchCommand( $@" select id, false as is_new from test_table where id = 1;" );
batch.BatchCommands.Add(insertCommand); batch.BatchCommands.Add(selectCommand);
await using (var reader = await batch.ExecuteReaderAsync()) { do { while (await reader.ReadAsync()) { var id = await reader.GetFieldValueAsync<int>("id"); var isNew = await reader.GetFieldValueAsync<bool>("is_new"); } } while (await reader.NextResultAsync()); } } |
insert into test_table (id) values (1) on conflict do nothing;
select id from test_table where id = 1; | - Работает.
- Флага нет явно, но его можно вычислить через счетчик.
- 1 result set.
| // Флаг можно получить через счетчик // statement[0] - insert, statement[1] - select. var isNew = reader.Statements[0].RecordsAffected != 0; |
insert into test_table (id) values (1) on conflict do nothing;
select id, xmin = pg_current_xact_id()::xid as is_new from test_table where id = 1; | - Работает.
- Минусы:
- Вроде не работает, если выше есть хотя бы один savepoint.
- Возвращает флаг.
- 1 result set.
| |
insert into test_table (id, insert_key) values (1, @insert_key) on conflict do nothing;
select id, insert_key from test_table where id = 1; | - Работает.
- Минус: требует отдельный столбец (insert_key)
- Плюс: легко встраивается (например там где ORM).
- Возвращает флаг.
- 1 result set.
| // Вычисляем флаг var currentInsertKey = Guid.NewGuid(); var insertedRow = await ExecuteInsertQueryAsync(data, currentInsertKey); var isNew = insertedRow.InsertKey == currentInsertKey; |
insert into test_table (id, is_new) values (1, true) on conflict (id) do update SET is_new = false returning id, is_new; | - Работает.
- Минус:
- Требует отдельный столбец (is_new)
- Избыточная запись на update.
- Плюс: легко встраивается (например там где ORM).
- Возвращает флаг.
- 1 result set.
| |