Приветствую. Проблема с созданием Join'а.
Имеется вот такой SelectQuery.
SELECT [tbl_OfferingInMovement].[ID] AS [ID], [tbl_OfferingInMovement].[OfferingMovementID] AS [OfferingMovementID], [tbl_OfferingInMovement].[OfferingID] AS [OfferingID], [Offering].[Name] AS [OfferingName], [Offering].[Code] AS [OfferingCode], [Unit].[Name] AS [UnitName], [OfferingMovement].[StoreID] AS [StoreID], [tbl_Store].[Store] AS [Store], [tbl_OfferingInMovement].[Quantity] AS [Quantity], [tbl_OfferingInMovement].[BasicPrice] AS [BasicPrice], [tbl_OfferingInMovement].[BasicAmount] AS [BasicAmount], [tbl_OfferingInMovement].[SignedQuantity] AS [SignedQuantity], [tbl_OfferingInMovement].[SignedAmount] AS [SignedAmount], [tbl_OfferingInMovement].[Description] AS [Description], [OfferingMovementType].[ID] AS [OfferingMovementTypeID], [OfferingMovementType].[Name] AS [OfferingMovementType], [tbl_OfferingInMovement].[PlanQuantity] AS [PlanQuantity], [tbl_OfferingInMovement].[PlanAmount] AS [PlanAmount], [OfferingMovement].[StatusID] AS [OfferingMovementStatusID], [tbl_OfferingInMovement].[Price] AS [Price], [tbl_OfferingInMovement].[Amount] AS [Amount], [OfferingMovement].[CurrencyID] AS [CurrencyID], [tbl_Currency].[Currency] AS [Currency], [OfferingMovement].[CurrencyRate] AS [Rate], [tbl_OfferingInMovement].[ConsignmentID] AS [ConsignmentID], [Consignment].[Number] AS [ConsignmentNumber], [Offering].[OfferingChargeMethodID] AS [OfferingChargeMethodID], [OfferingMovement].[Number] AS [OfferingMovementNumber], [tbl_OfferingInMovement].[TZR] AS [TZR], [tbl_OfferingInMovement].[PrimeCost] AS [PrimeCost], [tbl_OfferingInMovement].[PrimeAmount] AS [PrimeAmount], [Offering].[Volume] AS [Volume], [Offering].[Weight] AS [Weight], [Offering].[BasicPrice] AS [OfferingBasicPrice], [tbl_OfferingInMovement].[TZRAmount] AS [TZRAmount], [tbl_OfferingInMovement].[DocumentID] AS [DocumentID], [tbl_OfferingInMovement].[ContractID] AS [ContractID], [tbl_OfferingInMovement].[InvoiceID] AS [InvoiceID], [tbl_Document].[Title] AS [DocumentNumber], [tbl_Contract].[Title] AS [ContractNumber], [tbl_Invoice].[InvoiceNumber] AS [InvoiceNumber], [tbl_OfferingInMovement].[PurchaseID] AS [PurchaseID], [tbl_Purchases].[Number] AS [PurchaseNumber], [OfferingMovement].[SupplierID] AS [SupplierID], [tbl_OfferingInMovement].[Date] AS [Date], [OfferingMovement].[ModifiedOn] AS [ModifiedOn], [OfferingMovement].[DateOfShipment] AS [DateOfShipment], [AccountBillingInfoItelon].[Name] AS [ItelonName], [AccountBillingPayerInfo].[Name] AS [PayerName] FROM [dbo].[tbl_OfferingInMovement] AS [tbl_OfferingInMovement] LEFT OUTER JOIN [dbo].[vw_Offering] AS [Offering] ON [Offering].[ID] = [tbl_OfferingInMovement].[OfferingID] LEFT OUTER JOIN [dbo].[tbl_Unit] AS [Unit] ON [Unit].[ID] = [Offering].[DefaultUnitID] LEFT OUTER JOIN [dbo].[vw_OfferingMovement] AS [OfferingMovement] ON [OfferingMovement].[ID] = [tbl_OfferingInMovement].[OfferingMovementID] LEFT OUTER JOIN [dbo].[tbl_OfferingMovementType] AS [OfferingMovementType] ON [OfferingMovementType].[ID] = [OfferingMovement].[TypeID] LEFT OUTER JOIN [dbo].[tbl_Store] AS [tbl_Store] ON [tbl_Store].[ID] = [OfferingMovement].[StoreID] LEFT OUTER JOIN [dbo].[vw_OfferingMovement] AS [Consignment] ON [Consignment].[ID] = [tbl_OfferingInMovement].[ConsignmentID] LEFT OUTER JOIN [dbo].[tbl_Currency] AS [tbl_Currency] ON [tbl_Currency].[ID] = [OfferingMovement].[CurrencyID] LEFT OUTER JOIN [dbo].[vw_Document] AS [tbl_Document] ON [tbl_Document].[ID] = [tbl_OfferingInMovement].[DocumentID] LEFT OUTER JOIN [dbo].[vw_Contract] AS [tbl_Contract] ON [tbl_Contract].[ID] = [tbl_OfferingInMovement].[ContractID] LEFT OUTER JOIN [dbo].[vw_Invoice] AS [tbl_Invoice] ON [tbl_Invoice].[ID] = [tbl_OfferingInMovement].[InvoiceID] LEFT OUTER JOIN [dbo].[vw_Purchases] AS [tbl_Purchases] ON [tbl_Purchases].[ID] = [tbl_OfferingInMovement].[PurchaseID] LEFT OUTER JOIN [dbo].[tbl_AccountBillingInfo] AS [AccountBillingInfoItelon] ON [AccountBillingInfoItelon].[ID] = [OfferingMovement].[InfoItelonID] LEFT OUTER JOIN [dbo].[tbl_AccountBillingInfo] AS [tbl_AccountBillingInfoPayer] ON [tbl_AccountBillingInfoPayer].[ID] = [tbl_OfferingInMovement].[PayerID]
Предпоследний Join(AS [AccountBillingInfoItelon]) создан мною. Работает отлично.
Вот его код. Заранее извиняюсь за синтаксис VBA.
Set oTable = TSConnector.Services.GetNewItemByUSI(AccountBillingInfoTableName) Set oJoin = oSelectQuery.Items(0).Joins.Items(4).CreateCopy oJoin.UID = TSConnector.GenGUID oJoin.RightField = oJoin.RightField.ParentFields.Items(40) oJoin.LeftField = oTable.Fields.ItemsByName("ID") oJoin.LeftTableAlias = "AccountBillingInfoItelon" oJoin.JoinType = jtLeftOuter oSelectQuery.Items(0).Joins.AddItem oJoin oSelectQuery.Items(0).Joins.Items(oSelectQuery.Items(0).Joins.Count - 1).CanDisable = False
Последний создаётся не правильно.
Set oJoin = oInvoiceSelectQuery.Items(0).Joins.Items(0).CreateCopy oJoin.UID = TSConnector.GenGUID oJoin.LeftField = oTable.Fields.ItemsByName("ID") oJoin.LeftTableAlias = "tbl_AccountBillingPayerInfo" oJoin.RightField = TSConnector.Services.GetNewItemByUSI(InvoiceTableName).Fields.Items(31) oJoin.JoinType = jtLeftOuter oSelectQuery.Items(0).Joins.AddItem oJoin oSelectQuery.Items(0).Joins.Items(oSelectQuery.Items(0).Joins.Count - 1).CanDisable = False
Проблема с RightField. Поле верное, то что нужно [PayerID]. Но мне надо чтобы оно доставала его именно из [tbl_Invoice]. А она же в SQL подставляет [tbl_OfferingInMoment]. Где можно изменить таблицу в Join'е или ещё где-то в SelectQuery. Целую неделю мучаюсь не могу понять.
Нравится
В коробке в скрипте wnd_IWTGraphWizardScript есть функция:
function GetPathByColumn(Column) { var Result = Column.Field.ParentFields.ParentTable.UID + snpFields + Column.Field.UID; var ParentJoin = Column.ParentJoin; while (ParentJoin) { Result = ParentJoin.RightField.ParentFields.ParentTable.UID + snpFields + ParentJoin.RightField.UID + jtLeft + ParentJoin.LeftField.ParentFields.ParentTable.UID + snpFields + ParentJoin.LeftField.UID + snpSegment + Result; ParentJoin = ParentJoin.ParentJoin; } return Result; }
Возможно, подобным образом можно не только считывать, но и записывать название таблицы. Если разобраться не получится, можно попробовать подключится в отладчике и посмотреть, как устроены нормально работающие join-ы.
Не получилось записывать название таблицы в Join. Что за связь используется так и не получилось выяснить. Я пользуюсь редактором VBA непосредственно в EXCEL. За Visual Studio еще не садился.
Воспользовался oSubSelectColumn. Отличная штука. Всё что хотел, получилось.
Set oSubSelectColumn = oSelectQuery.Items(0).Columns.CreateSubSelectColumn Set oTable = TSConnector.Services.GetNewItemByUSI(AccountBillingInfoTableName) Dim oSQLFilter As CustomSQLFilter Dim oSelect As TSObjectLibrary.Select Set oSelect = oSelectQuery.CreateItem oSelect.FromTable = oTable oSelect.FromTableAlias = "AccountBillingInfo" Set oGeneralColumn = oSelectQuery.Columns.CreateGeneralColumn oGeneralColumn.Field = oTable.Fields.ItemsByName("Name") oGeneralColumn.ColumnAlias = "Name" oSelect.Columns.Add oGeneralColumn Set oSQLFilter = oSelect.Filters.CreateCustomSQLFilter oSQLFilter.SQLText = "[AccountBillingInfo].[ID] = [OfferingMovement].[InfoItelonID]" oSelect.Filters.Add oSQLFilter oSubSelectColumn.ColumnSelectQuery.Add oSelect oSubSelectColumn.ColumnAlias = "AccountBillingInfoItelon" oSelectQuery.Items(0).Columns.Add oSubSelectColumn oSelectQuery.Items(0).Columns.Items(oSelectQuery.Items(0).Columns.Count - 1).IsEnabled = True
В редакторе VBA тоже есть отладка. Не знаю, показывает ли структуру объектов, но вроде бы должен.
Можно и через SubSelect. Когда-то в базе на Orcacle упирались в лимит Join-ов и приходилось в дизайнере переделывать в sq часть колонок на колонки-подзапросы.
Если видно структуру, можно посмотреть, как устроен нормальный join. Ну, или использовать подзапросы.
Зверев Александр, Пользовался более года подзапросами. Сегодня столкнулся с проблемой фильтрации по столбцам от подзапросов. Долго не стал вникать в суть проблемы.
Решил вернуться к Join'ам.
Решение к проблеме в самом низу этого сообщения.
Пошёл по вашему совету, Александр. Решил сравнивать структуры созданного мною нового Join'а и уже готового Join'а из другого готового SelectQuery.
Задача была поставлена аналогична упомянутой выше: прикрепить таблицу(создать join) к запросу(SelectQuery). При этом из прикрепленной таблицы(join'а) должны выбираться те строки, значения ключевых полей которых равны значениям полей не из исходной таблицы, на основе которой сформирован запрос(SelectQuery), а из таблицы, прикрепленной ранее (уже прикрепленного join'а). Всё тоже самое, что и в предыдущей задаче. Выражаясь кратким языком, присоединить join к уже имеющемся join'у в SelectQuery.
На следующей картинке представлен SQL текст уже (упомянутого в первом сообщения топика) готового запроса "sq_OfferingInMovement", сформированный на основе таблицы "tbl_OfferingInMovement" и нескольких прикрепленных таблиц к нему. В этом тексте можно увидеть, что к запросу прикреплена таблица(join), к заранее прикрепленному (join'у). В этом запросе всё правильно.
Синим выделены строки, означающие что к запросу прикреплено представление(если не понятно что такое представление, можно прочесть как "таблица") "[vw_Offering], у которого значение ключевого поля "[ID]" равняется значению поля исходной таблицы "[tbl_OfferingInMovement].[OfferingID]". Этому присоединенному представлению присвоен псевдоним(alias) "[Offering]".
Красным выделены строки, означающие что к запросу прикреплена таблица "[tbl_Unit]", у которого значение ключевого поля "[ID]" равняется значению поля не исходной таблицы, а значению поля прикрепленного (синим выделено) представления [Offering].[DefaultUnitID].
В этом примере всё отлично.
Проблема заключалась в том, что при создании нового собственного прикрепления (join'а), которое должно было крепиться к уже имеющемуся прикреплению (join'у), в SQL тексте отображалось что новое прикрепление (join) крепиться не к уже имеющемуся прикреплению, а к исходной таблице. То есть, если взять пример выше, и прикрепление, которое выделено красным, было бы создано мною, то там вместо [Offering].[DefaultUnitID] было бы [tbl_OfferingInMovement][DefaultUnitID], что было бы неверным и, естественно, выдавало бы ошибку. Так как в [tbl_OfferingInMovement] нет поля [DefaultUnitID] и вообще это не то что мне нужно.
В ходе сравнения join'ов выяснилось, что у объекта Join, оказывается, есть параметр ParentJoin, которому необходимо присваивать тот Join, к которому будет необходимо прикреплять новый join.
Вот код правильно созданного Join'а и необходимого нам столбца из него.
Создание нового прикрепления (join'а) к исходной таблице запроса.
//Таблица, строки которой будем крепить. Set objTSTable = objTSConnector.GetService(strAssemblingInTaskTableName) Set objTSAssemblingInTaskJoin = objTSSelect.Joins.CreateItem objTSAssemblingInTaskJoin.ParentJoins = objTSSelect.Joins objTSAssemblingInTaskJoin.LeftField = objTSTable.Fields.ItemsByName("ID") objTSAssemblingInTaskJoin.RightField = objTSSelect.FromTable.Fields.ItemsByName("AssemblingInTaskID") objTSSelect.Joins.Add objTSAssemblingInTaskJoin
Добавляем необходимый нам столбец из этого прикрепления. Не знаю, нужен ли он для другого прикрепления, но это не трудно выяснить. Просто не надо его создавать и добавлять. Вот код.
Set objTSColumn = objTSSelect.Columns.CreateGeneralColumn objTSColumn.ParentColumns = objTSSelect.Columns objTSColumn.ParentJoin = objTSAssemblingInTaskJoin objTSColumn.ParentParametriticQuery = objTSSelectQuery objTSColumn.Field = objTSTable.Fields.ItemsByName("TaskID") objTSColumn.DependsOn.CommaText = objTSTable.SQLName objTSSelect.Columns.Add objTSColumn objTSColumn.IsEnabled = True
Теперь добавляем ещё одно прикрепление (join) к уже созданному выше прикреплению.
'Таблица нового прикрепления. Set objTSTable = objTSConnector.GetService(strTaskTableName) Set objTSTaskJoin = objTSSelect.Joins.CreateItem 'Вот здесь обязательно указать то прикрепление, к которому будем крепить это. objTSTaskJoin.ParentJoin = objTSAssemblingInTaskJoin objTSTaskJoin.ParentJoins = objTSSelect.Joins objTSTaskJoin.LeftField = objTSTable.Fields.ItemsByName("ID") objTSTaskJoin.RightField = objTSAssemblingInTaskJoin.LeftField.ParentFields.ItemsByName("TaskID") objTSSelect.Joins.Add objTSTaskJoin
Ну и добавляем обязательно столбец из этого прикрепления. Без него join не включиться, если не указать параметр у Join'а CanDisable = False. Без особой причины CanDisable можно не трогать. Достаточно просто добавить столбец из этого join'а, как его параметр IsEnabled сразу же станет True.
Set objTSColumn = objTSSelect.Columns.CreateGeneralColumn objTSColumn.ParentColumns = objTSSelect.Columns objTSColumn.ParentJoin = objTSTaskJoin objTSColumn.ParentParametriticQuery = objTSSelectQuery objTSColumn.Field = objTSTable.Fields.ItemsByName("StatusID") objTSColumn.DependsOn.CommaText = objTSTable.SQLName objTSSelect.Columns.Add objTSColumn objTSColumn.IsEnabled = True
Всё.
Извините за столь жидкий текст. Думаю, что кто столкнётся или уже столкнулся с данной проблемой, то всё поймёт.
Если есть какие-то замечания, то обязательно напишите.
Можно и так. Всё ли правильно, по коду сказать сложно. Если в результате в профайлере идёт нужный SQL-запрос, то нормально.
По поводу свойства ParentJoin, в SDK о нём есть, но очень кратко. Лучше смотреть примеры использования поиском по скриптам конфигурации.