Вложени заявки. Вложени заявки Работа с пакетни заявки

Вложени заявки. Вложени заявки Работа с пакетни заявки

Тази статия е предназначена за читатели, които са запознати с езика SQL.

Езикът за заявки 1C, използван от версия 8, днес се превърна в полезен инструмент за работа с бази данни, който ви позволява да четете от тях, но не и да пишете. Синтактично езикът на заявките е много подобен на езика SQL, но на руски език.

По-долу е дадена таблица на съответствие между основния език на заявките и SQL операторите:

1C оператори на език за заявки

SQL израз

РАЗЛИЧНИ

СЪЕДИНЕНИЕ

ГРУПИРАЙ ПО

КОМБИНИРАЙТЕ

СОРТИРАНЕ ПО

И това не е пълен списък. По-пълна справочна информация за наличните оператори на език за заявки може да бъде получена в дизайнера на заявки, който ще бъде разгледан по-долу.

Изпълнението на 1C заявка от програмния код се извършва с помощта на вградения езиков обект „Заявка“. Пример за писане на заявка към база данни с помощта на вградения език за програмиране:

Заявка = Нова заявка; Query.Text = "SELECT | Synonym.Link AS Link |FROM | Directory.Directory1 AS Synonym"; Изберете = Query.Run().Select(); Докато Selection.Next() Loop // Вмъкване на обработка на селекцията SelectionDetailedRecords EndCycle;

Методът “Run” изпълнява заявката, методът “Select” връща стойност от тип “SelectFromQueryResult”. Можете също да използвате метода Unload, който връща таблица със стойности.

Параметрите на заявката се съхраняват в свойството „Параметри“ (в този случай това е структура, така че всички методи на структурата са приложими тук - вмъкване, изтриване и т.н.).

Пример за настройка на параметъра “Query.Parameters.Insert” (“Директория”, DirectoryLink). В заявката можете да получите достъп до параметрите, като използвате амперсанда „&Директория“. По-долу е даден пример за заявка, използваща параметри:

Заявка = Нова заявка; Query.Text = "SELECT | Users.Link AS Link, | Users.Parent AS Parent, | Users.Name AS Name |FROM | Directory.Users AS Users |WHERE | Users.Link = &Directory"; Query.Parameters.Insert("Директория", DirectoryLink); Изберете = Query.Run().Select(); Докато Selection.Next() Loop // Вмъкване на обработка на селекцията SelectionDetailedRecords EndCycle;

Нека си припомним, че езикът на заявките е предназначен само за четене на данни от базата данни, така че няма аналози на такива SQL изрази като INS ERT и UPDATE. Данните могат да се променят само чрез обектния модел на вградения език за програмиране 1C. Също така в езика за заявки 1C има оператори, които нямат аналози в SQL, например:

  • В ЙЕРАРХИЯТА
  • МЯСТО
  • ИНДЕКС ПО

В ЙЕРАРХИЯТА– позволява да изберете всички елементи от йерархичната директория, които са включени в йерархията на прехвърлената връзка. Примерна заявка с използване В ЙЕРАРХИЯТА:

SELECT Products.Link, Products.Article FROM Directory.Products AS Products WHERE Products.Link IN HIERARCHY(&Citrus)"

В този случай резултатът ще върне всички подчинени елементи на номенклатурната директория на Citrus, без значение колко нива на йерархия има тази директория.

Също така, например, задачата е да се намери продукт с името „Pen“. Продуктът трябва да бъде включен в йерархията „Канцеларски материали“. Стоки”, тоест не е нужно да търсим дръжката на вратата. Структурата на номенклатурата в този случай е следната:

офис

|_ Писалки |_ Червен химикал |_ Син химикал |_ Мастилени химикалки |_ Линийки

Аксесоари

|_ Дръжки за врати |_ Семпла дръжка за врати |_ Луксозна дръжка за врати

Пишем следното искане:

SELECT Products.Link, Products.Article FROM Directory.Products AS Products WHERE Products.Name Like "Pen%" AND Products.Link IN HIERARCHY(&Stationery)"

При използване на дизайна В ЙЕРАРХИЯТАтрябва да се има предвид, че ако подадете празна връзка към параметъра „Office“, изпълнението на заявката ще се забави, тъй като платформата ще проверява всеки елемент, за да види дали принадлежи към корена.

МЯСТО– Този оператор поставя резултата във временна таблица. Примерна заявка:

ИЗБЕРЕТЕ Users.Link AS Link, Users.Parent AS Parent, Users.Name AS Name PLACE SelectedUsers FROM Directory.Users AS Users WHERE Users.Link = &Directory; SELECT SelectedUsers.Link AS Link, SelectedUsers.Parent AS Parent, SelectedUsers.Name AS Name FROM SelectedUsers AS SelectedUsers

Тази SQL заявка ще бъде изпълнена от няколко заявки:

  • Създаване на временна таблица (платформата може да „използва повторно“ предварително създадени временни таблици, така че създаването не винаги се случва);
  • Поставяне на данни във временна таблица;
  • Изпълнение на основната заявка, а именно SEL ECT от тази временна таблица;
  • Разрушаване/почистване на временна маса.

Временна таблица може да бъде унищожена изрично чрез конструкцията УНИЩОЖИТЕ, или имплицитно - при затваряне на мениджъра на временни таблици.

Обектът “Query” на вградения език за програмиране има свойство “Temporary Table Manager”, което е предназначено за работа с временни таблици. Примерен код:

MVT = Нов TemporaryTableManager(); Заявка = Нова заявка; Query.TemporaryTableManager = MVT;

След изпълнение на заявка, променливата MVT може да се използва втори път в друга заявка, което несъмнено е още едно предимство на използването на временни таблици. В този случай временната таблица от базата данни ще бъде изтрита, когато се извика методът “Close”...

MVT.Close();

...или при изчистване на променлива от паметта, тоест при изпълнение на метода, в който променливата е декларирана. Временните таблици увеличават натоварването на дисковата подсистема, така че не трябва да създавате твърде много временни подсистеми (например в цикъл) или подсистеми с голям обем.

ИНДЕКС ПО– този оператор се използва заедно с оператора МЯСТО.Когато създавате временна таблица, този оператор може да индексира създаваната таблица, което значително ускорява работата с нея (но само ако индексът съвпада с вашата заявка).

Безплатна експертна консултация

Благодарим ви за заявката!

1C специалист ще се свърже с вас в рамките на 15 минути.

Характеристики на някои оператори на езика за заявки

ЗА СМЯНА– този оператор е предназначен да заключи конкретна таблица на заявка (или всички таблици, които участват в заявката). Заключването се осъществява чрез прилагане на U-заключване към масата. В SQL това се реализира чрез намек UPDLOCK. Този дизайн е необходим за предотвратяване на задънени блокировки. Пример за заявка с конструкция ЗА СМЯНА:

ИЗБЕРЕТЕ Users.Link AS Link, Users.Parent AS Parent, Users.Name AS Name FROM Directory.Users AS Users LEFT JOIN Directory.RFK AS RFK BY Users.RFK = RFK.Link ЗА ПРОМЯНА на Directory.Users

В този пример U lock ще бъде поставен в таблицата Users. Ако не посочите таблица за заключване, то ще бъде наложено на всички таблици, участващи в заявката. Важно е да се отбележи, че този дизайн работи само в конфигурации, в които е активиран режимът за автоматично управление на заключването.



СЪЕДИНЕНИЕ– заявката поддържа връзки ЛЯВО/ДЯСНО, ПЪЛНО, ВЪТРЕШНО,което съответства на съединенията в SQL – LEFT/RIGHT JOIN, OUTER JOIN, INNER JOIN.

Въпреки това, когато използвате конструктора на заявки, няма да можете да направите ПРАВИЛНО ПРИСЪЕДИНЕНЕ.Конструкторът просто ще размени таблиците, но операторът винаги ще бъде с лява ръка. Поради тази причина никога няма да видите използването на дясно съединение в 1C.

Синтактично връзката изглежда така:

SELECT Table1.Link AS Link FROM Directory.Directory1 AS Table1 LEFT JOIN Directory.Directory2 AS Table2 BY Table1.Attributes = Table2.Attributes

Езикът за заявки 1C няма оператор за свързване на декартов продукт (CROSS JOIN). Липсата на оператор обаче не означава, че езикът на заявката не поддържа такава връзка. Ако е необходимо, можете да обедините таблици по следния начин:

SELECT Table1.Link AS Link FROM Directory.Directory1 AS Table1 LEFT JOIN Directory.Directory2 AS Table2 BY TRUE

Както се вижда от примера, ключът за връзка е зададен ПО ИСТИНА, тоест всеки ред от една таблица съответства на ред от друга. Типът на съединение (ЛЯВО, ДЯСНО, ПЪЛНО, ВЪТРЕШНО) не е важен, ако имате редове и в двете таблици, но ако няма редове в една от таблиците (да кажем таблицата) - резултатът ще бъде различен. Например при използване ВЪТРЕШЕНрезултатът от връзката ще бъде празен. Използвайки ЛЯВО, ДЯСНОрезултатът от присъединяването ще бъде или няма да бъде данни в зависимост от това коя таблица обединяваме - с данни или не. Използвайки ПЪЛЕНДанните винаги ще бъдат свързани (естествено само от една таблица, тъй като другата е празна); изборът на тип връзка зависи от конкретната задача на приложението.

Малък визуален намек за това как работят различните типове връзки:



КАТО.За разлика от подобния SQL оператор - LIKE, шаблонът за КАТОможе да се посочи само с някои специални знаци:

  • % (процент): последователност, съдържаща произволен брой произволни знаци;
  • _ (долна черта): един произволен знак;
  • / - следващият знак трябва да се интерпретира като нормален знак.

РЕЗУЛТАТИ ОТ СОФТУЕРА SQL аналогът е операторът ROLLUP. Пример за използване на оператор РЕЗУЛТАТИ:

ИЗБЕРЕТЕ Продукти.Цена КАТО Цена, Продукти.Продукт КАТО Продукт ОТ Директория.Номенклатура КАТО Продукти СРЕДНИ РЕЗУЛТАТИ (Цена) ПО Продукт

Резултатът ще бъде така:

легло

9833,333

Желязо

Химилка

Тоест към резултата се добавя допълнителен ред, съдържащ стойността на полето, по което се извършва групирането и стойността на агрегиращата функция.

Работа с пакетни заявки

1C ви позволява да работите с партиди от заявки. В пакетна заявка текстовете на заявката са разделени с точка и запетая (;). Пакетната заявка 1C се изпълнява последователно. Примерен текст на пакетна заявка:

ИЗБЕРЕТЕ Users.Link AS Link, Users.Parent AS Parent, Users.Name AS Name FROM Directory.Users AS Users;
ИЗБЕРЕТЕ Работен график.Потребител КАТО Потребител, Работен график.Дата КАТО Дата, Работен график.Работни часове КАТО Работни часове ОТ Регистрирайте информация.Работен график КАТО Работен график

За да получите резултата от всички заявки, включени в пакет, трябва да използвате метода „ExecutePackage“ на обекта на заявката, вместо „Run“. Този метод изпълнява всички заявки последователно. Резултатът от заявката е масив от резултати за всяка заявка в пакета и последователността на поставяне в масива е същата като последователността от заявки в текста на пакета.

Когато разглеждаме език за заявки, си струва да споменем такава функция като виртуални таблици. Виртуалните таблици не присъстват в базата данни; те са вид обвивка, която се изпълнява от страна на СУБД като заявка, използваща подзаявки. Пример за 1C заявка, използваща виртуални таблици:

ИЗБЕРЕТЕ RegisterLiabilitiesTurnovers.Liability AS Пасив ОТ RegisterAccumulations.RegisterLiabilities.Turnover() AS RegisterLiabilitiesTurnovers

Такава заявка към СУБД ще изглежда така:

SEL ECT T1.Fld25931RRef FR OM (SELECT T2._Fld25931RRef AS Fld25931RRef, CAST(SUM(T2._Fld25936) AS NUMERIC(38, 8)) AS Fld25936Turnover_, CAST(SUM(T2._Fld25937) AS NUMERIC(38, 8) ) AS Fld25937Turnover_ FR OM dbo._AccumRgTn25938 T2 WH ERE ((T2._Fld949 = @P1)) И ((T2._Fld25936 @P2 ИЛИ T2._Fld25937 @P3)) ГРУПИРАНЕ ПО T2._Fld25931RRef HAVING (CAST(SUM(T2. _Fld2 ) 5936 ) AS NUMERIC(38, 8))) 0.0 ИЛИ (CAST(SUM(T2._Fld25937) AS NUMERIC(38, 8))) 0.0) T1>>>>

Вижда се, че не прилича на SQL, тъй като има подзаявка, групиране. Виртуалните таблици като цяло са „синтактична захар“, т.е. те са създадени като цяло за удобство при разработване на заявки, така че заявките да са по-компактни и по-четими.

Само регистрите имат виртуални таблици, но кои виртуални таблици са налични в даден регистър могат да се видят в дизайнера на заявки.



Когато използвате виртуални таблици, винаги трябва да предоставяте условие за избор. В противен случай може да възникнат проблеми с производителността.



В тялото на заявката изглежда така:

Регистър на натрупване на задължения (, Операция = &Операция) AS Регистър на задълженията

За удобство при писане на заявки, тоест създаване на текстове на заявки, в 1C има конструктор, който може да бъде извикан чрез контекстното меню (десен бутон на мишката):



В дизайнера на заявки можете да видите пълен списък на поддържаните функции и оператори на езика за заявки.


Query Builder е много гъвкав визуален инструмент за създаване на заявки с всякаква сложност. Достъпен е само в режим на конфигуратор. В режим Enterprise има така наречената “Query Console” - това е външна обработка, доставяна на ITS диска. За управлявано приложение конзолата за заявки може да бъде изтеглена от its.1c.ru.

Описанието на работата в дизайнера на заявки е извън обхвата на тази статия, така че няма да бъде обсъждано подробно.

Причини за неоптималната производителност на заявките

По-долу е даден списък на основните причини (но не всички), които водят до бавно изпълнение на заявка.

  • Използване на съединения с подзаявки

Не се препоръчва да се извършва свързване с подзаявки; подзаявките трябва да бъдат заменени с временни таблици. Конкатенирането на подзаявки може да доведе до значителни загуби на производителност, а изпълнението на заявки на различни СУБД може да варира значително по скорост. Скоростта на изпълнение на такива заявки също е чувствителна към статистиката в СУБД. Причината за това поведение е, че оптимизаторът на СУБД не винаги може правилно да определи оптималния план за изпълнение на заявката, тъй като оптимизаторът не знае нищо за това колко реда ще върне подзаявката след нейното изпълнение.

  • Използване на виртуални таблици в обединения на заявки

Виртуалните таблици на ниво СУБД се изпълняват като подзаявки, така че причините са същите като в първия параграф.

  • Използване на условия в заявка, които не отговарят на съществуващите индекси

Ако в условията на заявката (в оператора КЪДЕТОили условия на виртуална таблица) използва полета, които не всички са включени в индекса, тази заявка ще бъде изпълнена чрез сканиране на таблица на SQL конструкция или сканиране на индекс (изцяло или частично). Това ще повлияе не само на времето за изпълнение на заявката, но и ще бъде поставено прекомерно S заключване на допълнителни редове, което от своя страна може да доведе до ескалация на заключване, тоест цялата таблица ще бъде заключена.

  • Използване на ИЛИ в условията на заявката

Използване на логическия оператор ИЛИв дизайна КЪДЕТОможе също да доведе до сканиране на таблица. Това се случва, защото СУБД не може да използва правилно индекса. Вместо ИЛИможете да използвате дизайна КОМБИНИРАЙТЕ ВСИЧКО.

  • Получаване на данни чрез точка за полета от съставен тип

Не се препоръчва да се получават стойности чрез точка (в конструкцията ИЗБЕРЕТЕ КЪДЕ), защото ако атрибутът на обекта се окаже сложен тип, свързването ще се случи с всяка таблица, включена в този сложен тип. В резултат на това заявката за СУБД ще бъде значително по-сложна, което може да попречи на оптимизатора да избере правилния план за изпълнение на заявката.

От базата данни според определено условие. За да направите това, в 1C 8.3 трябва да използвате вложени заявки.

Но трябва да се има предвид, че в повечето случаи вложените заявки в 1C са безполезни, без да свързват резултатите си с други таблици. В почти всеки случай такава връзка значително ще забави изпълнението на заявката като цяло.

Пример за вложена заявка на език за заявки

Ще дам пример за вложена заявка за . Да кажем, че трябва да вземем извадка от сумата на определен баланс за отделни клиенти на определена дата:

ИЗБИРАМ
Неизплащане на платежни салда на клиента,
Non-dispatchPaymentsBalances.AmountBest
ОТ

Вземете безплатно 267 видео урока за 1C:

LEFT JOIN Регистър за натрупване. Неизплащане на плащания Салда AS Неизплащане на плащания
Software AttachmentRequest.LinkToRequestCustomers = Неразплатени PaymentsBalances.Customer

Когато СУБД изпълни такава заявка, са възможни неправилни действия от оптимизатора, тъй като е трудно да се определи планът за обработка на заявката. Когато СУБД обединява две таблици, оптимизаторът изгражда алгоритъм, базиран на изчисляване на броя на записите в тези таблици.

Когато се използва подзаявка обаче, е много трудно да се изчисли броят на записите, върнати от подзаявката.

Кое е по добре?

// Временна таблица
ИЗБИРАМ
Клиенти.Връзка КАК Клиенти
Раздел МЯСТО Клиенти
ОТ
Директория.Клиенти КАТО Клиенти
WHERE Клиенти.Връзка B (&Клиенти)
;

// Основна заявка
ИЗБИРАМ
tabClients.Link,
Non-paymentBalances.AmountBest,
ОТ
tabCustomers КАК tabCustomers
ЛЯВА ВРЪЗКА Регистрирайте натрупвания на неразпределени плащания (.
,
Клиент Б
(ИЗБИРАМ
разделКлиенти.Клиенти
ОТ
tabCustomers)) КАК Неплащане на PaymentsBalances
Софтуерен разделCustomers.Customers = Неплатени плащанияBalances.Customers

Гледайте също видео урока за вложените заявки:

Сега оптимизаторът знае предварително колко записа има във временната таблица и лесно оптимизира алгоритъма за свързване на таблица.

Ако започвате да изучавате 1C програмиране, препоръчваме нашия безплатен курс (не забравяйте

Дизайнерът на заявки в 1C 8.3 и 8.2 е мощен инструмент за разработка. Тя ви позволява да съставите текст на заявка, като използвате специална визуална среда. По този начин, за да създадете 1C заявка, не е необходимо да знаете вградения език за заявки, достатъчно е да навигирате в простия и интуитивен интерфейс на дизайнера.

Конструкторът на заявки е набор от раздели, всеки от които отговаря за своята част от заявката. Така че попълването на раздела Таблици и полетаИзбираме таблици, от които 1C заявката ще получи данните и полетата на тези таблици, необходими за решаване на конкретен проблем. Запълване на зидарията Условияналагаме условия на избраните таблици, за да изберем от тях само необходимите ни данни и т.н.

Описание на дизайнера на заявки на официалния уебсайт на 1C 8: v8.1c.ru

Таблици и полета; ; ; ; ; ; Вложени заявки (в процес на разработка).

За да извикате дизайнера на заявки 1s 8 в програмния код, трябва да:

  • Създайте нова заявка
Заявка = Нова заявка;
  • Задайте празен текстов ред за заявка
Request.Text = "";
  • Поставете курсора на мишката между кавичките и натиснете десния бутон на мишката. В контекстното меню, което се отваря, изберете елемента Конструктор на заявкии отговори дана въпроса за създаване на нова заявка. Ако текстът на заявката вече е записан, тогава трябва да щракнете някъде вътре в нея и да извикате конструктора ;

Нека да разгледаме всички основни раздели на конструктора на заявки, като използваме малки примери с нарастваща сложност. Този подход ще позволи на начинаещ 1C програмист по-ефективно да изучава конструктора и всичките му възможности. За примери ще използваме конфигурацията Счетоводство 3.0.

Урок 1. Създателят на заявки е най-простият случай на използване.

Задача: напишете заявка в номенклатурната директория, изберете цялата номенклатура на директорията.

Нови раздели: Таблици и полета.

Нови механизми: преглед и редактиране на текста на заявката чрез бутона „Заявка“.

За да започнете да създавате заявка, нека създадем нова заявка и извикаме конструктора (както е написано няколко абзаца по-горе). След това прозорецът на дизайнера ще се отвори в раздела Таблици и полета.

Теоретична част на урок No1

Раздел Таблици и полетасе състои от три раздела:

База данни. Този раздел представя всички таблици на базата данни, които могат да се използват за изграждане на заявка;

Маси. В този раздел са избрани таблиците, необходими за тази заявка. За да ги преместите след това от секцията база даннитрябва да:

  • Или щракнете двукратно върху масата;
  • Или използвайте бутоните “>” или “>>”.

Горен раздел МасиИма редица бутони. Повечето от тях ще бъдат разгледани по-подробно в следващите уроци. Засега ще дам само кратки обяснения.

  • Създайте подзаявка(Червена линия). Предназначен за създаване на нова подзаявка;
  • Създайте описание на временна таблица(жълта линия). Позволява ви да посочите името на временна таблица, която се намира извън тази заявка; може също да се използва за предаване на таблица със стойности към заявката;
  • Промяна на текущия елемент(зелена линия). Позволява ви да преминете към избраната подзаявка, временна таблица или описание на временна таблица;
  • Премахване на текущия елемент(синя линия). Премахва избраната таблица от избраните таблици;
  • Замяна на масата(синя линия). Отваря диалоговия прозорец за подмяна на избраната таблица. Полезно, ако сте избрали грешна виртуална таблица на регистъра, тъй като позиционирането се извършва върху текущо избраната таблица в списъка.
  • Опции за виртуална маса(лилава линия). Отваря параметрите на таблицата на виртуалния регистър.

Полета. Този раздел избира полета на таблица от предишния раздел. Тези полета ще бъдат колоните на таблицата или селекцията, получена в резултат на заявката. Те са необходими преди всичко, за да се получи от избраните таблици само необходимата информация в конкретен случай. За да ги преместя от раздела Необходими таблици:

  • Или щракнете двукратно върху полето;
  • Или използвайте бутоните “>” или “>>”;
  • Можете също така сами да добавите ново поле, като използвате произволен израз от полетата на избрани таблици и функции на езика за заявки.

Горен раздел ПолетаИма редица бутони. Създаването на полета с помощта на произволни изрази ще бъде обсъдено по-подробно в следващите уроци. Засега ще дам само кратки обяснения.

  • Добавете(зелена линия). Проектиран за добавяне на ново поле с помощта на безплатния редактор на изрази;
  • Промяна на текущия елемент(Червена линия). Позволява ви да промените избраното поле с помощта на редактора;
  • Изтриване на текущия(синя линия). Премахва избраното поле от списъка.

Практическа част на урок №1

Заехме се с теорията, необходима за изпълнение на задачата, предоставена в този урок. Нека ви напомня как звучи: напишете заявка до номенклатурната директория, изберете цялата номенклатура на директорията.

Нека започнем да създаваме заявка за елементи:

  • Нека създадем нова заявка и отворим конструктора, използвайки метода, посочен в началото на урока;
  • В глава База данни, нека отворим тема Справочниции там ще намерим водач номенклатура;
  • Изберете го и използвайте бутона „>“, за да го преместите в секцията Маси;
  • В глава Масиотворете номенклатурната директория с помощта на иконата „+“;
  • В списъка с полета, който се отваря, намерете полето Връзкаи го преместете в секцията Полетас помощта на бутона ">".
  • Заявката за артикул е готова, щракнете върху бутона „OK“ в долната част на прозореца на дизайнера.

Нека да видим какво представлява вложени заявкив и защо са необходими.
Често има ситуация, когато трябва да се извършат няколко последователни действия на маса. Доста илюстративен пример е, когато първо трябва и след това наложите някакво условие на групирана таблица или я свържете с друга таблица. В такива случаи те идват на помощ вложени заявки.

Вложената заявка практически не се различава от обикновената заявка. Той е ограден в скоби и в него са налични почти всички методи и функции на езика за заявки 1C. А за родителската заявка са налични всички полета на подзаявката.
Структурата на най-примитивната вложена заявка изглежда така:

ИЗБЕРЕТЕ ОТ (ИЗБЕРЕТЕ ОТ) КАТО NestedQuery

Разбира се, в тази форма използването на вложена заявка няма смисъл, защото Можете веднага да изберете необходимите полета, без да използвате влагане. Всичко тук е изключително опростено за по-лесно разбиране.

Сега нека разгледаме всичко по-горе, използвайки пример.
Нека имаме таблица EmployeesDivisions:

И искаме да изберем от тази таблица всички отдели, в които работят повече от един служител.

ИЗБЕРЕТЕ EmployeesDivisions.Division AS Division, NUMBER(EmployeesDivisions.Employee) AS Брой служители ОТ EmployeesDivisions AS EmployeesDivisions ГРУПИРАНЕ ПО EmployeesDivisions.Division

Ако изпълним тази заявка, ще получим следната таблица като резултат

Втората стъпка е да наложите ограничение за броя на служителите в тази таблица. За да направим това, ще направим горната заявка вложена и ще напишем съответното условие в по-горната заявка

ИЗБЕРЕТЕ NestedQuery.Unit AS Unit FROM (SELECT EmployeesUnits.Unit AS Unit, QUANTITY(EmployeesUnits.Employee) AS Number OfEmployees FROM EmployeesUnits AS EmployeesUnits GROUP BY EmployeesUnits.Unit) AS NestedQuery WHERE NestedQuery.NumberofEmployees > 1

Така резултатът от крайната заявка ще бъде както следва

За да бъдем честни, струва си да се отбележи, че същият резултат може да бъде постигнат с помощта на функцията ИМАЩ 1C език за заявки, както и използване на временни таблици.
На практика, разбира се, ще срещнете по-сложни вложени заявки, които могат да използват както таблици, така и таблици. Може да има и няколко нива на гнездене.

Реших да направя своя принос и да опиша тези характеристики на езика, които не бяха обсъдени в горните статии. Статията е насочена към начинаещи разработчици.

1. “IZ” дизайн.

За да получите данни от базата данни, изобщо не е необходимо да използвате конструкцията „ОТ“.
Пример: Трябва да изберем цялата информация за банките от указателя на банките.
Заявка:

ИЗБЕРЕТЕ Директория.Банки.*

Избира всички полета от директорията Банки. И е подобно на искането:

ИЗБЕРЕТЕ Банки.* ОТ Директория.Банки КАТО Банки

2. Подреждане на данни по референтно поле

Когато трябва да организираме данните на заявката по примитивни типове: "Низ", "Число", "Дата" и т.н., тогава всичко се решава с помощта на конструкцията "ORDER BY", ако трябва да подредите данните по референтно поле? Референтното поле е връзка, уникален идентификатор, т.е. Грубо казано, някакъв произволен набор от знаци и обикновено подреждане може да доведе до резултат, който не е напълно очакван. За подреждане на референтни полета се използва конструкцията "AUTO ORDER". За да направите това, първо трябва да подредите данните директно по референтния тип, като използвате конструкцията "ORDER BY", а след това конструкцията "AUTO ORDER".

В този случай за документи подреждането ще се извърши в реда "Дата->Номер", за справочници в "Основен изглед". Ако подреждането не се извършва чрез референтни полета, тогава използването на конструкцията "AUTO ORDER" не се препоръчва.

В някои случаи конструкцията "AUTO ORDER" може да забави процеса на избор. По подобен начин можете да пренапишете без автоматично подреждане на документи:

3.Получаване на текстово представяне от референтен тип. Дизайн "ПРЕЗЕНТАЦИЯ".

Когато трябва да покажете поле от референтен тип, например полето "Банка", което е връзка към елемент от директорията "Банки", трябва да разберете, че при показване на това поле, подзаявка към " Banks" ще се изпълни автоматично, за да се получи изглед на директорията. Това ще забави извеждането на данни. За да избегнете това, трябва да използвате конструкцията "PRESENTATION" в заявката, за да получите незабавно представяне на обекта и след това да го покажете за преглед.

В системата за съставяне на данни този механизъм се използва по подразбиране, но когато създавате оформления в клетки, трябва да посочите представянето на референтното поле и например да поставите самата връзка в преписа.

4. Условие за извадка на данните по образец.

Например, трябва да получите мобилни телефони на служители от формата (8 -123- 456-78-912). За да направите това, трябва да зададете следното условие в заявката:

ИЗБЕРЕТЕ Employee.Name, Employee.Phone AS Phone FROM Directory.Employees AS Employees WHERE Телефон LIKE "_-___-___-__-__"

Знакът "_" е служебен знак и замества всеки знак.

5. Едновременно използване на суми и групи.


Общите суми често се използват заедно с групирането; в този случай агрегатните функции може да не са посочени в общите суми.

ИЗБЕРЕТЕ Предоставяне на услуги. Организация КАТО Организация, Предоставяне на услуги. Номенклатура КАТО Номенклатура, SUM(Предоставяне на услуги. Сума на документа) КАТО Сума на документа ОТ Документ. Предоставяне на услуги КАТО Предоставяне на услуги ГРУПИРАНЕ ПО Предоставяне на услуги. Организация, Предоставяне на услугите. Номенклатура РЕЗУЛТАТИ ПО ОБЩИ, Организация, номенклатура

В този случай заявката ще върне почти същото като следната заявка:

ИЗБЕРЕТЕ Предоставяне на услуги. Организация КАТО Организация, Предоставяне на услуги. Номенклатура КАТО Номенклатура, Предоставяне на услуги. Сума на документа КАТО Сума на документа ОТ Документ. Предоставяне на услуги КАТО Предоставяне на услуги РЕЗУЛТАТИ СУМА (Сума на документа) ПО ОБЩО, Организация, Номенклатура

Само първата заявка ще свие записи със същата номенклатура.

6. Дерефериране на полета.

Обръщането към полета чрез точка се нарича операция за дерефериране на референтно поле. Например Разплащане.Организация.Административна единица. В този случай в справочното поле "Организация" на документ "Плащане" препраща към друга таблица "Организации", в която ще се получи стойността на атрибута "Административна единица". Важно е да се разбере, че при достъп до полета чрез точка платформата имплицитно създава подзаявка и обединява тези таблици.

Заявка:

Може да се представи като:

ИЗБЕРЕТЕ Плащане.Връзка, Плащане.Организация, Плащане.Организация, Организации. AdministrativeUnit FROM Document.Payment AS Payment LEFT JOIN Directory.Organizations AS Организации Софтуер Payment.Organization = Organisations.Link

При дерефериране на референтни полета от съставен тип, рамката се опитва да създаде имплицитни съединения към всички таблици, които са част от типа на това поле. В този случай заявката няма да бъде оптимална, ако е ясно какъв тип поле е, е необходимо да се ограничат такива полета по тип с конструкция ЕКСПРЕС().

Например има регистър за натрупване „Неразпределени плащания“, където няколко документа могат да действат като регистратор. В този случай е неправилно да се получат стойностите на данните на регистратора по този начин:

ИЗБЕРЕТЕ UnallocatedPayments.Registrar.Date, ..... ОТ RegisterAccumulation.UnallocatedPayments AS UnallocatedPayments

трябва да ограничите типа на съставното поле до logger:

SELECT EXPRESS(UnallocatedPayments.Register AS Document.Payment).Date, ..... FROM RegisterAccumulation.UnallocatedPayments AS UnallocatedPayments

7. Конструкция "КЪДЕ"

При ляво съединение на две таблици, когато наложите условие “WHERE” на дясната таблица, ще получим резултат, подобен на резултата с вътрешно съединение на таблици.

Пример. Необходимо е да се изберат всички Клиенти от Указател Клиенти и за тези клиенти, които имат платежен документ със стойност на атрибута "Организация" = &Организация, да се покаже документът "Плащане", за тези, които нямат, да не се показва.

Резултатът от заявката ще върне записи само за онези клиенти, които са имали плащане от организация в параметъра, и ще филтрира други клиенти. Следователно първо трябва да получите всички плащания за „такава и такава“ организация във временна таблица и след това да я свържете към директорията „Клиенти“, като използвате ляво съединение.

ИЗБЕРЕТЕ Payment.Link AS Payment, Payment.Shareholder AS Client PLACE toPayments FROM Document.Payment AS Payment WHERE Payment.Branch = &Branch; /////////////////////////////////////////////// // /////////////////////////// ИЗБЕРЕТЕ Clients.Link AS Client, ISNULL(tPayment.Payment, "") AS Плащане ОТ Директория .Clients AS Клиенти ЛЯВА ВРЪЗКА topayments AS topayments СОФТУЕР Clients.Link = topayments.Client

Можете да заобиколите това състояние по друг начин. Необходимо е да се наложи условие "WHERE" директно върху връзката между двете таблици. Пример:

ИЗБЕРЕТЕ Clients.Link, Payment.Link FROM Directory.US_Subscribers AS US_Subscribers ЛЯВА ВРЪЗКА Document.Payment AS софтуер за плащане (Clients.Link = Payment.Client И Payment.Client.Name КАТО "Sugar Packet") ГРУПИРАНЕ ПО Clients.Link, Payment. Връзка

8. Съединения с вложени и виртуални таблици

Вложени заявкичесто е необходимо за извличане на данни въз основа на някакво условие. Ако след това ги използвате заедно с други таблици, това може критично да забави изпълнението на заявката.

Например трябва да получим сумата на баланса към текущата дата за някои клиенти.

SELECT UnallocatedPaymentsBalances.Customer, UnallocatedPaymentsBalances.AmountBalance FROM (SELECT Clients.Link AS Link FROM Directory.Clients AS Clients WHERE Clients.Link IN(&Clients)) AS NestedQuery LEFT JOIN RegisterAccumulations.UnallocatedPayments.Balances AS UnallocatedPayments BY Nested nyRe quest.Link = UnallocatedPaymentsBalances. Клиент

При изпълнение на такава заявка оптимизаторът на СУБД може да направи грешки при избора на план, което ще доведе до неоптимално изпълнение на заявката. При свързване на две таблици оптимизаторът на СУБД избира алгоритъм за свързване на таблици въз основа на броя на записите в двете таблици. Ако има вложена заявка, е изключително трудно да се определи броят на записите, които вложената заявка ще върне. Следователно винаги трябва да използвате временни таблици вместо вложени заявки. Така че нека пренапишем заявката.

ИЗБЕРЕТЕ Clients.Link AS Link PLACE tClients FROM Directory.Clients AS Clients WHERE
Clients.Link B (&Клиенти) ; /////////////////////////////////////////////// // /////////////////////////// ИЗБЕРЕТЕ tClients.Link, UnallocatedPaymentsRemains.AmountRemaining, FROM tClients AS tClients LEFT JOIN RegisterAccumulations.UnallocatedPayments.Balances (, Client IN (SELECT tClients.Link FROM tClients)) AS UnallocatedPaymentsBalances tClients.Link = UnallocatedPaymentsBalances.Clients

В този случай оптимизаторът ще може да определи колко записа използва временната таблица tClients и ще може да избере оптималния алгоритъм за свързване на таблици.

Виртуални маси , ви позволяват да получите практически готови данни за повечето приложни задачи (част от първата, част от последната, остатъци, обороти, остатъци и обороти) Ключовата дума тук е виртуална. Тези таблици не са физически, а се съставят от системата в движение, т.е. При получаване на данни от виртуални таблици, системата събира данни от крайните регистърни таблици, асемблира, групира и ги издава на потребителя.

Тези. При свързване към виртуална таблица се осъществява връзка към подзаявка. В този случай оптимизаторът на СУБД може също да избере неоптимален план за свързване. Ако заявката не се генерира достатъчно бързо и заявката използва съединения във виртуални таблици, тогава се препоръчва да преместите достъпа до виртуалните таблици към временна таблица и след това да направите съединение между две временни таблици. Нека пренапишем предишната заявка.

ИЗБЕРЕТЕ Clients.Link AS Link PLACE tClients FROM Directory.Clients AS Clients INDEX BY Link WHERE
Clients.Link B (&Клиенти) ; /////////////////////////////////////////////// // /////////////////////////// ИЗБЕРЕТЕ UnallocatedPayments.AmountBalance, UnallocatedPayments.Client AS Client PLACE баланси ОТ RegisterAccumulations.UnallocatedPayments.Balances(, Client B ( SELECT tClients Link FROM tClients)) AS UnallocatedPaymentsBalances; /////////////////////////////////////////////// // /////////////////////////// ИЗБЕРЕТЕ tClients.Link, toRemainders.AmountRemaining AS AmountRemaining FROM tClients AS tClients LEFT JOIN toRemainders AS Remainders BY tClients.Link = tRemainings.Client

9. Проверка на резултата от заявката.

Резултатът от заявката може да е празен, използвайте следната конструкция:

ResRequest = Request.Execute(); If resQuery.Empty() Then Return; endIf;

Метод празен()трябва да се използва преди методите Избирам()или Разтоварване(), тъй като извличането на колекцията отнема време.

За никого не е откровение, че е изключително нежелателно да се използват заявки в цикъл. Това може критично да повлияе на времето за работа на определена функция. Много е желателно да получите всички данни в заявката и след това да ги обработите в цикъл. Но понякога има случаи, когато става невъзможно преместването на заявката извън цикъла. В този случай за оптимизация можете да преместите създаването на заявката извън цикъла и в цикъла да замените необходимите параметри и да изпълните заявката.

Заявка = Нова заявка; Query.Text = "SELECT | Clients.Link, | Clients.Birthdate |FROM | Directory.Clients AS Clients |WHERE | Clients.Link = &Client"; За всеки ред FROM TableClients Loop Query.SetParameter("Клиент", Клиент); QueryResult = Query.Execute().Select(); EndCycle;

Това ще спаси системата от проверка на синтаксиса на заявката в цикъл.

11. Конструкция "ИМАНЕ".

Дизайн, който е доста рядък в заявките. Позволява ви да налагате условия върху стойностите на агрегатните функции (СУМА, МИНИМУМ, СРЕДНО и т.н.). Например, трябва да изберете само онези клиенти, чиято сума на плащането през септември е над 13 000 рубли. Ако използвате условието „WHERE“, първо ще трябва да създадете временна таблица или вложена заявка, да групирате записите там по сума на плащането и след това да приложите условието. Конструкцията “HAVING” ще помогне да се избегне това.

ИЗБЕРЕТЕ Payment.Customer, AMOUNT(Payment.Amount) AS Amount FROM Document.Payment AS Payment WHERE MONTH(Payment.Date) = 9 GROUP BY Payment.Customer HAVING AMOUNT(Payment.Amount) > 13000

В конструктора, за да направите това, просто отидете в раздела „Условия“, добавете ново условие и поставете отметка в квадратчето „По избор“. Тогава просто пишете Сума(Плащане.Сума) > 13000


12. NULL стойност

Тук няма да описвам принципите на тризначната логика в базата данни; има много статии по тази тема. Само накратко как НУЛАможе да повлияе на резултата от заявката. Стойността NULL всъщност не е стойност и фактът, че стойността е недефинирана, е неизвестен. Следователно всяка операция с NULL връща NULL, било то събиране, изваждане, деление или сравнение. NULL стойност не може да бъде сравнена с NULL стойност, защото не знаем какво да сравним. Тези. и двете сравнения са: NULL = NULL, NULL<>NULL не е True или False, не е известно.

Нека разгледаме един пример.

За тези клиенти, които нямат плащания, трябва да покажем полето „Подпис“ със стойност „Няма плащания“. Освен това знаем със сигурност, че имаме такива клиенти. И за да отразя същността на това, което написах по-горе, нека го направим по този начин.

ИЗБЕРЕТЕ „Без плащания“ AS Attribute, NULL AS Document PLACE topayments; /////////////////////////////////////////////// // /////////////////////////// ИЗБЕРЕТЕ Clients.Link AS Client, Payment.Link HOW Payment PUT tClientPayment FROM Directory.Clients AS Clients LEFT CONNECTION Document. Payment AS Payment Software Clients.Link = Payment.Shareholder; /////////////////////////////////////////////// // //////////////////////// ИЗБЕРЕТЕ tClientPayment.Client ОТ tClientPayment КАТО tClientPayment ВЪТРЕШНО ПРИСЪЕДИНЯВАНЕ към tPayment КАТО tTopay ОТ tClientPayment.Payment = tPayment

Обърнете внимание на втората временна таблица tClientPayment. С лявото присъединяване избирам всички клиенти и всички плащания за тези клиенти. За тези клиенти, които нямат плащания, полето „Плащане“ ще бъде NULL. Следвайки логиката, в първата временна таблица “tPayments” обозначих 2 полета, едното от тях NULL, вторият ред “Не разполага с плащания”. В третата таблица свързвам таблиците „tClientPayment“ и „tPayment“, като използвам полетата „Payment“ и „Document“ с вътрешно съединение. Знаем, че в първата таблица полето „Документ“ е NULL, а във втората таблица тези, които нямат плащания в полето „Плащане“ също са NULL. Какво ще ни върне подобна връзка? Но няма да върне нищо. Тъй като сравнението NULL = NULL не се оценява на True.

За да може заявката да върне очаквания резултат, нека я пренапишем:

ИЗБЕРЕТЕ „Без плащания“ AS Attribute, VALUE(Document.Payment.EmptyLink) AS Document PLACE toPayments; /////////////////////////////////////////////// // //////////////////////////// ИЗБЕРЕТЕ Clients.Link AS Client, ISNULL(Payment.Link, VALUE(Document.Payment.EmptyLink )) КАК Плащане PUT tClientPayment FROM Directory.Clients AS Clients LEFT CONNECTION Document.Payment AS Payment BY Clients.Link = Payment.Shareholder; /////////////////////////////////////////////// // //////////////////////// ИЗБЕРЕТЕ tClientPayment.Client ОТ tClientPayment КАТО tClientPayment ВЪТРЕШНО ПРИСЪЕДИНЯВАНЕ към tPayment КАТО tTopay ОТ tClientPayment.Payment = tPayment

Сега във втората временна таблица сме посочили, че ако полето „Плащане“ е NULL, тогава това поле = празна връзка към платежния документ. В първата таблица също заменихме NULL с празна препратка. Сега връзката включва не-NULL полета и заявката ще върне очаквания резултат.

Всички искания, съдържащи се в статията, отразяват ситуациите, които бих искал да разгледам и нищо повече. ОТНОСНО Те може да не са заблуди или неоптимални, основното е, че отразяват същността на примера.

13. Недокументирана характеристика на дизайна "ИЗБОР КОГАТО...ТОГДА...КРАЙ".

В случай, че е необходимо да опишем конструкцията „Условия“ в заявката, използваме стандартния синтаксис:

SELECT SELECTION WHEN Users.Name = "Vasya Pupkin" THEN "Нашият любим служител" ELSE "Ние не знаем това" END AS Field1 FROM Directory.Users AS Users

Но какво ще стане, ако например трябва да получим името на месеца в заявка? Писането на огромна конструкция в заявка е грозно и отнема много време, така че тази форма на писане по-горе може да ни помогне:

ИЗБЕРЕТЕ МЕСЕЦ(US_CalculationConsumption_TurnoverSchedule.CalculationPeriod) WHEN 1 THEN "Януари" WHEN 2 THEN "February" WHEN 3 THEN "March" WHEN 4 THEN "April" WHEN 5 THEN "May" WHEN 6 THEN "June" WHEN 7 THEN "July" WHEN 8 ТОГАВА „Август“ КОГАТО 9 ТОГАВА „Септември“ КОГАТО 10 ТОГАВА „Октомври“ КОГАТО 11 ТОГАВА „Ноември“ КОГАТО 12 ТОГАВА „Декември“ КРАЙ КАТО месец

Сега дизайнът изглежда по-малко тромав и е лесен за разбиране.

14. Пакетно изпълнение на заявка.


За да не се умножават заявките, можете да създадете една голяма заявка, да я разделите на пакети и да работите с нея.
Например, трябва да получа следните полета от директорията „Потребители“: „Дата на раждане“ и наличните роли за всеки потребител. качете това в различни таблични части на формуляра. Разбира се, можете да направите това с една заявка, след което ще трябва да преминете през записите или да ги свиете, или можете да направите следното:

ИЗБЕРЕТЕ Users.Link AS пълно име, Users.Date of Birth, Users.Role PUT vtUsers FROM Directory.Users AS Users; /////////////////////////////////////////////// // /////////////////////////// ИЗБЕРЕТЕ tueUsers.Пълно име, tueUsers.Дата на раждане ОТ tueUsers КАТО tueUsers ГРУПИРАНЕ ПО tueUsers.пълно име, tueUsers . Дата на раждане; /////////////////////////////////////////////// // //////////////////////// ИЗБЕРЕТЕ wUsers.Пълно име, wUsers.Роля ОТ wUsers AS wUsers GROUP BY wUsers.Пълно име, wUsers Дата на раждане

tPackage = Request.ExecutePackage();

TP_BirthDate = tPackage.Upload();
TP_Roles = tPackage.Unload();

Както виждаме, заявката може да бъде изпълнена групово и резултатът да бъде обработен като масив. В някои случаи е много удобно.

15. Условия в пакетна заявка

Например, имаме пакетна заявка, където първо получаваме полетата: „Име, дата на раждане, код“ от директорията „Потребители“ и искаме да получим записи с условия за тези полета от директорията „Лични лица“.

ИЗБЕРЕТЕ Users.Individual.Name AS Име, Users.Individual.Date of Birth AS Дата на раждане, Users.Individual.Code AS Code PLACE vtUsers FROM Directory.Users AS Users; /////////////////////////////////////////////// // ///////////////////// ИЗБЕРЕТЕ ЛИЦА КАТО ФИЗИЧЕСКИ ЛИЦА ОТ Директория

Можете да наложите такива условия:

WHERE Individuals.Code IN (SELECT vtUsers.Code FROM vtUsers) И Individuals.Name IN (SELECT vtUsers.Code FROM vtUsers) AND Individuals.BirthDate IN (SELECT vtUsers.DateBirth FROM tvUsers)

И можете да го направите така:

WHERE (Individuals.Code, Individuals.Name, Individuals.Date of Birth) IN (ИЗБЕРЕТЕ tueUsers.Code, tueUsers.Name, tueUsers.Дата на раждане ОТ tueUsers)

Освен това е необходимо да се поддържа ред.

16. Извикване на конструктора на заявки за „условие“ в групова заявка

Когато е необходимо да наложите условие, както в примера по-горе, можете да забравите как се извиква това или онова поле във виртуалната таблица.
Например, трябва да поставите условие в полето "Дата на раждане", а във виртуалната таблица това поле се нарича "Дата на раждане на длъжника" и ако забравите името, ще трябва да излезете от редактирането на условието без запазване и вижте името на полето. За да избегнете това, можете да използвате следната техника.

Необходимо е да поставите скоби след конструкцията “B” и да оставите празно пространство (интервал) между скобите, да изберете това пространство и да извикате конструктора на заявката. Дизайнерът ще има достъп до всички таблици на груповата заявка. Техниката работи както на виртуални регистрационни таблици, така и на раздела „Условия“. В последния случай трябва да поставите отметка в квадратчето „P (произволно условие)“ и да влезете в режим на редактиране „F4“.

Заявките често бяха измислени в движение и те просто служат за илюстрация на „техниките“, които обмислях.

Исках да разгледам използването на индекси в заявки, но това е много обширна тема. Ще го поставя в отделна статия или ще го добавя тук по-късно.

upd1. Точки 11,12
upd2. Точки 13,14,15,16

Използвани книги:
Език за заявки "1C:Enterprise 8" - E.Yu. Хрусталева
Професионално развитие в системата 1C:Enterprise 8."

изгледи