Не работает TOP в InsertSelect для СУБД Oracle

Есть запрос в базу данных, по ответу поддержки "классы EntitySchemaQuery, Select, Insert, Update, Delete это СУБД-независимое API ", исходя из этого был использован InsertSelect. На PostgreSQL запрос отрабатывает отлично, но в Oracle выдает ошибку при использовании TOP в запросе.

Код запроса:

Query selectQuery = new Select(UserConnection)
    .Top(numberCountForNumberPool)
    .Column(Column.Parameter(request))
    .Column(Column.Parameter(currentUserContactId))
    .Column(Column.Parameter(currentUserContactId))
    .Column("KtSimManagementInitialPoolNumbers", "KtIccid")
    .Column("KtSimManagementInitialPoolNumbers", "KtImsi")
    .Column("KtSimManagementInitialPoolNumbers", "KtMsisdn")
    .Column("KtSimManagementInitialPoolNumbers", "KtName")
    .Column(Column.Parameter(cityAndCountNumbersEntity.GetTypedColumnValue<Guid>(city.Name)))
    .Column(Column.Parameter(cityAndCountNumbersEntity.GetTypedColumnValue<string>(note.Name)))
    .Column(Column.Parameter(DateTime.UtcNow.Date))
    .Column(Column.Parameter(DateTime.UtcNow.Date
        .AddDays((int)Core.Configuration.SysSettings.GetValue(UserConnection,
            "DayCountForDedicatedPoolNumbers") + 1).AddSeconds(-1)))
    .From("KtSimManagementInitialPoolNumbers")
    .OrderByAsc("KtSimManagementInitialPoolNumbers", "KtName")
    .Join(JoinType.LeftOuter, "KtJasperFullNumberPool")
    .On("KtSimManagementInitialPoolNumbers", "KtName")
    .IsEqual("KtJasperFullNumberPool", "KtName")
    .Where("KtJasperFullNumberPool", "KtName")
    .IsNull()
    .And("KtSimManagementInitialPoolNumbers", "KtMarketCodeId")
    .IsEqual(Column.Parameter(cityForMarketCode));
 
InsertSelect insertSelectQuery = new InsertSelect(UserConnection)
    .Into("KtJasperFullNumberPool")
    .Set("KtRequestId", "ModifiedById", "CreatedById", "KtIccid", "KtImsi", "KtMsisdn", "KtName", "KtCityId", "KtNote", "KtReserveDate", "KtReserveToDate")
    .FromSelect(selectQuery);
int numberCountInserted = insertSelectQuery.Execute();

Подскажите, есть ли возможность использовать в Select для Oracle - TOP для выборки необходимого количества записей в запросе?

Нравится

8 комментариев
Лучший ответ

Проверил, на запросе с Top, OrderByAsc,  Join, On, IsEqual, Where отрабатывает нормально. А если добавить колонки с числом и датой из параметра, получим такую же ошибку, как у Вас. Но если, как я выше предложил, дописать «.As», она исчезнет:

			var query = new Select(UserConnection)
				.Top(2)
				.Column("Contact", "Dear")
    			.Column(Column.Parameter("test")).As("SomeString")
    			.Column(Column.Parameter(DateTime.UtcNow.Date)).As("SomeDate")
				.From("Contact")
				.OrderByAsc("Contact", "Dear")
		    	.Join(JoinType.LeftOuter, "Account")
    			.On("Contact", "AccountId")		
				.IsEqual("Account", "Id")
    			.Where("Account", "AnnualRevenueId")
    			.IsNull()				;
var text =  query.GetSqlText();

Код генерируется:

SELECT  "Dear", "SomeString",   "SomeDate"FROM (SELECT  "Contact"."Dear",       :P1 "SomeString",       :P2 "SomeDate"FROM      "название_базы"."Contact""название_базы"."Account"WHERE      ("Account"."AnnualRevenueId" IS NULL)   AND "Contact"."AccountId" = "Account"."Id"(+)ORDER BY   "Contact"."Dear" ASC NULLS FIRST)WHERE  (ROWNUM <= 2)

Кстати, месяц назад Вы уже об этом спрашивали и я предлагал начать с выяснения мешающей колонки.

Александр, какая именно выдаётся ошибка? Только в Insert Select или просто в Select с Top тоже?

Если перед последней строчкой считать insertSelectQuery.GetSqlText(), что там будет?

Зверев Александр,

 в Select тоже, пишет что "

Terrasoft.Common.NullOrEmptyException: Псевдоним колонки запроса не может быть пустым
   в Terrasoft.Core.DB.DBEngine.BuildSelectColumnAliasesSqlText(StringBuilder sb, QueryColumnExpressionCollection columnExpressions)
   в Terrasoft.DB.Oracle.OracleEngine.BuildSelectQuerySqlText(StringBuilder sb, Select select)
   в Terrasoft.Core.DB.DBEngine.BuildQuerySqlText(StringBuilder sb, Select selectQuery)
   в Terrasoft.Core.DB.DBEngine.GetQuerySqlText(Select selectQuery)
   в Terrasoft.Core.DB.Select.GetSqlText()
   в Terrasoft.Configuration.KtReserveNumbersService.ReserveNumbers(Guid request)
   в SyncInvokeReserveNumbers(Object , Object[] , Object[] )
   в System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
   в Terrasoft.Web.Common.ServiceModel.ThreadContextInitializer.Invoke(Object instance, Object[] inputs, Object[]& outputs)
   в System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)

"

Проверил без TOP - такой ошибки нет

А если без этой колонки?

    .Column(Column.Parameter(DateTime.UtcNow.Date
        .AddDays((int)Core.Configuration.SysSettings.GetValue(UserConnection,
            "DayCountForDedicatedPoolNumbers") + 1).AddSeconds(-1)))

Или с ней, но сразу после после дописать псевдоним:

.As("MyColumnName")

Она самая подозрительная, но если дело не в ней, проверьте и предыдущие.

Зверев Александр, Проверил - при закоментировании колонок разницы нет, но заметил закономерность:
1) если использовать Top без OrderByAsc и Join (ну вчесте с его on, IsEqual, Where) - тогда работает
2) если использовать OrderByAsc или Join (ну вчесте с его on, IsEqual, Where) без Top - тогда работает
3) если использовать Top с OrderByAsc или Join (ну вчесте с его on, IsEqual, Where) - тогда не работает, ошибка

Проверил, на запросе с Top, OrderByAsc,  Join, On, IsEqual, Where отрабатывает нормально. А если добавить колонки с числом и датой из параметра, получим такую же ошибку, как у Вас. Но если, как я выше предложил, дописать «.As», она исчезнет:

			var query = new Select(UserConnection)
				.Top(2)
				.Column("Contact", "Dear")
    			.Column(Column.Parameter("test")).As("SomeString")
    			.Column(Column.Parameter(DateTime.UtcNow.Date)).As("SomeDate")
				.From("Contact")
				.OrderByAsc("Contact", "Dear")
		    	.Join(JoinType.LeftOuter, "Account")
    			.On("Contact", "AccountId")		
				.IsEqual("Account", "Id")
    			.Where("Account", "AnnualRevenueId")
    			.IsNull()				;
var text =  query.GetSqlText();

Код генерируется:

SELECT  "Dear", "SomeString",   "SomeDate"FROM (SELECT  "Contact"."Dear",       :P1 "SomeString",       :P2 "SomeDate"FROM      "название_базы"."Contact""название_базы"."Account"WHERE      ("Account"."AnnualRevenueId" IS NULL)   AND "Contact"."AccountId" = "Account"."Id"(+)ORDER BY   "Contact"."Dear" ASC NULLS FIRST)WHERE  (ROWNUM <= 2)

Кстати, месяц назад Вы уже об этом спрашивали и я предлагал начать с выяснения мешающей колонки.

Зверев Александр,

 да, именно Ваша рекомендация с .As("SomeString") помогла когда прописал данный алиас во все колонки где используется "Column.Parameter". Так же в поддержке ответили. Не понял только почему в PostgreSQL это работает без алиаса, а в Oracle без него не так. Но видимо это специфика запросов СУБД, главное что с алиасом работает и там, и там.

Спасибо за помощь!

Передал информацию об этой особенности для освещения в академии.

Показать все комментарии