Создание большой виртуальной таблицы в предложении FROM. Sql виртуальная таблица


SQL Views

Представление - это виртуальная таблица.

В этой статье показано: как создавать, обновлять и удалять представления.

Создание Представления

В SQL представления создаются с помощью SQL запроса.

Представление содержит колонки и строки, как в реальных таблицах. Представление создается на основе существующих таблиц.

Вы можете добавлять SQL функции, WHERE и JOIN запросы, как если бы получали данные из одной таблицы.

Синтаксис SQL CREATE VIEW

- Замечание: Представление всегда показывает актуальные данные!

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

Создадим представление "Current Product List" на основе таблицы Products. Для этого выберем колонки ProductID, ProductName с условием WHERE Discontinued=No:

1 2 3 4 CREATE VIEW [Current Product List] AS SELECT ProductID,ProductName FROM Products WHERE Discontinued=No

Теперь посмотрим на созданную виртуальную таблицу:

Обновление Представления

Для обновления представления используйте следующий синтаксис:

1 2 3 4 CREATE OR REPLACE VIEW view_name AS SELECT column_name(s) FROM table_name WHERE condition

Итак, мы хотим добавить новую колонку "Category" в представление "Current Product List". Для этого используем такой запрос:

1 2 3 4 CREATE VIEW [Current Product List] AS SELECT ProductID,ProductName,Category FROM Products WHERE Discontinued=No

Удаление представления

Представление удаляется с помощью запроса DROP VIEW.

Синтаксис SQL DROP VIEW

dimonchik.com

sql - Создание большой виртуальной таблицы в предложении FROM

Задний план

У меня есть приложение Java, которое периодически принимает набор результатов из одной базы данных (MySQL) и пытается найти совпадения в другой базе данных (в частности, Postgres/PostGIS).

проблема

В настоящее время приложение запрашивает базу данных Postgres раз навсегда запись MySQL в результирующем наборе (может превышать десятки тысяч). Я пытаюсь изменить алгоритм так, чтобы приложение генерировало один единственный запрос, который дает несколько результатов, если найдено совпадение. Другой способ описать мою цель состоит в том, что запрос должен вести себя аналогично типичному JOIN, если эти две таблицы существуют в одной системе баз данных.

Текущее решение

Чтобы решить эту проблему, я создаю виртуальную таблицу в предложении FROM. Однако единственный способ, которым я знаю, как это сделать из списка значений, - написать отдельные SELECT соединенные с UNION. Результат, похоже, работает, и пока я не тестировал производительность с тысячами записей, он, похоже, не оказывает большого влияния, используя сотни таких SELECT UNION. Это соответствующая часть общего запроса, чтобы проиллюстрировать, что я сделал до сих пор:

SELECT *, ST_Distance_Sphere(latlng, geom) as distance FROM rwis_sites INNER JOIN (SELECT 1100 as unit_id, ST_GeomFromText('POINT(-81.19701 32.09279)', 4326) as geom UNION SELECT 1100 as unit_id, ST_GeomFromText('POINT(-81.19682 32.09224)', 4326) as geom UNION SELECT 1100 as unit_id, ST_GeomFromText('POINT(-81.1968 32.09213)', 4326) as geom UNION ... just a few more...hundred...thousand... SELECT 2266 as unit_id, ST_GeomFromText('POINT(-97.98719 29.57656)', 4326) as geom UNION SELECT 2266 as unit_id, ST_GeomFromText('POINT(-97.98815 29.57602)', 4326) as geom ) virtualTable ON ST_Distance_Sphere(latlng, geom) < 10000 ORDER BY ST_Distance_Sphere(latlng, geom) ASC limit 1

Поскольку "виртуальная таблица" генерируется программно, с моей стороны мало усилий.

Вопрос

Тем не менее, меня беспокоит, является ли это "тупой" подход (не говоря уже о каких-либо проблемах с производительностью, которые я еще не обнаружил), и в конечном итоге мне интересно: есть ли лучший способ создания чего-то подобного без тысяч SELECT UNION заявления?

qaru.site

Проблемы создания виртуальной таблицы. SQL

Форум: "Базы";Поиск по всему сайту: www.delphimaster.net;Текущий архив: 2003.11.27;Скачать: [xml.tar.bz2];

Вниз

Проблемы создания виртуальной таблицы. SQL 
Мыш   (2003-11-09 23:33) [0]

Задача такая: нужно выбрать все записи из набора но не последовательно, а случайным образом. При этом нельзя выбириать запись дважды, и в итоге все записи должны быть выбраны. Я подумал, что лучшим способом будет делать LOCATE по нумерованному полю с помощью random, а затем удалять запись, чтобы не мешалась. Т.к. это мой первый опыт работы с базой данных и SQL, то выбор решений у меня небольшой - подумал что лучшим вариантом будет создать виртуальную таблицу и выбирать записи по ней, чтобы удаления не сказались на реальной таблице. Но борландовский DatabaseEngine выдает сообщение Capability not supported на академический запрос, сделанный по образу и подобию примерного запроса из книги по SQL. запрос такой: CREATE VIEW temp_table AS SELECT num, word FROM table1 Вообще то нужно создать виртуальную таблицу из нескольких реальных, (Запрос: CREATE VIEW temp_table AS SELECT num, word FROM table1 UNION SELECT num, word FROM table2 но там другая ошибка "Invalid use of keyword token UNION"

зы Сорри, что столько накатал, спасибо уж если кто до конца дочитал, просто почему-то не получается сказать коротко и ясно :)

Johnmen   (2003-11-10 09:18) [1]

Если в НД есть уникальное поле, то задача к базам данных отношения не имеет...:) Чистая алгоритмика...

Мыш   (2003-11-10 09:27) [2]

Да, но набор то получить еще надо. Можно конечно перебирать все таблицы по очереди, но ведь вроде можно создать одну из всех и ее просматривать, так лаконичнее будет

Johnmen   (2003-11-10 09:34) [3]

>...записи из набора ...

Так мы что перебираем то ?

Sergey13   (2003-11-10 09:55) [4]

2Мыш © (09.11.03 23:33) А если не секрет, зачем такие хитрости? Обычно упорядочивают наборы, а ты наоборот.

Bob   (2003-11-10 11:13) [5]

LocalSQL не поддерживает виртуальные таблицы

Форум: "Базы";Поиск по всему сайту: www.delphimaster.net;Текущий архив: 2003.11.27;Скачать: [xml.tar.bz2];

Наверх

EMAIL={{}};LOGIN={{Мыш}};TITLE={{Проблемы создания виртуальной таблицы. SQL}};ATTRIBUTES={{}};ID_MSG={{709076}};ID_GROUP={{3}};ID_NNTP={{129872}};ID_DM={{89721}};REPLYNR={{0}};ID_DM_AUTHOR={{0}};ARCHIVE={{2003.11.27}};REPLYDATE={{2003-11-09 23:33}};CNT={{5}};

Память: 0.75 MBВремя: 0.028 c

www.delphimaster.net

mysql - Виртуальная таблица MySQL LEFT OUTER JOIN

Я работаю над довольно сложным запросом, чтобы попытаться объяснить это вам. Вот таблицы, которые у меня есть в моей базе данных MySQL:

Таблица студентов

--- 'students' --- student_id first_name last_name current_status status_change_date ------------ ------------ ----------- ---------------- -------------------- 1 John Doe Active NULL 2 Jane Doe Retread 2012-02-01

students_have_courses Таблица

--- 'students_have_courses' --- students_student_id courses_course_id s_date e_date int_date --------------------- ------------------- ---------- ---------- ----------- 1 1 2012-01-01 2012-01-04 2012-01-05 1 2 2012-01-05 NULL NULL 2 1 2012-01-10 2012-01-11 NULL

students_have_optional_courses Таблица

--- 'students_have_optional_courses' --- students_student_id optional_courses_opcourse_id s_date e_date --------------------- ------------------------------ ---------- ---------- 1 1 2012-01-02 2012-01-03 1 1 2012-01-06 NULL 1 5 2012-01-07 NULL

Вот мой запрос до сих пор

SELECT 'students_and_courses'.student_id, 'students_and_courses'.first_name, 'students_and_courses'.last_name, 'students_and_courses'.courses_course_id, 'students_and_courses'.s_date, 'students_and_courses'.e_date, 'students_and_courses'.int_date, 'students_have_optional_courses'.optional_courses_opcourse_id, 'students_have_optional_courses'.s_date, 'students_have_optional_courses'.e_date FROM ( SELECT 'c_s_a_s'.student_id, 'c_s_a_s'.first_name, 'c_s_a_s'.last_name, 'c_s_a_s'.courses_course_id, 'c_s_a_s'.s_date, 'c_s_a_s'.e_date, 'c_s_a_s'.int_date FROM ( SELECT 'students'.student_id, 'students'.first_name, 'students'.last_name, 'students_have_courses'.courses_course_id, 'students_have_courses'.s_date, 'students_have_courses'.e_date, 'students_have_courses'.int_date FROM 'students' LEFT OUTER JOIN 'students_have_courses' ON ( 'students_have_courses'.'students_student_id' = 'students'.'student_id' AND (( 'students_have_courses'.'s_date' >= 'students'.'status_change_date' AND 'students'.current_status = 'Retread' ) OR 'students'.current_status = 'Active') ) WHERE 'students'.current_status = 'Active' OR 'students'.current_status = 'Retread' ) 'c_s_a_s' ORDER BY 'c_s_a_s'.'courses_course_id' DESC ) 'students_and_courses' LEFT OUTER JOIN 'students_have_optional_courses' ON ( 'students_have_optional_courses'.students_student_id = 'students_and_courses'.student_id AND 'students_have_optional_courses'.s_date >= 'students_and_courses'.s_date AND 'students_have_optional_courses'.e_date IS NULL ) GROUP BY 'students_and_courses'.student_id;

То, что я хочу вернуть, - это имя student_id, first_name и last_name для всех участников Active или Retread, а затем LEFT JOIN - высший курс course_id, s_date, e_date и int_date для тех студентов, где s_date имеет статус status_change_date, если статус "Retread" ". Затем LEFT присоединяйтесь к наивысшим параметрам optional_courses_opcourse_id, s_date и e_date из students_have_optional_courses TABLE, где student_have_optional_courses.s_date больше или равно student_have_courses.s_date, а students_have_optional_courses.e_date IS NULL

Вот что возвращается:

student_id first_name last_name courses_course_id s_date e_date int_date optional_courses_opcourse_id s_date_1 e_date_1 ------------ ------------ ----------- ------------------- ---------- ---------- ------------ ------------------------------ ---------- ---------- 1 John Doe 2 2012-01-05 NULL NULL 1 2012-01-06 NULL 2 Jane Doe NULL NULL NULL NULL NULL NULL NULL

Вот что мне нужно вернуть:

student_id first_name last_name courses_course_id s_date e_date int_date optional_courses_opcourse_id s_date_1 e_date_1 ------------ ------------ ----------- ------------------- ---------- ---------- ------------ ------------------------------ ---------- ---------- 1 John Doe 2 2012-01-05 NULL NULL 5 2012-01-07 NULL 2 Jane Doe NULL NULL NULL NULL NULL NULL NULL

Все работает, кроме одного, я не могу получить наивысшие students_have_optional_courses.optional_courses_opcourse_id независимо от того, как я формирую запрос

Извините, я просто решил это сам, написав все это, я думаю, это помогло мне подумать о решении.

Вот запрос решения:

SELECT 'students_and_courses'.student_id, 'students_and_courses'.first_name, 'students_and_courses'.last_name, 'students_and_courses'.courses_course_id, 'students_and_courses'.s_date, 'students_and_courses'.e_date, 'students_and_courses'.int_date, 'students_optional_courses'.optional_courses_opcourse_id, 'students_optional_courses'.s_date, 'students_optional_courses'.e_date FROM ( SELECT 'c_s_a_s'.student_id, 'c_s_a_s'.first_name, 'c_s_a_s'.last_name, 'c_s_a_s'.courses_course_id, 'c_s_a_s'.s_date, 'c_s_a_s'.e_date, 'c_s_a_s'.int_date FROM ( SELECT 'students'.student_id, 'students'.first_name, 'students'.last_name, 'students_have_courses'.courses_course_id, 'students_have_courses'.s_date, 'students_have_courses'.e_date, 'students_have_courses'.int_date FROM 'students' LEFT OUTER JOIN 'students_have_courses' ON ( 'students_have_courses'.'students_student_id' = 'students'.'student_id' AND (( 'students_have_courses'.'s_date' >= 'students'.'status_change_date' AND 'students'.current_status = 'Retread' ) OR 'students'.current_status = 'Active') ) WHERE 'students'.current_status = 'Active' OR 'students'.current_status = 'Retread' ) 'c_s_a_s' ORDER BY 'c_s_a_s'.'courses_course_id' DESC ) 'students_and_courses' LEFT OUTER JOIN ( SELECT * FROM 'students_have_optional_courses' ORDER BY 'students_have_optional_courses'.optional_courses_opcourse_id DESC ) 'students_optional_courses' ON ( 'students_optional_courses'.students_student_id = 'students_and_courses'.student_id AND 'students_optional_courses'.s_date >= 'students_and_courses'.s_date AND 'students_optional_courses'.e_date IS NULL ) GROUP BY 'students_and_courses'.student_id;

qaru.site

Регистры накопления. Виртуальные таблицы. Часть №1: Обороты.

Виртуальные таблицы

В статье "Регистры накопления. Структура хранения в базе данных" мы рассматривали таблицы, которые использует платформа для хранения движений в регистрах накопления, а также его итоговых оборотов или остатков в зависимости от вида регистра ("Остатки" или "Обороты"). Также были подробно рассмотрены действия платформы с таблицами остатков и оборотов при записи движений в регистр. Сегодня в статье проанализируем SQL-запросы, формируемые платформой, при обращении к виртуальным таблицам регистра. Напомню, что у регистров накопления существует всего три виртуальных таблицы:
Физические и виртуальные таблицы в зависимостиот вида регистра ("Остатки" или "Обороты")
Как мы видим, кроме физической таблицы движений, для которой в базе данных создается отдельная таблица, также имеются виртуальные таблицы. Всего их три:
  1. "Обороты".
  2. "Остатки".
  3. "Остатки и обороты".

Последние две становятся доступными только если вид регистра установлен как "Остатки". 

Главное отличие виртуальных таблиц от физических: виртуальные таблицы не хранятся непосредственно в базе данных. При выборке данных из виртуальной таблицы платформа формирует некоторый запрос в зависимости от переданных параметров, который может получать записи из двух и более таблиц для формирования конечного результата.

Далее в статье проанализируем SQL-запросы платформы 1С:Предприятие 8.2 при обращении к виртуальной таблицам. При этом будем выполнять запросы при различных комбинациях параметров.

Сторона СУБД

Отмечу, что для экспериментов использовал простую тестовую конфигурацию, ссылка на которую приведена в конце статьи. В конфигурации созданы два регистра накопления различного вида, а также два документа для выполнения + и - движений по регистрам. Узнать подробнее о составе объектов тестовой конфигурации Вы можете либо скачав файл конфигурации, либо прочитав статью "Регистры накопления. Структура хранения в базе данных". Используемая версия платформы 8.2.17.153.
Объекты метаданных тестовой конфигурации

Начнем анализ с виртуальной таблицы "Обороты", так как она присутствует вне зависимости от вида регистра.

Виртуальная таблица "Обороты"

Виртуальная таблица "Обороты" есть, как у регистра накопления с видом "Обороты", так и с видом "Остатки". Рассмотрим оба варианта. Начнем с последнего.

Вид регистра "Остатки"

Посмотрим состав полей таблицы оборотов на примере регистра "ОстаткиНоменклатуры".

В нем содержатся поля каждого из измерений, а также поля "Приход", "Расход" и "Оборот" для каждого из ресурсов в регистре. В нашем случае у нас два измерения ("Номенклатура" и "Склад"), а также три поля "КоличествоПриход", "КоличествоРасход" и "КоличестоОборот".
Поля виртуальной таблицы "Обороты"
Главной особенностью любой виртуальной таблицы является возможность указать параметры. Установленные параметры кардинальным образом могут изменить SQL-запрос платформы к базе данных, поэтому понимать их назначение - это обязанность любого разработчика на платформе 1С:Предприятие.
Параметры виртуальной таблицы "Обороты"в конструкторе запросов
В зависимости от установленного параметра "Периодичность" в состав доступных полей вирт. таблицы будут добавляться соответствующие периоды ("ПериодДень", "ПериодМесяц" и т.д.).

Теперь напишем простой запрос для получения оборотов по номенклатуре за период. В параметрах виртуальной таблицы установим поля "НачалоПериода" и "КонецПериода", а в условия добавим отбор по складу "Склад №1". При выполнении запроса платформа сформирует два SQL-запроса к базе данных. Первый запрос получает настройки регистра накопления:

Запрос к параметрам регистра накопления при обращениик виртуальной таблице "Обороты"
Используя эти настройки, платформа формирует SQL-запрос непосредственно на получение оборотов. Вот так выглядит SQL-запрос платформы для получения оборотов:"exec sp_executesql N' |SELECT"+ // Поля виртуальной таблицы ""Обороты"" " T1.Fld22RRef, // Номенклатура | T1.Fld23RRef, // Склад | T1.Fld24Turnover_,// КоличествоОборот | T1.Fld24Receipt_, // КоличествоПриход | T1.Fld24Expense_ // КоличествоРасход"+ // Получаем обороты с помощью вложенного запроса "FROM ("+ // -- Начало вложенного запроса -- " SELECT | T2._Fld23RRef AS Fld23RRef, // Склад | T2._Fld22RRef AS Fld22RRef, // Номенклатура"+ // Если вид записи (""RecordKind"") равно 0, тогда это ""Приход"", // иначе ""Расход"". ""Приход"" берется положительным, ""Расход"" // с отрицательным знаком. // 1. Поле ""КоличествоОборот"" получает значение оборота с // соответствующим знаком. Значение поля суммируется // в разрезе группировок " CAST(SUM(CASE WHEN T2._RecordKind = 0.0 | THEN T2._Fld24 | ELSE -T2._Fld24 END | ) AS NUMERIC(22, 8)) AS Fld24Turnover_,"+ // 2. Поле ""КоличествоПриход"" формируется по тому же принципу, // за исключением случаев для вида записи ""Расход"". Для него // берется значение 0. " CAST(SUM(CASE WHEN T2._RecordKind = 0.0 | THEN T2._Fld24 | ELSE 0.0 END) AS NUMERIC(22, 8) | ) AS Fld24Receipt_,"+ // 3. Поле ""КоличествоРасход"". Формируется по тем же принципам, // что и предыдущие поля, за исключением вида записи ""Приход"". // Для нее берется значение 0. " CAST(SUM(CASE WHEN T2._RecordKind = 0.0 | THEN 0.0 | ELSE T2._Fld24 END | ) AS NUMERIC(22, 8)) AS Fld24Expense_"+ // Для получения данных по оборотам для регистра вида ""Остатки"" // используется таблица движений регистра ""AccumRg[n]"" " FROM _AccumRg21 T2 WITH(NOLOCK)"+ // Во вложенном запросе в секции ""WHERE"" указываются отборы // в соответствии с установленными параметрами виртуальной таблицы. " WHERE T2._Period >= @P1 // НачалоПериода | AND T2._Period <= @P2 // ОкончаниеПериода | AND T2._Active = @P3 // Активность | AND ((T2._Fld23RRef = @P4)) // Условие отбора по складу"+ // Группировки результата вложенного запроса по полям: " GROUP BY T2._Fld23RRef, // Склад | T2._Fld22RRef // Номенклатура"+ // Условия отбора во вложенном запросе на сгруппированный результат // Проверяется, чтобы хотя бы один из выбираемых ресурсов // (""КоличествоОборот"", ""КоличествоПриход"", ""КоличествоРасход"") // не равнялся значению 0. " HAVING (CAST(SUM(CASE WHEN T2._RecordKind = 0.0 | THEN T2._Fld24 | ELSE -T2._Fld24 END | ) AS NUMERIC(22, 8))) <> @P5 | OR (CAST(SUM(CASE WHEN T2._RecordKind = 0.0 | THEN T2._Fld24 | ELSE 0.0 END | ) AS NUMERIC(22, 8))) <> @P5 | OR (CAST(SUM(CASE WHEN T2._RecordKind = 0.0 | THEN 0.0 | ELSE T2._Fld24 END | ) AS NUMERIC(22, 8))) <> @P5"+ // -- Окончание вложенного запроса -- " ) T1', // Присваиваем синоним для таблицы, в | // которую поместим результат вложеного запроса"+ // Установим типы и значения параметров, передаваемых в запрос "N'@P1 datetime, // Параметр ""НачалоПериода"" |@P2 datetime, // ""КонецПериода"" |@P3 varbinary(1), // Активность записи, т.е. влияет ли она на итоги |@P4 varbinary(16),// Парам. ""Склад"", используемый в парам. вирт. таблицы |@P5 numeric(1,0)',// Значение для проверки ресурсов на знач. 0. |{ts '4013-01-01 00:00:00'}, // Значение ""НачалоПериода"" |{ts '4014-01-01 00:00:00'}, // ""КонецПериода"" |0x01, // Активность записи |0xBE923860773387FD11E2D2B47CD2CB1E, |0 // Проверка на знач. 0 для ресурсов |" Старался подробно закомментировать весь запрос. Если будут непонятные моменты, то прошу в комментарии. Исходный текст запроса на языке 1С:Предприятия выглядит следующим образом:Запрос = Новый Запрос; Запрос.Текст = "ВЫБРАТЬ | ОстаткиНоменклатурыОбороты.Номенклатура, | ОстаткиНоменклатурыОбороты.Склад, | ОстаткиНоменклатурыОбороты.КоличествоОборот, | ОстаткиНоменклатурыОбороты.КоличествоПриход, | ОстаткиНоменклатурыОбороты.КоличествоРасход |ИЗ | РегистрНакопления.ОстаткиНоменклатуры.Обороты( | &НачалоПериода, | &КонецПериода, | , Склад = &Склад) | КАК ОстаткиНоменклатурыОбороты"; В случае, если для виртуальной таблицы также устанавливается параметр "Периодичность", например, в значение "Месяц", то SQL-запрос немного видоизменится: "exec sp_executesql N' |SELECT"+ // Новое поле "Period" ("Период") " T1.Period_, | T1.Fld22RRef, | T1.Fld23RRef, | T1.Fld24Turnover_, | T1.Fld24Receipt_, | T1.Fld24Expense_ |FROM ( | SELECT"+ // Получаем период во вложенном запросе вместе с остальными данными. // Значение периода вычисляется из таблицы движений "AccumRg[n] // преобразуется к началу периода в зависимости от периодичности. // Например, для периодичности "Месяц" период приводится к началу // этого месяца. Также учитывается тот факт, что в таблице движений // год в значении периода больше текущего года на 2000 лет. " DATEADD(DAY,1.0 - 1,DATEADD(MONTH,CAST(DATEPART(MONTH,T2._Period) | AS NUMERIC(4)) - 1,DATEADD(YEAR,(CAST(DATEPART(YEAR,T2._Period) | AS NUMERIC(4)) - 2000) - 2000,{ts ''4000-01-01 00:00:00''}))) | AS Period_, | T2._Fld22RRef AS Fld22RRef, | T2._Fld23RRef AS Fld23RRef, | CAST(SUM(CASE WHEN T2._RecordKind = 0.0 | THEN T2._Fld24 | ELSE -T2._Fld24 END) | AS NUMERIC(22, 8)) AS Fld24Turnover_, | CAST(SUM(CASE WHEN T2._RecordKind = 0.0 | THEN T2._Fld24 | ELSE 0.0 END) | AS NUMERIC(22, 8)) AS Fld24Receipt_, | CAST(SUM(CASE WHEN T2._RecordKind = 0.0 | THEN 0.0 | ELSE T2._Fld24 END) | AS NUMERIC(22, 8)) AS Fld24Expense_ | FROM _AccumRg21 T2 WITH(NOLOCK) | WHERE T2._Period >= @P1 | AND T2._Period <= @P2 | AND T2._Active = @P3 | AND ((T2._Fld23RRef = @P4)) | GROUP BY "+ // Для получения оборотов в соответствии с заданной периодичностью // результат вложенного запроса группируется по полю период и по // другим измерениям. " DATEADD(DAY,1.0 - 1,DATEADD(MONTH,CAST(DATEPART(MONTH,T2._Period) | AS NUMERIC(4)) - 1,DATEADD(YEAR,(CAST(DATEPART(YEAR,T2._Period) | AS NUMERIC(4)) - 2000) - 2000,{ts ''4000-01-01 00:00:00''}))), | T2._Fld22RRef, | T2._Fld23RRef | HAVING ( | CAST(SUM(CASE WHEN T2._RecordKind = 0.0 | THEN T2._Fld24 | ELSE -T2._Fld24 END) AS NUMERIC(22, 8))) <> @P5 | OR (CAST(SUM(CASE WHEN T2._RecordKind = 0.0 | THEN T2._Fld24 | ELSE 0.0 END) AS NUMERIC(22, 8))) <> @P5 | OR (CAST(SUM(CASE WHEN T2._RecordKind = 0.0 | THEN 0.0 | ELSE T2._Fld24 END) AS NUMERIC(22, 8))) <> @P5 | ) T1', |N'@P1 datetime, |@P2 datetime, |@P3 varbinary(1), |@P4 varbinary(16), |@P5 numeric(1,0)', |{ts '4013-01-01 00:00:00'}, |{ts '4014-01-01 00:00:00'}, |0x01, |0xBE923860773387FD11E2D2B47CD2CB1E, 0"

Если в виртуальной таблице периодичность установлена "Авто", то в SQL-запросе будут содержаться поля периода для каждой из получаемой в запросе периодичности ("День", "Месяц", "Год" и т.д.). Причина, по которой платформа хранит значения периода с увеличением части даты "Год" на 2000 лет мне не известна. Если кто из читателей подскажет, буду благодарен.

Мы с Вами рассмотрели SQL-запросы платформы при работе с виртуальной таблицей "Обороты" регистра накопления с видом "Остатки". Как мы видим, виртуальная таблица "Обороты" в этом случае берет данные из таблицы движений регистра. Даже, если обороты в запросе получаются за несколько месяцев, необходимые данные будут также формироваться по таблице движений без использования каких-либо сохраненных ранее итогов. И это понятно, регистр накопления с видом "Остатки" предназначен для учета остатков, а не оборотов. Далее мы увидим, почему для решения задач учета оборотов лучше использовать соответствующий вид регистра накопления.

Вид регистра "Обороты"

Виртуальная таблица "Обороты" включает в себя поля для каждого из измерений регистра, а также по одному полю на каждый ресурс. Для оборотного регистра "ДвиженияНоменклатуры" из тестовой конфигурации состав полей таблицы следующий:

Состав полей виртуальной таблицы "Обороты"

Как и в предыдущем случае, в зависимости от параметра "Периодичность" в составе доступных полей появятся соответствующие периоды.

Поля периодов виртуальной таблицы "Обороты" в зависимости от параметра "Периодичность"
И так, выполним несколько запросов к таблице "Обороты" и проанализируем SQL-запросы платформы. Первый запрос на языке запросов платформы: Запрос = Новый Запрос; Запрос.Текст = " |ВЫБРАТЬ | ДвиженияНоменклатурыОбороты.Номенклатура, | ДвиженияНоменклатурыОбороты.Склад, | ДвиженияНоменклатурыОбороты.КоличествоОборот |ИЗ | РегистрНакопления.ДвиженияНоменклатуры.Обороты( | &НачалоПериода, | &КонецПериода, | , | Склад = &Склад) | КАК ДвиженияНоменклатурыОбороты"

Запрос принимает также три параметра: "НачалоПериода", "КонецПериода" и "Склад". Как начало периода возьмем начало 2012 года, конец периода - 13 апреля 2013 00:00:00. Склад пусть будет "Склад №1". 

Первым делом платформа 1С:Предприятие получит настройки регистра накопления, к которому выполняется запрос. Запрос будет идентичный рассматриваемому ранее примеру, пойдем дальше. Сформированный платформой SQL-запрос тогда будет такой: "exec sp_executesql N' |SELECT"+ // Результатирующие поля выборки " T1.Fld27RRef, // Номенклатура | T1.Fld28RRef, // Склад | T1.Fld29Turnover_ // КоличествоОборот"+ // Получаем необходимые данные с помощью вложенных запросов "FROM ("+ // Выполняем запрос к вложенной таблице, в которой // получаем данные по итогам оборотов, а также // обороты по тем записям, которые не учтены в итогах " SELECT | T2.Fld27RRef AS Fld27RRef, // Номенклатура | T2.Fld28RRef AS Fld28RRef, // Склад | CAST(SUM(T2.Fld29Turnover_) // КоличествоОборот | AS NUMERIC(38, 8)) AS Fld29Turnover_ | FROM ("+ // ++++++++++ ДАННЫЕ ПО ЗАПИСЯМ ИТОГОВ ++++++++++ // Первым запросом получаем данные по оборотам // из таблицы итогов оборотов "AccumRgTn[n]" // по месяцам " SELECT | T3._Fld27RRef AS Fld27RRef, // Склад | T3._Fld28RRef AS Fld28RRef, // Номенклатура | CAST(SUM(T3._Fld29) // КоличествоОборот | AS NUMERIC(33, 8)) AS Fld29Turnover_ | FROM _AccumRgTn30 T3 WITH(NOLOCK)"+ // Накладываем условия на выборку записей // В эту секцию входят все параметры виртуальной // таблицы "Обороты", которые задает разработчик // в тексте запроса платформы. ИСКЛЮЧЕНИЕ: // параметр P2 - это не конец периода, а начало // месяца параметра "КонецПериода" " WHERE T3._Period >= @P1 // Начало периода | AND T3._Period < @P2 // Ограничение для итогов | AND ((T3._Fld28RRef = @P3)) // Склад"+ // Группируем результат выбранным в запросе измерениям " GROUP BY T3._Fld27RRef, // Склад | T3._Fld28RRef // Номенклатура" // Проверяем, чтобы значения выбранных в запросе ресурсов // не равнялось 0 " HAVING (CAST(SUM(T3._Fld29) | AS NUMERIC(33, 8))) <> @P4"+ // --------- ДАННЫЕ ПО ЗАПИСЯМ ИТОГОВ --------- // // Объединяем результаты по записям итогов и движений " UNION ALL"+ // // ++++++++++ ДАННЫЕ ПО ЗАПИСЯМ ДВИЖЕНИЙ ++++++++++ // Вторым запросом получаем данные по оборотам // из таблицы движений "AccumRg[n]" за период // с начала последних рассчитанных итогов и по // значение параметра "Конец периода" " SELECT | T4._Fld27RRef AS Fld27RRef, // Склад | T4._Fld28RRef AS Fld28RRef, // Номенклатура | CAST(CAST(SUM(T4._Fld29) // КоличествоОборот | AS NUMERIC(27, 8)) | AS NUMERIC(27, 2)) | AS Fld29Turnover_ | FROM _AccumRg26 T4 WITH(NOLOCK)"+ // Условия выборки записей аналогичны запросу // к итогам, за исключением: // - параметра P2 = начало месяца от значения // параметра "Конец периода" // - добавилось условие на активность записей " WHERE // Ограничение для периода движений | T4._Period >= @P2 | AND T4._Period <= @P5 // Конец периода | AND T4._Active = @P6 // Активность записей | AND ((T4._Fld28RRef = @P3))"+ // Склад // Группировки и условия выборки аналогичные // запросу по итогам " GROUP BY T4._Fld27RRef, | T4._Fld28RRef | HAVING (CAST(CAST(SUM(T4._Fld29) | AS NUMERIC(27, 8)) | AS NUMERIC(27, 2))) <> @P4"+ // // ---------- ДАННЫЕ ПО ЗАПИСЯМ ДВИЖЕНИЙ ---------- " ) T2" + // Группируем результат запроса ко вложенной таблице по // выбранным измерениям " GROUP BY T2.Fld27RRef, // Номенклатура | T2.Fld28RRef // Склад"+ // Проверяем, чтобы хотя бы одно значение из // выбранных в запросе ресурсов // было не равно 0. В регистре из примера один ресурс, // поэтому условие одно. " HAVING (CAST(SUM(T2.Fld29Turnover_) | AS NUMERIC(38, 8))) <> @P4 |) T1', |N'@P1 datetime, // НачалоПериода | // Начало месяца от значения | // параметра ""КонецПериода"" |@P2 datetime, |@P3 varbinary(16), // Склад | // Проверка на 0 для полученных записей |@P4 numeric(1,0), |@P5 datetime, // Конец периода |@P6 varbinary(1)', // Активность |{ts '4012-01-01 00:00:00'}, // Начало периода | // Начало месяца от значения | // параметра ""КонецПериода"" |{ts '4013-04-01 00:00:00'}, |0xBE923860773387FD11E2D2B47CD2CB1E, // Склад |0, // Проверка на 0 для полученных записей |{ts '4013-04-13 00:00:00'}, // Конец периода |0x01 // Активность" К комментариям в приведенном тексте добавлю, что вне зависимости от значений параметров "НачалоПериода" и "КонецПериода" запрос пытается получить данные и из итоговых таблиц, и из таблицы движений регистра.

Если в запросе на языке платформы мы добавим использование параметра "Периодичность" (например, поставим значение "Месяц"), то SQL-запрос платформы изменится аналогично рассмотренному примеру для регистра накопления с видом остатки. Будут добавлены поля выбранных периодов ("ПериодДень", "ПериодМесяц" и т.д.) в секции запроса "SELECT" и "GROUP BY". Для нашего примера это месяц. Поля и группировки будут добавлены для всех вложенных запросов и, конечно, содержаться в результатирующей выборке. В нашем примере, выражения в поле запроса для получения периода будет таким:

"DATEADD(DAY,1.0 - 1, | DATEADD(MONTH, | CAST(DATEPART(MONTH,T3._Period) | AS NUMERIC(4)) - 1, | DATEADD(YEAR,(CAST(DATEPART(YEAR,T3._Period) | AS NUMERIC(4)) - 2000) - 2000, | {ts ''4000-01-01 00:00:00''} | ) | ) |) AS Period_" Принцип получения значений периода был описан выше для регистра с видом "Обороты".

Заключение

Эксперименты с регистром показали, что для виртуальной таблицы "Обороты" платформа 1С:Предприятие 8 имеет разный принцип построения SQL-запросов к базе данных в зависимости от вида регистра накопления ("Остатки" или "Обороты"). Если вид регистра - "Остатки", то SQL-запрос получает данные по оборотам непосредственно из таблицы движений. В случае, если вид регистра "Обороты", то тогда уже используется таблица итогов оборотов и запрос работает более оптимально, нежели чем для регистра остатков.

Если представить действия SQL-запросов схематично, то выглядеть это будет примерно так:

Получение данных для виртуальной таблицы "Обороты"в зависимости от вида регистра накопления ("Остатки" или "Обороты")

По схеме видно, что наиболее оптимальным образом платформа работает с виртуальной таблицей "Обороты" для регистра накопления с видом "Обороты", поскольку использует рассчитанных итоги по оборотам в разрезе месяцев. И лишь в тех случаях, когда рассчитанных итогов для периода нет, тогда использует таблицу движений. Для регистра вида "Остатки" всегда используется таблица движений вне зависимости от настроек хранения итоговых записей. Именно поэтому следует внимательно отнестись к настройке вида регистра накопления при проектировании структуры метаданных конфигурации.

Интересен тот факт, что если для регистра накопления отключить использование итогов, то тогда запрос к виртуальной таблице "Остатки" станет невозможным. Будет появляться такая ошибка:

Ошибка получения данных виртуальной таблицы "Обороты"при отключенных итогов регистра накопления

Причем, данная ошибка будет не смотря на то, что виртуальная таблица "Обороты" для регистра накопления с видом "Остатки" использует только таблицу движений.

Возможно что-то упустил. Все замечания/дополнения прошу оставлять в комментариях к статье.

В следующих статьях будет рассмотрена работа платформы с виртуальными таблицами "Остатки" и "Остатки и обороты".

Файлы для загрузки:

  1. Тестовая конфигурация, используемая в статье.

devel1c.blogspot.com

Виртуальные таблицы | SQL Программирование

Представления часто характеризуют как виртуальные таблицы. Пользователи базы данных могут отбирать в представлении строки и столбцы, объединять их с другими представлениями и таблицами, ограничивать, сортировать и группировать результаты запросов и т. д. На самом деле пользователь чаще всего не знает, откуда извлекает значения: из таблицы или представления. Дело в том, что, в отличие от таблиц, представления не занимают физическое пространство диска. Определения представления хранятся в СУБД в виде скомпилированных запросов, которые динамически наполняют данными виртуальные таблицы, для запросов пользователей.

Детали реализации представления отличаются в разных СУБД. СУБД может за кулисами создавать временную таблицу, наполнять ее реальными данными и использовать ее для возвращения результатов запросов пользователей. Механизм базы данных может также комбинировать запросы пользователей с внутренними определениями представлений (которые также по сути являются запросами) и выполнять результирующий запрос для возврата данных. Как бы там ни было, для конечного пользователя это не имеет ни малейшего значения. Представления используются для разных целей. К примеру, в представлении можно скомбинировать данные из множества таблиц в удобном для пользователя виде. Также с их помощью можно реализовать определенные правила системы безопасности, открывая для пользователя только указанные горизонтальные и вертикальные срезы данных. В этой главе показано, как создавать различные типы представлений. В этом разделе описан синтаксис инструкции CREATE VIEW в различных реализациях СУБД. В большинстве случаев список столбцов не указывают; если он опущен, то имена столбцов представления будут совпадать с именами столбцов в инструкции SELECT. Однако он становится обязательным элементом инструкции создания представления, если выполняется хотя бы одно из следующих условий:

Похожие публикации

new-techs.ru

Sql. Ряд виртуальных таблиц. Ключевая фраза принадлежности к набору заданных значений. Команда упорядочения ORDER BY

Что такое SQL?

1)  название СУБД

2)  устройство работы с базами данных

3)  язык запросов к базе данных

4)  язык запросов к операционной системе

Какое из ниже перечисленных свойств присуще SQL?

1)  модульный

2)  непроцедурный

3)  объектно-ориентированный

4)  процедурный

В SQL существует ряд виртуальных таблиц. Какая из них может использоваться как в интерактивном режиме, так и в программе?

1)  запрос

2)  курсор

3)  представление

4)  рабочая таблица

С помощью какого предложения в SQL выполняются все запросы на получение данных из одной или нескольких таблиц?

1)  CREATE

2)  INSERT

3)  QUERY

4)  SELECT

Ключевая фраза принадлежности к набору заданных значений:

1)  BETWEEN

2)  FROM

3)  IN

4)  LIKE

Команда упорядочения ORDER BY выполняет

1)  упорядочение по адресу

2)  упорядочение по значению одного из столбцов таблицы

3)  упорядочение по значению одной из строк таблицы

4)  упорядочение таблице

Что такое представление?

1)  виртуальная таблица

2)  каталог

3)  файл

4)  физическая таблица

Что такое индекс?

1)  адрес поля некоторой таблицы

2)  база данных с числовыми полями

3)  значение столбца некоторой таблицы

4)  системная таблица, построенная по значениям заданного столбца заданной таблицы

Какой командой осуществляется удаление индекса?

1)  CLOSE INDEX

2)  DELETE INDEX

3)  DROP INDEX

4)  REMOVE INDEX

Что такое системный каталог?

1)  набор таблиц, содержащих информацию для правильного функционирования СУБД

2)  набор файлов на жестком диске

3)  набор файлов, содержащих системные данные

4)  таблица размещения файлов

Что такое база знаний?

1)  набор знаний

2)  набор определенных данных и программ их обработки

3)  набор определенных данных и соответствующих им знаний

4)  набор определенных знаний и программ их обработки

Как называют технологию построения банка знаний?

1)  инженеринг знаний

2)  мониторинг знаний

3)  настройка знаний

4)  подбор знаний

Какая особенность знаний проявляется, когда в базе знаний сами информационные единицы определяют поведение системы?

1)  активность

2)  направленность

3)  связность

4)  структурированность

Какая особенность знаний проявляется, когда в базе знаний каждая информационная единица должна иметь уникальное имя?

1)  активность

2)  внутренняя интерпретируемость

3)  определенность

4)  связность

Экспертные системы являются разновидностью

1)  базы знаний

2)  базы знаний

3)  банка данных

4)  банка знаний

Сетевая модель называется семантической, если:

1)  в ней допускаются связи различного типа

2)  в ней допускаются связи только одного вида

3)  в ней допускаются символьные и числовые связи

4)  в ней допускаются числовые связи

Что представляет собой фрейм?

1)  базу данных

2)  набор записей

3)  набор отношений

4)  структуру, составленную из ряда описаний

Фрейм — поименованная структура, составленная из ряда описаний. Как называются эти описания?

1)  домен

2)  слот

3)  специфика

4)  фреймтайп

Какая группа людей устанавливает предназначение экспертной системы, определяет ее предметную область?

1)  администраторы

2)  пользователи

3)  специалисты по сбору знаний

4)  эксперты

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

1)  администраторы

2)  пользователи

3)  специалисты по сбору знаний

4)  эксперты

Какая группа людей собирает информацию для базы знаний, анализирует и эвристически организует информацию?

1)  администрация

2)  инженеры-когнитологи

3)  программисты

4)  эксперты

На каком этапе устанавливаются ключевые понятия, отношения в характеристики проблемной области?

1)  идентификации

2)  концептуализации

3)  сбора информации

4)  формализации

На каком этапе осуществляется проверка выбранного способа представления знаний и всей системы в целом на адекватность?

1)  модификации

2)  опытной эксплуатации

3)  отладки

4)  тестирования

Назовите предложение, с помощью которого создается базовая таблица.

1)  CREATE TABLE

2)  CREATE VIEW

3)  DECLARE CURSOR

4)  MAKE TABLE

Как называется пустая поименованная таблица, определяемая перечнем столбцов базовых таблиц и признаками строк, которые необходимо увидеть?

1)  вид

2)  курсор

3)  представление

4)  рабочая таблица

vunivere.ru