Получить 3ю строку

Заметка

Declare @N int
set @N = 3;
WITH CTE AS
(
SELECT Name, Salary, EmpID, RN = ROW_NUMBER()
OVER (ORDER BY Salary DESC)
FROM Employee
)
SELECT Name, Salary, EmpID
FROM CTE
WHERE RN = @N

Как найти дубликат записи

Заметка

Дублирование записей с одним полем

SELECT name, COUNT(email)
FROM users
GROUP BY email
HAVING COUNT(email) > 1

 

Дублирование записей с несколькими полями

SELECT name, email, COUNT(*)
FROM users
GROUP BY name, email
HAVING COUNT(*) > 1

 

Использование буферного кеша Postgres

SELECT
'total', pg_size_pretty(count(*) * (SELECT current_setting('block_size')::int))
FROM pg_buffercache
UNION SELECT
'dirty', pg_size_pretty(count(*) * (SELECT current_setting('block_size')::int))
FROM pg_buffercache
WHERE isdirty
UNION SELECT
'clear', pg_size_pretty(count(*) * (SELECT current_setting('block_size')::int))
FROM pg_buffercache
WHERE NOT isdirty
UNION SELECT
'used', pg_size_pretty(count(*) * (SELECT current_setting('block_size')::int))
FROM pg_buffercache
WHERE reldatabase IS NOT NULL
UNION SELECT
'free',pg_size_pretty(count(*) * (SELECT current_setting('block_size')::int))
FROM pg_buffercache
WHERE reldatabase IS NULL;
SELECT
d.datname,
pg_size_pretty(pg_database_size(d.datname)) AS database_size,
pg_size_pretty(count(b.bufferid) * (SELECT current_setting('block_size')::int)) AS size_in_shared_buffers,
round((100 * count(b.bufferid) / (SELECT setting FROM pg_settings WHERE name
= 'shared_buffers')::decimal),2) AS pct_of_shared_buffers
FROM pg_buffercache b
JOIN pg_database d ON b.reldatabase = d.oid
WHERE b.reldatabase IS NOT NULL
GROUP BY 1 ORDER BY 4 DESC LIMIT 10;

Нагрузка, создаваемая запросами Postgres

SELECT
pg_database.datname AS Database,
pg_stat_statements.query AS Query,
pg_stat_statements.calls AS ExecutionCount,
pg_stat_statements.total_time ExecutionTime,
pg_stat_statements.shared_blks_read + pg_stat_statements.shared_blks_written AS Memory,
pg_stat_statements.local_blks_read + pg_stat_statements.local_blks_written AS IO,
pg_stat_statements.temp_blks_read + pg_stat_statements.temp_blks_written AS Temp

FROM
pg_stat_statements AS pg_stat_statements
INNER JOIN pg_database AS pg_database
ON pg_database.oid = pg_stat_statements.dbid
ORDER BY
ExecutionTime DESC
with s AS (SELECT
CASE WHEN sum(total_time) = 0 THEN 1 ELSE sum(total_time) END AS sum_time,
CASE WHEN sum(blk_read_time+blk_write_time) = 0 THEN 1 ELSE sum(blk_read_time+blk_write_time) END as sum_iotime,
CASE WHEN sum(total_time-blk_read_time-blk_write_time) = 0 THEN 1 ELSE sum(total_time-blk_read_time-blk_write_time)
END as sum_cputime,
CASE WHEN sum(calls) = 0 THEN 1 ELSE sum(calls) END AS sum_calls,
CASE WHEN sum(rows) = 0 THEN 1 ELSE sum(rows) END as sum_rows
FROM pg_stat_statements
)
SELECT
'all_users@all_databases' as "user@database",
100 AS time_percent,
100 AS iotime_percent,
100 AS cputime_percent,
(sum_time/1000)*'1 second'::interval as total_time,
(sum_cputime/sum_calls)::numeric(20, 2) AS avg_cpu_time_ms,
(sum_iotime/sum_calls)::numeric(20, 2) AS avg_io_time_ms,
sum_calls as calls,
100 AS calls_percent,
sum_rows as rows,
100 as row_percent,
'all_queries' as query
FROM s
UNION ALL
SELECT
(select rolname from pg_roles where oid = p.userid) || '@' || (select datname from pg_database where oid
(100*total_time/(SELECT sum_time FROM s))::numeric(20, 2) AS time_percent,
(100*(blk_read_time+blk_write_time)/(SELECT sum_iotime FROM s))::numeric(20, 2) AS iotime_percent,
(100*(total_time-blk_read_time-blk_write_time)/(SELECT sum_cputime FROM s))::numeric(20, 2) AS cputime_percent,
(total_time/1000)*'1 second'::interval as total_time,
((total_time-blk_read_time-blk_write_time)/calls)::numeric(20, 2) AS avg_cpu_time_ms,
((blk_read_time+blk_write_time)/calls)::numeric(20, 2) AS avg_io_time_ms,
calls,
(100*calls/(SELECT sum_calls FROM s))::numeric(20, 2) AS calls_percent,
rows,
(100*rows/(SELECT sum_rows from s))::numeric(20, 2) AS row_percent,
query
FROM pg_stat_statements p
WHERE
(total_time-blk_read_time-blk_write_time)/(SELECT sum_cputime FROM s)>=0.005
UNION ALL
SELECT
'all_users@all_databases' as "user@database",
(100*sum(total_time)/(SELECT sum_time FROM s))::numeric(20, 2) AS time_percent,
(100*sum(blk_read_time+blk_write_time)/(SELECT sum_iotime FROM s))::numeric(20, 2) AS iotime_percent,
(100*sum(total_time-blk_read_time-blk_write_time)/(SELECT sum_cputime FROM s))::numeric(20, 2) AS cputime_percent,
(sum(total_time)/1000)*'1 second'::interval,
(sum(total_time-blk_read_time-blk_write_time)/sum(calls))::numeric(10, 3) AS avg_cpu_time_ms,
(sum(blk_read_time+blk_write_time)/sum(calls))::numeric(10, 3) AS avg_io_time_ms,
sum(calls),
(100*sum(calls)/(SELECT sum_calls FROM s))::numeric(20, 2) AS calls_percent,
sum(rows),
(100*sum(rows)/(SELECT sum_rows from s))::numeric(20, 2) AS row_percent,
'other' AS query
FROM pg_stat_statements p
WHERE
(total_time-blk_read_time-blk_write_time)/(SELECT sum_cputime FROM s)<0.005 ORDER BY 4 DESC;

Использование индексов Postgres

SELECT
t.tablename,
indexname,
c.reltuples AS num_rows,
pg_size_pretty(pg_relation_size(quote_ident(t.tablename)::text)) AS table_size,
pg_size_pretty(pg_relation_size(quote_ident(indexrelname)::text)) AS index_size,
CASE WHEN indisunique THEN 'Y' ELSE 'N' END AS UNIQUE,
idx_scan AS number_of_scans, idx_tup_read AS tuples_read, idx_tup_fetch AS tuples_fetched
FROM pg_tables t
LEFT OUTER JOIN pg_class c ON t.tablename=c.relname
LEFT OUTER JOIN
( SELECT c.relname AS ctablename, ipg.relname AS indexname, x.indnatts AS number_of_columns,
idx_scan, idx_tup_read, idx_tup_fetch, indexrelname, indisunique FROM pg_index x
JOIN pg_class c ON c.oid = x.indrelid JOIN pg_class ipg ON ipg.oid = x.indexrelid
JOIN pg_stat_all_indexes psai ON x.indexrelid = psai.indexrelid )
AS foo
ON t.tablename = foo.ctablename
WHERE t.schemaname='public'
ORDER BY 1,2;
--------------------------------------------------------------
SELECT
idstat.relname AS table_name,
indexrelname AS index_name,
idstat.idx_scan AS times_used,
pg_size_pretty(pg_relation_size(tabstat.relid)) AS table_size,
pg_size_pretty(pg_relation_size(indexrelid)) AS index_size,
n_tup_upd + n_tup_ins + n_tup_del as num_writes,
indexdef AS definition
FROM
pg_stat_user_indexes AS idstat
JOIN pg_indexes ON indexrelname = indexname
JOIN pg_stat_user_tables AS tabstat ON idstat.relname = tabstat.relname
WHERE
idstat.idx_scan < 200 AND indexdef !~* 'unique' ORDER BY idstat.relname, indexrelname; -------------------------------------------------------------- WITH table_scans as ( SELECT relid, tables.idx_scan + tables.seq_scan as all_scans, ( tables.n_tup_ins + tables.n_tup_upd + tables.n_tup_del ) as writes, pg_relation_size(relid) as table_size FROM pg_stat_user_tables as tables ), all_writes as ( SELECT sum(writes) as total_writes FROM table_scans ), indexes as ( SELECT idx_stat.relid, idx_stat.indexrelid, idx_stat.schemaname, idx_stat.relname as tablename, idx_stat.indexrelname as indexname, idx_stat.idx_scan, pg_relation_size(idx_stat.indexrelid) as index_bytes, indexdef ~* 'USING btree' AS idx_is_btree FROM pg_stat_user_indexes as idx_stat JOIN pg_index USING (indexrelid) JOIN pg_indexes as indexes ON idx_stat.schemaname = indexes.schemaname AND idx_stat.relname = indexes.tablename AND idx_stat.indexrelname = indexes.indexname WHERE pg_index.indisunique = FALSE ), index_ratios AS ( SELECT schemaname, tablename, indexname, idx_scan, all_scans, round(( CASE WHEN all_scans = 0 THEN 0.0::NUMERIC ELSE idx_scan::NUMERIC/all_scans * 100 END),2) as index_scan_pct, writes, round((CASE WHEN writes = 0 THEN idx_scan::NUMERIC ELSE idx_scan::NUMERIC/writes END),2) as scans_per_write, pg_size_pretty(index_bytes) as index_size, pg_size_pretty(table_size) as table_size, idx_is_btree, index_bytes FROM indexes JOIN table_scans USING (relid) ), index_groups AS ( SELECT 'Never Used Indexes' as reason, *, 1 as grp FROM index_ratios WHERE idx_scan = 0 and idx_is_btree UNION ALL SELECT 'Low Scans, High Writes' as reason, *, 2 as grp FROM index_ratios WHERE scans_per_write <= 1 and index_scan_pct < 10 and idx_scan > 0
and writes > 100
and idx_is_btree
UNION ALL
SELECT 'Seldom Used Large Indexes' as reason, *, 3 as grp
FROM index_ratios
WHERE
index_scan_pct < 5 and scans_per_write > 1
and idx_scan > 0
and idx_is_btree
and index_bytes > 100000000
UNION ALL
SELECT 'High-Write Large Non-Btree' as reason, index_ratios.*, 4 as grp
FROM index_ratios, all_writes
WHERE
( writes::NUMERIC / total_writes ) > 0.02
AND NOT idx_is_btree
AND index_bytes > 100000000
ORDER BY grp, index_bytes DESC )
SELECT reason, schemaname, tablename, indexname,
index_scan_pct, scans_per_write, index_size, table_size
FROM index_groups;

Отсутствие индексов Postgres

SELECT
relname,
seq_scan - coalesce(idx_scan, 0) AS too_much_seq,
case when seq_scan - coalesce(idx_scan, 0) > 0 THEN 'Нет индекса?' ELSE 'OK' END AS Message,
pg_relation_size(relname::regclass) AS rel_size,
seq_scan,
coalesce(idx_scan, 0) AS idx_scan
FROM
pg_stat_all_tables
WHERE
schemaname='public'
AND pg_relation_size(relname::regclass)>10000 -- ограничение на размер анализируемых таблиц
ORDER BY
too_much_seq DESC;

Базы данных с максимальным IO Postgres

SELECT
pg_stat_database.datname AS DatabaseName,
MAX(pg_stat_database.tup_returned) AS TotalReads,
MAX(pg_stat_database.tup_inserted + pg_stat_database.tup_updated + pg_stat_database.tup_deleted) AS TotalWrites,
MAX(pg_stat_database.tup_returned + pg_stat_database.tup_inserted + pg_stat_database.tup_updated
+ pg_stat_database.tup_deleted) AS IO,
SUM(pg_stat_statements.calls) AS ExecutionCount

FROM
pg_catalog.pg_stat_database AS pg_stat_database
LEFT OUTER JOIN pg_stat_statements AS pg_stat_statements
ON pg_stat_statements.dbid = pg_stat_database.datid
GROUP BY
pg_stat_database.datname
ORDER BY
IO Desc

Размер временных таблиц «1С» в Postgres

select relnamespace, sum(relpages::bigint*8192), pg_size_pretty(sum(relpages::bigint*8192))
from pg_class where relname like 'tt%' group by 1 order by 2 desc;
select sum(relpages::bigint*8192), pg_size_pretty(sum(relpages::bigint*8192)) from pg_class where relname like 'tt%';

Таблицы с максимальным пустым местом Postgres

-- установка расширения
create extension pg_freespacemap;
select
result.table_name,
result.freespace as fororder,
pg_size_pretty(result.size) as size,
pg_size_pretty(result.freespace) as freespace,
result.freespace * 100 / result.size as percent_free
from
(select
t.table_name,
pg_total_relation_size(t.table_name) as size,
sum(s.avail) as freespace
from
(select table_name from information_schema.tables where table_schema = 'public') as t,
LATERAL pg_freespace(t.table_name) as s
group by
t.table_name) as result
order by
fororder desc
limit 20;

Транзакции, ожидающие на блокировках Postgres

SELECT blocked_locks.pid AS blocked_pid,
blocked_activity.usename AS blocked_user,
blocking_locks.pid AS blocking_pid,
blocking_activity.usename AS blocking_user,
blocked_activity.query AS blocked_statement,
blocking_activity.query AS current_statement_in_blocking_process,
blocked_activity.application_name AS blocked_application,
blocking_activity.application_name AS blocking_application
FROM pg_catalog.pg_locks blocked_locks
JOIN pg_catalog.pg_stat_activity blocked_activity ON blocked_activity.pid = blocked_locks.pid
JOIN pg_catalog.pg_locks blocking_locks
ON blocking_locks.locktype = blocked_locks.locktype
AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE
AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
AND blocking_locks.pid != blocked_locks.pid
JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid
WHERE NOT blocked_locks.GRANTED;

Особенности 8.3.10

Реализована поддержка СУБД PostgreSQL версии 9.6.

 Смотрите также http://1c.ru/news/pressrelise.jsp?id=1847

Повышена масштабируемость кластера серверов в том случае, если:

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

Снижено количество оперативной памяти, используемой сервером «1С:Предприятия», если в прикладном решении используются пакетные запросы.

Упрощена диагностика использования циклических ссылок при работе встроенного языка.

Реализована возможность дополнительно обработать данные, которые получил динамический список для отображения. Реализовано событие ПриПолученииДанныхНаСервере. Дополнительно смотрите https://wonderland.v8.1c.ru/blog/obrabotka-i-oformlenie-dannykh-dinamicheskogo-spiska/

В технологическом журнале реализовано отражение событий, связанных с:

  • получением и освобождением лицензий (как программных, так и ключей HASP);
  • получением лицензий на базовые версии;
  • регулярным мониторингом соответствия реального оборудования и списка оборудования, зафиксированного в лицензии.

Реализовано событие технологического журнала <LIC>.

Событие технологического журнала <HASP> предоставляет возможность анализа только технологических аспектов работы с ключами HASP (вызовы интерфейса работы с HASP), не предоставляя возможности отслеживать получение и освобождение лицензий, получаемых с ключей HASP.

Реализовано журналирование событий, возникающих при первом соединении сервера «1С:Предприятия» с СУБД Microsoft SQL Server, в технологическом журнале. Журналирование выполняется с помощью события <DBMSSQLCONN>.

В документации данное изменение описано здесь и здесь.

Изменен подход к хранению истории исполнения фоновых и регламентных заданий. В клиент-серверном варианте история хранится в разрезе информационных баз. Для каждой информационной базы хранится история:

  • до 1 000 фоновых заданий, созданных из встроенного языка;
  • до 1 000 регламентных заданий;
  • до 1 000 системных фоновых заданий (формируемых самой системой).

Для каждого задания (фонового, системного фонового и регламентного) будет предприниматься попытка хранить информацию минимум о трех последних запусках. Это количество (три запуска) будет уменьшаться в том случае, если превышен лимит в 1 000 записей на тот или иной вид заданий.

Реализовано в версии 8.3.10.2168 в новое событие SCRIPTCIRCREFS  режим автоматического поиска циклических ссылок

Пользователи блокирующие конкретную таблицу

select a.usename, t.relname, a.current_query, mode from pg_locks l inner join pg_stat_activity a on a.procpid = l.pid inner join pg_stat_all_tables t on t.relid=l.relation where t.relname = ‘tablename’;

select relation::regclass, mode, a.usename, granted, pid from pg_locks l inner join pg_stat_activity a on a.procpid = l.pid where not mode = ‘AccessShareLock’ and relation is not null;

Определение размеров таблиц в базе данных PostgreSQL

SELECT tableName, pg_size_pretty(pg_total_relation_size(CAST(tablename as text))) as size
from pg_tables
where tableName not like ‘sql_%’
order by size;

или

SELECT
table_name,
pg_size_pretty(table_size) AS table_size,
pg_size_pretty(indexes_size) AS indexes_size,
pg_size_pretty(total_size) AS total_size
FROM (
SELECT
table_name,
pg_table_size(table_name) AS table_size,
pg_indexes_size(table_name) AS indexes_size,
pg_total_relation_size(table_name) AS total_size
FROM (
SELECT ('"' || table_schema || '"."' || table_name || '"') AS table_name
FROM information_schema.tables
) AS all_tables
ORDER BY total_size DESC
) AS pretty_sizes

или

Размер таблиц и индексов

SELECT
t.tablename,
indexname,
c.reltuples::integer AS num_rows,
pg_size_pretty(pg_relation_size(quote_ident(t.tablename)::text)) AS table_size,
pg_size_pretty(pg_relation_size(quote_ident(indexrelname)::text)) AS index_size,
CASE WHEN x.is_unique = 1 THEN 'Y'
ELSE 'N'
END AS UNIQUE,
idx_scan AS number_of_scans,
idx_tup_read AS tuples_read,
idx_tup_fetch AS tuples_fetched
FROM pg_tables t
LEFT OUTER JOIN pg_class c ON t.tablename=c.relname
LEFT OUTER JOIN
(SELECT indrelid,
max(CAST(indisunique AS integer)) AS is_unique
FROM pg_index
GROUP BY indrelid) x
ON c.oid = x.indrelid
LEFT OUTER JOIN
( SELECT c.relname AS ctablename, ipg.relname AS indexname, x.indnatts AS number_of_columns,
idx_scan, idx_tup_read, idx_tup_fetch,indexrelname FROM pg_index x
JOIN pg_class c ON c.oid = x.indrelid
JOIN pg_class ipg ON ipg.oid = x.indexrelid
JOIN pg_stat_all_indexes psai ON x.indexrelid = psai.indexrelid )
AS foo
ON t.tablename = foo.ctablename
WHERE t.schemaname='public'
ORDER BY pg_relation_size(quote_ident(indexrelname)::text) desc;

Объединение данных двух периодических регистров

http://forum.infostart.ru/forum26/topic111009/

Есть два периодических регистра. Первый содержит количества на дату (РегистрКоличество), а второй — состояния на дату (РегистрСостояние). Даты двух регистров независимы друг от друга. Требуется запросом построить третий «регистр», являющийся объединением первых двух, чтобы показывались соответствующие друг другу даты, количества и состояния.

Вот короткое решение с использованием коррелированных запросов (ахтунг!):
ВЫБРАТЬ
ВЫБОР
КОГДА ТаблицаКоличества.Дата > ТаблицаСостояний.Дата
ТОГДА ТаблицаКоличества.Дата
ИНАЧЕ ТаблицаСостояний.Дата
КОНЕЦ КАК Дата,
ТаблицаКоличества.Количество КАК Количество,
ТаблицаСостояний.Состояние КАК Состояние
ИЗ
ТаблицаКоличества КАК ТаблицаКоличества
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТаблицаСостояний КАК ТаблицаСостояний
ПО (ТаблицаСостояний.Дата В
(ВЫБРАТЬ
МАКСИМУМ(ТаблицаСостояний.Дата)
ИЗ
ТаблицаСостояний КАК ТаблицаСостояний
ГДЕ
ТаблицаСостояний.Дата <= ТаблицаКоличества.Дата)
ИЛИ ТаблицаКоличества.Дата В
(ВЫБРАТЬ
МАКСИМУМ(ТаблицаКоличества.Дата)
ИЗ
ТаблицаКоличества КАК ТаблицаКоличества
ГДЕ
ТаблицаКоличества.Дата <= ТаблицаСостояний.Дата))
 

Объединение непересекающихся интервалов в запросе

http://www.forum.mista.ru/topic.php?id=748551

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

 НачалоПериода  КонецПериода  Гость
1.01.2001 2.01.2001  Росс Геллер
3.01.2001 4.01.2001  Росс Геллер
7.01.2001 8.01.2001 Росс Геллер

должно получиться

 НачалоПериода  КонецПериода  Гость
1.01.2001 4.01.2001  Росс Геллер
7.01.2001 8.01.2001  Росс Геллер

Это делает следующий запрос, являющийся развитием идей решения задачи 14 из предыдущей статьи на случай интервалов:
ВЫБРАТЬ
Дано.НачалоПериода,
Дано.КонецПериода,
Дано.Гостиница,
Дано.ФизическоеЛицо,
СУММА(РАЗНОСТЬДАТ(Слева.НачалоПериода, Слева.КонецПериода, ДЕНЬ) + 1) КАК Интеграл
ПОМЕСТИТЬ ДаноПлюс
ИЗ
Дано КАК Дано
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Дано КАК Слева
ПО (Слева.НачалоПериода <= Дано.НачалоПериода)
СГРУППИРОВАТЬ ПО
Дано.НачалоПериода,
Дано.КонецПериода,
Дано.Гостиница,
Дано.ФизическоеЛицо
;
ВЫБРАТЬ
МИНИМУМ(Дано.НачалоПериода) КАК НачалоПериода,
МАКСИМУМ(Дано.КонецПериода) КАК КонецПериода,
Дано.Гостиница,
Дано.ФизическоеЛицо
ИЗ
ДаноПлюс КАК Дано
СГРУППИРОВАТЬ ПО
ДОБАВИТЬКДАТЕ(Дано.КонецПериода, ДЕНЬ, Дано.Интеграл),
Дано.Гостиница,
Дано.ФизическоеЛицо

Сравнение двух массивов

 

http://www.forum.mista.ru/topic.php?id=750240

Задача заключается в том, чтобы сравнить два массива и вывести те их элементы, которые не встречаются в обоих массивах, то есть выполнить операцию исключающего ИЛИ для массивов. С использованием соответствия функция сравнения получается достаточно простой:
Функция ИсключающееИЛИ(Массив1, Массив2)
Результат = Новый Массив;
Повтор = Новый Соответствие;
Для каждого Элемент Из Массив1 Цикл
Повтор[Элемент] = ?(Повтор[Элемент] = Неопределено, Ложь, Истина)
КонецЦикла;
Для каждого Элемент Из Массив2 Цикл
Повтор[Элемент] = ?(Повтор[Элемент] = Неопределено, Ложь, Истина)
КонецЦикла;
Для каждого Элемент Из Повтор Цикл
Если НЕ Элемент.Значение Тогда
Результат.Добавить(Элемент.Ключ)
КонецЕсли
КонецЦикла;
Возврат Результат
КонецФункции
Если в массиве могут быть только даты (в исходной задаче было так), то можно использовать другой принцип, сократив один цикл:
Функция ИсключающееИЛИ1(Массив1, Массив2)
Результат = Новый Массив;
Строка1 = ЗначениеВСтрокуВнутр(Массив1);
Строка2 = ЗначениеВСтрокуВнутр(Массив2);
Для каждого Элемент Из Массив1 Цикл
Если НЕ Найти(Строка2, Формат(Элемент,«ДФ=ггггММддЧЧммсс»)) Тогда
Результат.Добавить(Элемент)
КонецЕсли
КонецЦикла;
Для каждого Элемент Из Массив2 Цикл
Если НЕ Найти(Строка1, Формат(Элемент,«ДФ=ггггММддЧЧммсс»)) Тогда
Результат.Добавить(Элемент)
КонецЕсли
КонецЦикла;
Возврат Результат
КонецФункции

Cпособ ожидания Linux/Windows на сервере

.

// Процедура — Ожидание
//
// Параметры:
//  Длительность — Число — длительность ожидания в секундах.
//
Процедура Ожидание(Длительность) Экспорт

Идентификатор = Новый УникальныйИдентификатор;

НачатьТранзакцию();

Блокировка = Новый БлокировкаДанных;
Элемент = Блокировка.Добавить(«РегистрСведений.сшпБлокировкаОчереди»);
Элемент.Режим = РежимБлокировкиДанных.Исключительный;
Элемент.УстановитьЗначение(«Идентификатор», Идентификатор);
Блокировка.Заблокировать();

мсвПараметров = Новый Массив;
мсвПараметров.Добавить(Идентификатор);
Задание = ФоновыеЗадания.Выполнить(«сшпОбщегоНазначения.ВыполнитьПаузу», мсвПараметров,, «Выполнить паузу 20 сек.»);

Попытка
Задание.ОжидатьЗавершения(Длительность);
Исключение
КонецПопытки;

ОтменитьТранзакцию();

КонецПроцедуры

// Процедура — Выполнить паузу
//
// Параметры:
//  Идентификатор     — УникальныйИдентификатор — идентификатор сессии ожидания.
//
Процедура ВыполнитьПаузу(Идентификатор) Экспорт

НачатьТранзакцию();
Блокировка = Новый БлокировкаДанных;

Элемент = Блокировка.Добавить(«РегистрСведений.сшпБлокировкаОчереди»);
Элемент.Режим = РежимБлокировкиДанных.Исключительный;
Элемент.УстановитьЗначение(«Идентификатор», Идентификатор);

Попытка
Блокировка.Заблокировать();
Исключение
КонецПопытки;
ОтменитьТранзакцию();

КонецПроцедуры

 

Округление в большую сторону

http://www.forum.mista.ru/topic.php?id=752392

Для округления числа Ч в бОльшую сторону можно применять выражение:
М Цел(М Ч)
где М = 999999999 или больше, при необходимости.

В качестве дополнения красивый прием, взятый из чужого кода. Абсолютное значение числа Ч:
Макс(Ч, Ч)

Движения периодического регистра сведений без повторов

http://forum.infostart.ru/forum26/topic140198/

Часто бывает так, что одно и то же значение устанавливается в периодическом регистре сведений несколько раз подряд. На примере таблицы дат и цен следующий запрос позволяет избавиться от ненужных повторов:
ВЫБРАТЬ
Дано.Дата КАК Дата,
Дано.Цена
ИЗ
Дано КАК Дано
ЛЕВОЕ СОЕДИНЕНИЕ Дано КАК Слева
ПО (Слева.Дата < Дано.Дата)
СГРУППИРОВАТЬ ПО
Дано.Дата,
Дано.Цена
ИМЕЮЩИЕ
ЕСТЬNULL(МАКСИМУМ(Слева.Дата), 0) <> ЕСТЬNULL(МАКСИМУМ(ВЫБОР Слева.Цена КОГДА Дано.Цена ТОГДА Слева.Дата КОНЕЦ), 1)
Или вот еще решение через коррелированный запрос (всегда требуется тестировать производительность таких вариантов!)
ВЫБРАТЬ
Дано.Дата КАК Дата,
Дано.Цена
ИЗ
Дано КАК Дано
ГДЕ
НЕ Дано.Цена В
(ВЫБРАТЬ ПЕРВЫЕ 1
Слева.Цена
ИЗ
Дано КАК Слева
ГДЕ
Слева.Дата < Дано.Дата
УПОРЯДОЧИТЬ ПО
Слева.Дата УБЫВ)

Количество дней, когда товар был на складе

http://forum.infostart.ru/forum14/topic141252/

Обычный подход к решению этой задачи — рассчитать «остатки на каждый день» и подсчитать дни наличия товара. Предлагается другой подход: найти все интервалы отсутствия товара и вычесть их общую длину из длины периода. Получается следующий запрос:
ВЫБРАТЬ
Движения.Склад,
Движения.Номенклатура,
Движения.Период,
Движения.КоличествоНачальныйОстаток,
Движения.КоличествоКонечныйОстаток
ПОМЕСТИТЬ Движения
ИЗ
РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, Секунда, , ) КАК Движения
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
Движения.Склад,
Движения.Номенклатура,
Движения.Период,
Движения.КоличествоНачальныйОстаток,
Движения.КоличествоКонечныйОстаток
ПОМЕСТИТЬ ДополненныеДвижения
ИЗ
Движения КАК Движения

ОБЪЕДИНИТЬ

ВЫБРАТЬ РАЗЛИЧНЫЕ
НачальныеНули.Склад,
НачальныеНули.Номенклатура,
&НачалоПериода,
0,
0
ИЗ
Движения КАК НачальныеНули

ОБЪЕДИНИТЬ

ВЫБРАТЬ РАЗЛИЧНЫЕ
КонечныеНули.Склад,
КонечныеНули.Номенклатура,
&КонецПериода,
0,
0
ИЗ
Движения КАК КонечныеНули
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
Точки.Склад,
Точки.Номенклатура,
Точки.Период,
МАКСИМУМ(Точки.КоличествоНачальныйОстаток) КАК КоличествоНачальныйОстаток,
МАКСИМУМ(Точки.КоличествоКонечныйОстаток) КАК КоличествоКонечныйОстаток
ПОМЕСТИТЬ ТочкиВремени
ИЗ
ДополненныеДвижения КАК Точки

СГРУППИРОВАТЬ ПО
Точки.Склад,
Точки.Номенклатура,
Точки.Период
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
Точки.Склад,
Точки.Номенклатура,
МАКСИМУМ(Слева.Период) КАК НачалоОтсутствия,
Точки.Период
ПОМЕСТИТЬ Интервалы
ИЗ
ТочкиВремени КАК Точки
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТочкиВремени КАК Слева
ПО Точки.Склад = Слева.Склад
И Точки.Номенклатура = Слева.Номенклатура
И (Точки.КоличествоНачальныйОстаток = 0)
И (Слева.КоличествоКонечныйОстаток = 0)
И Точки.Период > Слева.Период

СГРУППИРОВАТЬ ПО
Точки.Склад,
Точки.Номенклатура,
Точки.Период

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ РАЗЛИЧНЫЕ
Точки.Склад,
Точки.Номенклатура,
&КонецПериода,
&НачалоПериода
ИЗ
Движения КАК Точки
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
Интервалы.Склад,
Интервалы.Номенклатура,
СУММА(РАЗНОСТЬДАТ(Интервалы.Период, Интервалы.НачалоОтсутствия, СЕКУНДА)) / 60 / 60 / 24 КАК ДнейНаличия
ИЗ
Интервалы КАК Интервалы

СГРУППИРОВАТЬ ПО
Интервалы.Склад,
Интервалы.Номенклатура
Чтобы обработать «особые случаи» (когда в начале или в конце интервала остаток будет нулевым), потребовалось добавить записи — «заглушки» по краям интервала. Чтобы учесть возможность, когда периодов отсутствия не было, потребовалось добавить записи полного интервала, из которых при группировке вычитаются интервалы отсутствия.
Из-за этих особых случаев запрос получился длинным, но по идее он простой. Большим плюсом этого подхода является то, что он замечает движения в течении дня. Если же ориентироваться только на остатки в начале/конце дня, то на складе типа «гардероб» (завезли и тут же продали) товар будет всегда отсутствовать.

Возможно, при небольшом объеме данных необходимости повышать быстродействие, выделяя более редкие интервалы отсутствия товаров, и не возникнет. Тогда можно просуммировать собственно интервалы наличия, что выливается в гораздо более короткий запрос (сразу для дней, но можно переделать и для секунд):
ВЫБРАТЬ
Движения.Период,
Движения.Склад,
Движения.Номенклатура,
Движения.КоличествоКонечныйОстаток
ПОМЕСТИТЬ Движения
ИЗ
РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, ДЕНЬ, ДвиженияИГраницыПериода, Склад = &Склад) КАК Движения
;
ВЫБРАТЬ
Интервалы.Склад,
Интервалы.Номенклатура,
СУММА(Интервалы.Интервал) КАК ДнейНаличия
ИЗ
(ВЫБРАТЬ
Было.Склад КАК Склад,
Было.Номенклатура КАК Номенклатура,
РАЗНОСТЬДАТ(Было.Период, МИНИМУМ(Стало.Период), ДЕНЬ) КАК Интервал
ИЗ
Движения КАК Было
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Движения КАК Стало
ПО Было.Склад = Стало.Склад
И Было.Номенклатура = Стало.Номенклатура
И (Было.КоличествоКонечныйОстаток > 0)
И Было.Период < Стало.Период
СГРУППИРОВАТЬ ПО
Было.Период,
Было.Склад,
Было.Номенклатура) КАК Интервалы
СГРУППИРОВАТЬ ПО
Интервалы.Склад,
Интервалы.Номенклатура
 

Первый пропущенный артикул

http://www.forum.mista.ru/topic.php?id=759443

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

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

Для максимизации скорости запрос преобразования в число записан иначе, чем в исходной статье.  Кроме того, для «надежности» вместо коррелированного запроса используется группировка, хотя запись при этом также получается более длинной:
ВЫБРАТЬ
ВЫБОР ПОДСТРОКА(Артикул, 6, 1)КОГДА«1»ТОГДА 1 КОГДА«2»ТОГДА 2 КОГДА«3»ТОГДА 3 КОГДА«4»ТОГДА 4 КОГДА«5»ТОГДА 5 КОГДА«6»ТОГДА 6 КОГДА«7»ТОГДА 7 КОГДА«8»ТОГДА 8 КОГДА«9»ТОГДА 9 ИНАЧЕ 0 КОНЕЦ
+ ВЫБОР ПОДСТРОКА(Артикул, 5, 1)КОГДА«1»ТОГДА 1 КОГДА«2»ТОГДА 2 КОГДА«3»ТОГДА 3 КОГДА«4»ТОГДА 4 КОГДА«5»ТОГДА 5 КОГДА«6»ТОГДА 6 КОГДА«7»ТОГДА 7 КОГДА«8»ТОГДА 8 КОГДА«9»ТОГДА 9 ИНАЧЕ 0 КОНЕЦ * 10
+ ВЫБОР ПОДСТРОКА(Артикул, 4, 1)КОГДА«1»ТОГДА 1 КОГДА«2»ТОГДА 2 КОГДА«3»ТОГДА 3 КОГДА«4»ТОГДА 4 КОГДА«5»ТОГДА 5 КОГДА«6»ТОГДА 6 КОГДА«7»ТОГДА 7 КОГДА«8»ТОГДА 8 КОГДА«9»ТОГДА 9 ИНАЧЕ 0 КОНЕЦ * 100
+ ВЫБОР ПОДСТРОКА(Артикул, 3, 1)КОГДА«1»ТОГДА 1 КОГДА«2»ТОГДА 2 КОГДА«3»ТОГДА 3 КОГДА«4»ТОГДА 4 КОГДА«5»ТОГДА 5 КОГДА«6»ТОГДА 6 КОГДА«7»ТОГДА 7 КОГДА«8»ТОГДА 8 КОГДА«9»ТОГДА 9 ИНАЧЕ 0 КОНЕЦ * 1000
+ ВЫБОР ПОДСТРОКА(Артикул, 2, 1)КОГДА«1»ТОГДА 1 КОГДА«2»ТОГДА 2 КОГДА«3»ТОГДА 3 КОГДА«4»ТОГДА 4 КОГДА«5»ТОГДА 5 КОГДА«6»ТОГДА 6 КОГДА«7»ТОГДА 7 КОГДА«8»ТОГДА 8 КОГДА«9»ТОГДА 9 ИНАЧЕ 0 КОНЕЦ * 10000
+ ВЫБОР ПОДСТРОКА(Артикул, 1, 1)КОГДА«1»ТОГДА 1 КОГДА«2»ТОГДА 2 КОГДА«3»ТОГДА 3 КОГДА«4»ТОГДА 4 КОГДА«5»ТОГДА 5 КОГДА«6»ТОГДА 6 КОГДА«7»ТОГДА 7 КОГДА«8»ТОГДА 8 КОГДА«9»ТОГДА 9 ИНАЧЕ 0 КОНЕЦ * 100000 КАК Х
ПОМЕСТИТЬ Числа
ИЗ Дано
ДЛЯ ИЗМЕНЕНИЯ
;
ВЫБРАТЬ
Х,
ЛОЖЬ КАК Свободен
ПОМЕСТИТЬ ЧислаПлюс
ИЗ Числа
ОБЪЕДИНИТЬ
ВЫБРАТЬ
Х + 1,
ИСТИНА
ИЗ Числа
;
ВЫБРАТЬ ПЕРВЫЕ 1
Х КАК ПервыйСвободныйАртикул
ИЗ ЧислаПлюс
СГРУППИРОВАТЬ ПО Х
ИМЕЮЩИЕ КОЛИЧЕСТВО(*) = 1 И МАКСИМУМ(Свободен) = ИСТИНА
Пример приведен для случая шестизначных артикулов.

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

Подсчет записей, содержащих одинаковые неупорядоченные пары значений

http://www.forum.mista.ru/topic.php?id=760508

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

К примеру, для таблицы «два любимых блюда»

 Блюдо1  Блюдо2
Овсянка Омлет
Плов Борщ
Омлет Овсянка
 Пельмени  Шашлык
Борщ Плов

так можно посчитать число различных комбинаций блюд:

Блюдо1 Блюдо2  Количество
Овсянка Омлет 2
Борщ Плов 2
 Пельмени  Шашлык 1

 

Собственно, запрос, решающий данную задачу:
ВЫБРАТЬ А, Б, КОЛИЧЕСТВО(*)
ИЗ (ВЫБРАТЬ А, Б ИЗ Дано ОБЪЕДИНИТЬ ВЫБРАТЬ Б, А ИЗ Дано ГДЕ А <> Б) КАК ВЗ
ГДЕ А <= Б

Определение длины строки в запросе методом половинного деления

http://infostart.ru/public/439822/

В исходной статье был продемонстрирован оригинальный алгоритм определения длины строки в запросе. Однако при высокой скорости вычислений выражение для получения длины строки получается чрезвычайно громозким. На каждую возможную длину строки требуется записать вариант «ТОГДА». В приведенном ниже решении этот недостаток устранен:
ВЫБРАТЬ
Стр, Х
ИЗ (ВЫБРАТЬ Стр, ВЫБОР КОГДА ПОДСТРОКА(Стр, Х 0, 1) = «» ТОГДА Х 1 ИНАЧЕ Х КОНЕЦ КАК Х
ИЗ (ВЫБРАТЬ Стр, ВЫБОР КОГДА ПОДСТРОКА(Стр, Х 1, 1) = «» ТОГДА Х 2 ИНАЧЕ Х КОНЕЦ КАК Х
ИЗ (ВЫБРАТЬ Стр, ВЫБОР КОГДА ПОДСТРОКА(Стр, Х 3, 1) = «» ТОГДА Х 4 ИНАЧЕ Х КОНЕЦ КАК Х
ИЗ (ВЫБРАТЬ Стр, ВЫБОР КОГДА ПОДСТРОКА(Стр, Х 7, 1) = «» ТОГДА Х 8 ИНАЧЕ Х КОНЕЦ КАК Х
ИЗ (ВЫБРАТЬ Стр, ВЫБОР КОГДА ПОДСТРОКА(Стр, Х 15, 1) = «» ТОГДА Х 16 ИНАЧЕ Х КОНЕЦ КАК Х
ИЗ (ВЫБРАТЬ Стр, ВЫБОР КОГДА ПОДСТРОКА(Стр, Х 31, 1) = «» ТОГДА Х 32 ИНАЧЕ Х КОНЕЦ КАК Х
ИЗ (ВЫБРАТЬ Стр, ВЫБОР КОГДА ПОДСТРОКА(Стр, Х 63, 1) = «» ТОГДА Х 64 ИНАЧЕ Х КОНЕЦ КАК Х
ИЗ (ВЫБРАТЬ Стр, ВЫБОР КОГДА ПОДСТРОКА(Стр, Х 127, 1) = «» ТОГДА Х 128 ИНАЧЕ Х КОНЕЦ КАК Х
ИЗ (ВЫБРАТЬ Стр, ВЫБОР КОГДА ПОДСТРОКА(Стр, Х 255, 1) = «» ТОГДА Х 256 ИНАЧЕ Х КОНЕЦ КАК Х
ИЗ (ВЫБРАТЬ Стр, ВЫБОР КОГДА ПОДСТРОКА(Стр, Х 511, 1) = «» ТОГДА Х 512 ИНАЧЕ Х КОНЕЦ КАК Х
ИЗ Дано КАК ВЗ) КАК ВЗ) КАК ВЗ) КАК ВЗ) КАК ВЗ) КАК ВЗ) КАК ВЗ) КАК ВЗ) КАК ВЗ) КАК ВЗ) КАК ВЗ
Для строки длиной до 1024 символов используется система из 10-ти вложенных запросов. Исходная таблица, кроме самой строки, должна содержать начальное значение поиска Х, равное 1024.

ПОИСК КРАТЧАЙШИХ ПУТЕЙ ПО АЛГОРИТМУ ФЛОЙДА-УОРШОЛЛА

http://forum.infostart.ru/forum24/topic144086/

Функция, решающая данную задачу:
Функция КратчайшийПутьФлойд(Откуда, Куда, Дуги) Экспорт
// загрузка графа в «соответствие соответствий» так, что Пути[Откуда][Куда] = Длина
Пути = Новый Соответствие;
Для каждого Дуга Из Дуги Цикл
Пути[Дуга.Откуда] = ?(Пути[Дуга.Откуда] = Неопределено, Новый Соответствие, Пути[Дуга.Откуда]);
Пути[Дуга.Откуда][Дуга.Куда] = Дуга.Длина
КонецЦикла;
// три вложенных цикла по узлам графа
Для каждого Узел1 Из Пути Цикл // тогда Узел.Ключ — это одна вершина из полного множества вершин
Для каждого Узел2 Из Пути Цикл
Если Пути[Узел2.Ключ][Узел1.Ключ] <> Неопределено Тогда
Для каждого Узел3 Из Узел1.Значение Цикл // здесь только вершины, связанные с Узел1.Ключ
Длина = Пути[Узел2.Ключ][Узел3.Ключ];
Обход = Пути[Узел2.Ключ][Узел1.Ключ] + Узел3.Значение; // Узел3.Значение == Пути[Узел1.Ключ][Узел3.Ключ]
Пути[Узел2.Ключ][Узел3.Ключ] = ?(Длина = Неопределено, Обход, Мин(Длина, Обход))
КонецЦикла
КонецЕсли
КонецЦикла
КонецЦикла;
// восстановление пути
Путь = Дуги.СкопироватьКолонки(«Куда, Длина»);
Путь.Добавить().Куда = Откуда;
Путь.Добавить().Куда = Куда;
Путь[1].Длина = Пути[Откуда][Куда];
Для каждого Узел Из Пути Цикл
Если Пути[Откуда][Узел.Ключ] <> Неопределено И Пути[Узел.Ключ][Куда] <> Неопределено
И Пути[Откуда][Узел.Ключ] + Пути[Узел.Ключ][Куда] = Пути[Откуда][Куда] Тогда
ЗаполнитьЗначенияСвойств(Путь.Добавить(), Новый Структура(«Куда, Длина», Узел.Ключ, Пути[Откуда][Узел.Ключ]))
КонецЕсли
КонецЦикла;
Путь.Сортировать(«Длина»);
Возврат Путь
КонецФункции // КратчайшийПуть()
Данное решение иллюстрирует использование соответствия при решении задач на графах. Благодаря этому достигается существенный выигрыш по быстродействию. Например, приведенная функция примерно на 30% опрережает по быстродействию решение задачи поиска пути в московском метро запросом, приведенное в статье «Определение кратчайших путей, критических путей одним запросом».

С другой стороны, и алгоритм Флойда и алгоритм матричного умножения относятся к классу задач «All Pairs Shortest Paths (APSP) problem», то есть для определения расстояния между парой вершин являются избыточными.  В данной задаче (для заданной пары вершин) лучше использовать алгоритм Дейкстры.

КАК СВЕРНУТЬ ТАБЛИЦУ ЗНАЧЕНИЙ В КОДЕ, НО ПОЛУЧИТЬ НЕ СУММУ, А МАКСИМУМ

http://www.forum.mista.ru/topic.php?id=716861

http://www.forum.mista.ru/topic.php?id=760950

С помощью небольшой предварительной обработки таблицы значений можно добиться реализации агрегатных функций минимум, максимум, первые, последние при выполнении свертки. Для этого достаточно обнулить все другие значения в группировках, кроме нужных. Это можно сделать по разному. Например, так
Дано.Сортировать(«Поле1, Поле2»);

Для ё = 1 По Дано.Количество() 1 Цикл
Если Дано[ё].Поле1 = Дано[ё 1].Поле1 И Дано[ё].Поле2 = Дано[ё 1].Поле2 Тогда
Дано[ё].Поле3 = МИН(Дано[ё].Поле3, Дано[ё 1].Поле3); // = МАКС(Дано[ё].Поле3, Дано[ё — 1].Поле3);
Дано[ё 1].Поле3 = 0
КонецЕсли
КонецЦикла;

Дано.Свернуть(«Поле1, Поле2», «Поле3»);
Здесь Поле1, Поле2 — поля группировки, а Поле3 — поле, в котором ищется минимум в группировках.

Заменив функцию МИН на функцию МАКС, получим агрегатную функцию максимум, если убрать первый оператор в цикле, то будут выбираться все последние записи в группировках, а если в цикле оставить только оператор
Дано[ё].Поле3 = 0
то будут выбираться первые значения в группировках.

В обсуждении http://www.forum.mista.ru/topic.php?id=766103 родился еще более короткий вариант:
Дано.Сортировать(«Поле1, Поле2, Поле3 Убыв»); //для МАКС, Дано.Сортировать(«Поле1, Поле2, Поле3»); //для МИН
Для ё = 1 По Дано.Количество() 1 Цикл
Если Дано[ё].Поле1 = Дано[ё 1].Поле1 И Дано[ё].Поле2 = Дано[ё 1].Поле2 Тогда
Дано[ё].Поле3 = 0
КонецЕсли
КонецЦикла;
Дано.Свернуть(«Поле1, Поле2», «Поле3»);
Чтобы не записывать каждый раз конкретные названия полей группировки, можно обобщить приведенный выше фрагмент, задавая строку имен полей группировок:
Дано.Сортировать(ИменаПолейГруппировки);

Для ё = 1 По Дано.Количество() 1 Цикл
Повтор = Истина;
Для каждого Элемент Из Новый Структура(ИменаПолейГруппировки) Цикл
Повтор = Повтор И (Дано[ё][Элемент.Ключ] = Дано[ё 1][Элемент.Ключ])
КонецЦикла;
Если Повтор Тогда
Дано[ё][Ресурс] = МИН(Дано[ё][Ресурс], Дано[ё 1][Ресурс]);
Дано[ё 1][Ресурс] = 0
КонецЕсли
КонецЦикла;

Дано.Свернуть(ИменаПолейГруппировки, Ресурс);
В принципе, можно обойтись и без сортировки, если использовать соответствие. Для случая группировки по одному полю, нужный фрагмент кода будет иметь вид:
Сток = Новый Соответствие;

Для каждого Строка Из Дано Цикл
Ключ = Строка[ПолеГруппировки];
Если Сток[Ключ] = Неопределено Тогда
Сток[Ключ] = Строка
Иначе
Сток[Ключ][Ресурс] = МИН(Сток[Ключ][Ресурс], Строка[Ресурс]);
Строка[Ресурс] = 0
КонецЕсли
КонецЦикла;

Дано.Свернуть(ПолеГруппировки, Ресурс);
 

ВЫБРАТЬ В ЗАПРОСЕ ОДНУ ЗАПИСЬ ИЗ НЕСКОЛЬКИХ

http://www.forum.mista.ru/topic.php?id=764178

Имеется таблица, содержащая, например,  колонки Ф, К1, К2, К3, К4. Для каждого значения Ф в тоблице может быть несколько записей.

Ф  К1  К2  К3  К4
 Петя 1 1 1 1
Петя 2 0 0 0
Петя 3 0 0 0
Вася 5 5 5 5
Женя 4 4 4 4

 

Требуется получить таблицу, включающую по одной (любой) записи для каждого значения Ф.

Ф  К1  К2  К3  К4
 Петя 1 1 1 1
Вася 5 5 5 5
Женя 4 4 4 4

 

Несмотря на простоту формлировки, у задачи нет простого решения, если только не использовать коррелированный запрос. С использованием коррелированного запроса решение получается очень простым:
ВЫБРАТЬ РАЗЛИЧНЫЕ Ф, К1, К2, К3, К4
ИЗ Дано
ГДЕ (Ф, К1, К2, К3, К4)
В (ВЫБРАТЬ ПЕРВЫЕ 1 * ИЗ Дано КАК ВСЁ ГДЕ ВСЁ.Ф = Дано.Ф)
При использовании коррелированных запросов нельзя забывать о подводных камнях этого механизма, в частности о том, что он может служить причиной падения производительности запроса. Кроме того, в некоторых версиях файлового варианта условие ГДЕ из-за ошибки платформы 8.2 не срабатывает.

Алгоритм перебора всех возможных сочетаний элементов

http://forum.infostart.ru/forum86/topic146528/

На входе массив из элементов: {X1, X2, …, Xm}. Требуется составить все возможные сочетания элементов без учета размещения: {X1}, {X2}, …, {Xm}, {X1, X2}, …, {X1, Xm},…,{X2, Xm},…,{X1, X2, …, Xm}. Другими словами, требуется получить все возможные подмножества множества элементов, заданного в исходном массиве.

Вот функция, решающая данную задачу:
Функция ВсеПодмножества(Множество)
Ответ = Новый Массив;
Ответ.Добавить(Новый СписокЗначений);
Для ИндексЭлемента = 0 По Множество.Количество() 1 Цикл
Для ИндексВарианта = 0 По Ответ.Количество() 1 Цикл
Ответ.Добавить(Ответ[ИндексВарианта].Скопировать());
Ответ[ИндексВарианта].Добавить(Множество[ИндексЭлемента])
КонецЦикла
КонецЦикла;
Возврат Ответ
КонецФункции
Результат функции — массив списков значений, содержащих разные подмножества элементов исходного массива. Массив включает и пустое подмножество (на последнем месте).

УДАЛЕНИЕ ПОВТОРЯЮЩИХСЯ СИМВОЛОВ В НАЧАЛЕ ИЛИ КОНЦЕ ТЕКСТА

http://www.forum.mista.ru/topic.php?id=765792

Функции СокрЛ, СокрП, СокрЛП удаляют любое количество пробелов в начале или конце строки. Этим можно воспользоваться, чтобы удалить другие начальные или конечные повторяющиеся символы, заменив их на пробел, а затем выполнив обратную замену. Например, чтобы удалить любое количество точек в конце строки, можно воспользоваться выражением:
СтрЗаменить(СокрП(СтрЗаменить(ИсходнаяСтрока, «.», » «)), » «, «.»)
Правда, если исходная строка изначально содержит пробелы, то результат будет неправильным. В этом случае предварительно требуется заменить пробелы каким-либо редким сочетанием символов, а после преобразования выполнить обратную замену.
СтрЗаменить(СтрЗаменить(СокрП(СтрЗаменить(СтрЗаменить(ИсходнаяСтрока, » «, Символы.НПП), «.», » «)), » «, «.»), Символы.НПП, » «)

Определение длины строки в запросе

Это тема из обсуждения «Как с помощью запроса посчитать количество символов в реквизите»
ВЫБРАТЬ
Дано.НомерСтроки,
Дано.Строка
ПОМЕСТИТЬ Дано
ИЗ
&Дано КАК Дано
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
0 КАК ё
ПОМЕСТИТЬ Р0

ОБЪЕДИНИТЬ

ВЫБРАТЬ
1
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
2 * Р1.ё + Р0.ё КАК ё
ПОМЕСТИТЬ Р10
ИЗ
Р0 КАК Р1,
Р0 КАК Р0
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
4 * Р32.ё + Р10.ё КАК ё
ПОМЕСТИТЬ Р3210
ИЗ
Р10 КАК Р32,
Р10 КАК Р10
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
16 * Р54.ё + Р3210.ё + 1 КАК ё
ПОМЕСТИТЬ Р543210
ИЗ
Р10 КАК Р54,
Р3210 КАК Р3210
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Дано.НомерСтроки,
Дано.Строка,
МАКСИМУМ(Р543210.ё) КАК ДлинаСтроки
ИЗ
Дано КАК Дано,
Р543210 КАК Р543210
ГДЕ
ПОДСТРОКА(Дано.Строка, Р543210.ё, 1) + «!» <> «!»

СГРУППИРОВАТЬ ПО
Дано.НомерСтроки,
Дано.Строка
 

Простой трюк для быстрого объединения таблиц значений

Стандартный способ объединения двух таблиц значений заключается в организации цикла, в котором строки второй таблицы приписываются в конец копии первой. Для этого используется следующий простой код:
ОбъединениеТаблиц = Таблица1.Скопировать();
Для Каждого Строка Из Таблица2 Цикл ЗаполнитьЗначенияСвойств(ОбъединениеТаблиц.Добавить(), Строка) КонецЦикла
Все возможности оптимизация данного способа ограничиваются записью в одну строку и выбором таблицы с меньшим количеством элементов в качестве источника добавляемых строк.

Предлагаемый трюк заключается в последовательном выполнении трех действий:

1)      Вторая (добавляемая) таблица копируется в таблицу-результат;

2)      В начало таблицы результата перед уже скопированной таблицей вставляется столько пустых строк, сколько строк в первой таблице. Таким образом «освобождается место» для первой таблицы;

3)      Затем первая таблица помещается на освобожденное место методом выгрузки-загрузки колонок.  Фокус в том, что при загрузке колонки в таблицу значений, если загружаемая колонка короче целевой, то оставшиеся элементы целевой колонки не меняются.

Схематичное описание той же последовательности действий приведено на рисунке ниже

Схема

Реализация предложенного способа очень проста и выполняется следующим фрагментом программного кода:
ОбъединениеТаблиц = Таблица2.Скопировать();
Для ё = 1 По Таблица1.Количество() Цикл ОбъединениеТаблиц.Вставить(0) КонецЦикла;
Для ё = 0 По Таблица1.Колонки.Количество() 1 Цикл
ОбъединениеТаблиц.ЗагрузитьКолонку(Таблица1.ВыгрузитьКолонку(ё), ё)
КонецЦикла;
Колонок в таблицах значений обычно всегда значительно меньше, чем строк. Поэтому такой способ содержит меньше отдельных действий и в результате выполняется платформой быстрее построчного копирования. Ускорение зависит от соотношения числа строк и столбцов и может достигать полутора раз.

ПОЛУЧЕНИЕ ТАБЛИЦЫ И МАССИВА, ЗАПОЛНЕННЫХ ПОСЛЕДОВАТЕЛЬНОСТЬЮ ЧИСЕЛ ОТ 0 ДО N-1

Иногда бывает нужно быстро получить готовый массив с последовательностью чисел от 0 до N-1. Например, чтобы пронумеровать строки таблицы значений путем загрузки в нее колонки с номерами строк. Это можно очень быстро сделать, используя«Порождающий запрос». Все необходимые функции очень компактны. Поэтому они приведены здесь.

// Возвращает текст запроса, формирующего таблицу чисел rN с одной колонкой X (eng), содержащую ряд: 0, 1, (N — 1).
function ProtoText(N, M = 1000000000) export
return ?(N > 2
, ProtoText(M Int(M Sqrt(N)))
+ strreplace(strreplace(«;select top #2 a.X * #1 + b.X X into r#2 from r#1 a, r#1 b», «#2», format(N, «NG=»)), «#1», format(M Int(M Sqrt(N)), «NG=»))
, «select 0 X into r2 union select 1»)
endfunction

// Возвращает таблицу, содержащую последовательность чисел: 0, 1, 2, …, (ЧислоСтрок — 1)
Функция ПоследовательностьЧиселТаблицей(ЧислоСтрок) Экспорт
Запрос = Новый Запрос(СтрЗаменить(ProtoText(ЧислоСтрок), «into r» + format(ЧислоСтрок, «NG=»), «»));
Возврат Запрос.Выполнить().Выгрузить()
КонецФункции

// Возвращает массив, содержащий последовательность чисел: 0, 1, 2, …, (ЧислоЭлементов — 1)
Функция ПоследовательностьЧиселМассивом(ЧислоЭлементов) Экспорт
Возврат ПоследовательностьЧиселТаблицей(ЧислоЭлементов).ВыгрузитьКолонку(0)
КонецФункции

ДОБАВИТЬ К ДАТЕ И РАЗНОСТЬ ДАТ

Функции для работы с датами как в языке запросов

http://infostart.ru/public/308429/
Функция ДобавитьКДате(Дата1, Количество, Период) Экспорт
Шаг = Новый Структура(«Год, Квартал, Месяц, Неделя, День, Час, Минута, Секунда», 12, 3, 1, 604800, 86400, 3600, 60, 1);
Возврат ?(Шаг[Период] > 0, ДобавитьМесяц(Дата1, Количество * Шаг[Период]), Дата1 Количество * Шаг[Период])
КонецФункции
Функция РазностьДат(Дата1, Дата2, Период) Экспорт
Шаг = Новый Структура(«Год, Квартал, Месяц, Неделя, День, Час, Минута, Секунда», 12, 3, 1, 604800, 86400, 3600, 60, 1);
Возврат Цел(?(Шаг[Период] > 0, Год(Дата2) * 12 + Месяц(Дата2) 1, ‘00010101’ Дата2) / Шаг[Период])
Цел(?(Шаг[Период] > 0, Год(Дата1) * 12 + Месяц(Дата1) 1, ‘00010101’ Дата1) / Шаг[Период])
КонецФункции
ну и раз зашла речь о датах…

Функция Квартал
Функция Квартал(Дата) Экспорт
Возврат Цел((Месяц(Дата) 1) / 3) + 1
КонецФункции

Названия месяцев прописью

Формат(Дата(1, НомерМесяца, 1),«ДФ=ММММ»)

Название дней недели прописью

Формат(Дата(1, 1, 2 + НомерДняНедели),«ДФ=дддд»)

СЖАТОЕ ПРЕДСТАВЛЕНИЕ ПОСЛЕДОВАТЕЛЬНОСТИ ДАТ ЗАПРОСОМ

http://forum.infostart.ru/forum26/topic112033/message1160294/#message1160294

Задача похожа на сжатое представление ряда чисел, только роль чисел играют даты. Дана последовательность дат. Нужно заменить ее последовательностью непрерывных интервалов дат. Вот решение

ВЫБРАТЬ
Даты.Дата,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ДатыДо.Дата) КАК Номер
ПОМЕСТИТЬ НомераДат
ИЗ
ВТДаты КАК Даты
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТДаты КАК ДатыДо
ПО (ДатыДо.Дата < = Даты.Дата)
СГРУППИРОВАТЬ ПО
Даты.Дата
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
МИНИМУМ(НомераДат.Дата) КАК ДатаНач,
МАКСИМУМ(НомераДат.Дата) КАК ДатаКон
ИЗ
НомераДат КАК НомераДат
СГРУППИРОВАТЬ ПО
ДОБАВИТЬКДАТЕ(НомераДат.Дата, ДЕНЬ, НомераДат.Номер)

ФУНКЦИЯ ДЛЯ ПРЕВРАЩЕНИЯ СТРОКИ В ДАТУ ПО ФОРМАТНОЙ СТРОКЕ

http://infostart.ru/public/200111/

Функция СтрокаВДату(Знач ФорматДаты, Знач Дано, Ошибка = Ложь) Экспорт
Попытка
ё = Формат(‘00010101’, «ДФ=» + ФорматДаты) // — необязательная проверка первого правильности параметра
Исключение
Ошибка = Истина;
Возврат ‘00010101’
КонецПопытки;
Ч = Новый Соответствие;
Для ё = 1 По СтрДлина(ФорматДаты) + 7 Цикл
Ч[Сред(ФорматДаты + «dMyHhms», ё, 1)] = 0 // — инициализация частей даты
КонецЦикла;
Для ё = 1 По 12 Цикл
Дано = СтрЗаменить(Дано, Формат(Дата(1, ё, 1), «ДФ=MMММ»), Формат(ё, «ЧЦ=4; ЧВН=»)); // — замена названий месяцев числами
Дано = СтрЗаменить(Дано, Формат(Дата(1, ё, 1), «ДФ=MMМ» ), Формат(ё, «ЧЦ=3; ЧВН=»))
КонецЦикла;
Для ё = 1 По СтрДлина(ФорматДаты) Цикл
Ч[Сред(ФорматДаты, ё, 1)] = 10 * Ч[Сред(ФорматДаты, ё, 1)] + Найти(«123456789», Сред(Дано, ё, 1)); // — накопление частей даты
Ошибка = Ошибка ИЛИ Найти(«dMyHhms», Сред(ФорматДаты, ё, 1)) И НЕ Найти(«0123456789», Сред(Дано, ё, 1)) // — необязательная проверка на цифры
КонецЦикла;
Ч[«y»] = Ч[«y»] + ?(Ч[«y»] < 50, 2000, ?(Ч[«y»] < 100, 1900, 0)); // — дополнение двух цифр года до четырех
Попытка
Возврат Дата(Ч[«y»], Ч[«M»], Ч[«d»], Ч[«H»] + Ч[«h»], Ч[«m»], Ч[«s»])
Исключение
Ошибка = Истина;
Возврат ‘00010101’
КонецПопытки
КонецФункции

Сравнение двух строк

http://infostart.ru/public/174530/

Результатом сравнения двух строк является массив, который показывает, что от «От» до «До» позиции строки совпадают (ОК = Истина) или нет.

Функция ТаблицаСравненияСтрок_(С1, С2) Экспорт
Ответ = Новый ТаблицаЗначений; //Ответ = НоваяТаблицаЗначений(«От, До, ОК»);
Ответ.Колонки.Добавить(«От»);
Ответ.Колонки.Добавить(«До»);
Ответ.Колонки.Добавить(«ОК»);
ЗаполнитьЗначенияСвойств(Ответ.Добавить(), Новый Структура(«От, ОК», 1, Сред(С1, 1, 1) = Сред(С2, 1, 1)));
Для ё = 2 По Макс(СтрДлина(С1), СтрДлина(С2)) Цикл
Если Ответ[0].ОК <> (Сред(С1, ё, 1) = Сред(С2, ё, 1)) Тогда
ЗаполнитьЗначенияСвойств(Ответ.Вставить(0), Новый Структура(«От, ОК», ё, НЕ Ответ[1].ОК));
Ответ[1].До = ё 1
КонецЕсли
КонецЦикла;
Ответ[0].До = Макс(СтрДлина(С1), СтрДлина(С2));
Возврат Ответ
КонецФункции

С дихотомией

Процедура РазДва(Ответ, С1, С2, От, До)
Если От + 2 > До И (Сред(С1, От, 1) = Сред(С2, От, 1)) <> (Сред(С1, До, 1) = Сред(С2, До, 1)) Тогда
ЗаполнитьЗначенияСвойств(Ответ.Вставить(0), Новый Структура(«От, ОК», До, НЕ Ответ[1].ОК));
Ответ[1].До = От
ИначеЕсли От + 1 < До И Сред(С1, От, До От + 1) <> Сред(С2, От, До От + 1) Тогда
РазДва(Ответ, С1, С2, От, Цел((От + До) / 2));
РазДва(Ответ, С1, С2, Цел((От + До) / 2), До)
КонецЕсли
КонецПроцедуры
Функция ТаблицаСравненияСтрок(С1, С2) Экспорт
Ответ = Новый ТаблицаЗначений;
Ответ.Колонки.Добавить(«От»);
Ответ.Колонки.Добавить(«До»);
Ответ.Колонки.Добавить(«ОК»);
ЗаполнитьЗначенияСвойств(Ответ.Добавить(), Новый Структура(«От, ОК», 1, Сред(С1, 1, 1) = Сред(С2, 1, 1)));
РазДва(Ответ, С1, С2, 1, Макс(СтрДлина(С1), СтрДлина(С2)));
Ответ[0].До = Макс(СтрДлина(С1), СтрДлина(С2));
Возврат Ответ
КонецФункции

СВЯЗЫВАНИЕ ТАБЛИЦ ЗНАЧЕНИЙ ПО ФИФО

Если имеется две таблицы с колонками: Период, Документ, Сумма, то часто возникает задача построения объединенной таблицы «Результат» с колонками Период1, Документ1, Период2, Документ2, Сумма, в которой документы двух таблиц связаны по ФИФО. Чтобы функция Результат.Свернуть(«Период1,Документ1», «Сумма») давала первую таблицу, а Результат.Свернуть(«Период2,Документ2», «Сумма») — вторую. 

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

Вот требуемая функция. Осторожнее, так как она меняет исходные таблицы!
Функция СвязываниеПоФИФО(А, Б, ё = 0, ж = 0) Экспорт
Результат = НовыйТаблицаЗначений(«Период1, Документ1, Период2, Документ2, Сумма»);
Пока ё < А.Количество() И ж < Б.Количество() Цикл
Сумма = Мин(А[ё].Сумма, Б[ж].Сумма);
ЗаполнитьЗначенияСвойств(Результат.Добавить()
, Новый Структура(«Период1, Документ1, Период2, Документ2, Сумма»
, А[ё].Период, А[ё].Документ, Б[ж].Период, Б[ж].Документ, Сумма));
А[ё].Сумма = А[ё].Сумма Сумма;
Б[ж].Сумма = Б[ж].Сумма Сумма;
ё = ё + (А[ё].Сумма = 0);
ж = ж + (Б[ж].Сумма = 0)
КонецЦикла;
Возврат Результат
КонецФункции

Остатки на каждый день

http://infostart.ru/public/102435/

Стандартная выборка из виртуального регистра остатков и оборотов не показывает остатки на периодах, в которых нет оборотов. В СКД, то есть вне запроса проблема легко решается, а для использования внутри запроса приходится «городить огород». У многих это выливается в несколько запросов, тогда как можно обойтись и одним. Остатки здесь получаются суммированием оборотов. По тому же принципу платформа рассчитывает остатки внутри периода хранения итогов.
ВЫБРАТЬ РАЗЛИЧНЫЕ
КурсыВалют.Период
ПОМЕСТИТЬ Дни
ИЗ
РегистрСведений.КурсыВалют КАК КурсыВалют
ГДЕ
КурсыВалют.Период МЕЖДУ &НачалоПериода И &КонецПериода
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Движения.Номенклатура,
ДНИ.Период,
СУММА(ВЫБОР
КОГДА Движения.Период = &НачалоПериода
ТОГДА Движения.КоличествоКонечныйОстаток
ИНАЧЕ ВЫБОР
КОГДА Движения.Период < = ДНИ.Период
ТОГДА Движения.КоличествоОборот
ИНАЧЕ 0
КОНЕЦ
КОНЕЦ) КАК КоличествоКонечныйОстаток
ИЗ
Дни КАК ДНИ,
РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, День, , Номенклатура = &Номенклатура) КАК Движения

СГРУППИРОВАТЬ ПО
Движения.Номенклатура,
ДНИ.Период

Правда, здесь рассчитываются остатки на конец каждого дня (это легко поправить, сдвинув даты на -1). Регистр «КурсыВалют» взят для краткости и для разнообразия — все даты внутри периода можно получать и по другому. Классический вариант проигрывает по быстродействию предложенному примерно в 1.5 раза (проверялось на файловой базе УПП).

СРЕЗЫ ПОСЛЕДНИХ (ИНТЕРПОЛЯЦИЯ ПЕРИОДИЧЕСКИХ СВЕДЕНИЙ)

http://infostart.ru/public/77568/

«Срезы последних» — одна из первых задач, на которой спотыкается начинающий программист 1С. Хорошо поняв идею виртуального регистра «Срез последних», мы ожидаем такой же простоты, если задана не одна дата, на которую нужно выбрать сведения, а несколько. Но, увы, приходится использовать два запроса. В первом мы выбираем ближайшие в прошлом даты, на которые были установлены значения, а во втором по датам определяем сами значения.

Оказывается, при большом желании можно уложиться в один запрос. Вот этот запрос для примера решения задачи «Продажи с выводом цены заданного типа, действующей на момент отгрузки».
ВЫБРАТЬ
Продажи.Период,
Продажи.Контрагент,
Продажи.Номенклатура,
СУММА(Продажи.КоличествоОборот) КАК Количество,
СУММА(Продажи.СтоимостьОборот) КАК Стоимость,
МИНИМУМ(РАЗНОСТЬДАТ(ЦеныНоменклатуры.Период, Продажи.Период, ДЕНЬ) * &Много + ЦеныНоменклатуры.Цена)
МИНИМУМ(РАЗНОСТЬДАТ(ЦеныНоменклатуры.Период, Продажи.Период, ДЕНЬ) * &Много) КАК Цена
ИЗ
РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, День, ) КАК Продажи
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры КАК ЦеныНоменклатуры
ПО Продажи.Номенклатура = ЦеныНоменклатуры.Номенклатура
И (ЦеныНоменклатуры.ТипЦен = &ТипЦен)
И (ЦеныНоменклатуры.Период < = Продажи.Период)
СГРУППИРОВАТЬ ПО
Продажи.Период,
Продажи.Контрагент,
Продажи.Номенклатура

Идея в том, чтобы вместо поиска периода, на котором начинается актуальная цена, искать саму цену. Для этого подобрана функция, которая «отправляет» цену прошлого периода на свой «эшелон», высота которого зависит от древности цены. Ширина «эшелона» задается параметром «Много» — это величина, гарантированно перекрывающая диапазон изменения цены (1000000, 10000000 и т.п.). После нахождения ближайшей (нижайшей) «летящей» цены, высота соответствующего «эшелона» вычитается и цена «опускается на землю».

Можно подобрать функцию для дат, булевых и строковых значений.

Кроме краткости записи, других достоинств у запроса нет. Минусы — некоторый проигрыш по времени «классическому» запросу из-за большего объема вычислений в группировках, необходимость думать над значением «Много», работа только с простыми типами.

Вообще, вместе с этим, известно четыре способа интерполяции. Интересно было бы провести вычислительный эксперимент по сравнению их эффективности. Пока всегда выигрывал классический способ.

Сортировка слиянием

http://infostart.ru/public/70024/

Дано два отсортированных по возрастанию массива А и В. Необходимо вывести по возрастанию все элементы этих массивов.

ёж = 0;
Для уж = 0 По А.Количество() + В.Количество() 1 Цикл
що = (уж ёж) = В.Количество() ИЛИ ёж < А.Количество() И А[ёж] < В[уж ёж];

Сообщить(?(що, «а» + ёж + «=» + А[ёж], «в» + (уж ёж) + «=» + В[уж ёж]));
ёж = ёж + що
КонецЦикла

ё = 0;
Для Сч = 1 По А.Количество() + В.Количество() Цикл
ж = (Сч 1 ё) = В.Количество() ИЛИ ё < А.Количество() И А[ё] < В[Сч 1 ё];
Сообщить(?(ж, «А[» + ё + «]=» + А[ё], «В[» + (Сч 1 ё) + «]=» + В[Сч 1 ё]));
ё = ё + ж
КонецЦикла

КОЛОНКА СЖАТО

http://infostart.ru/public/82347/

Суть задачи в том, что в колонке табличной части находятся целые числа. Необходимо «сжать» ряд чисел, заменив подряд идущие числа их диапазоном.

Например: 1, 3, 4, 5, 7, 10, 11, 12, 16 должно превратиться в 1, 3-5, 7, 10-12, 16.

Функция КолонкаСжато(ДокументСсылка, ИмяТабличнойЧасти, ИмяКолонки, Слэш = «,», Тире = «-«)
Запрос = Новый Запрос(«ВЫБРАТЬ Различные » + ИмяКолонки + » ИЗ Документ.» + ДокументСсылка.Метаданные().Имя + «.» + ИмяТабличнойЧасти + » ГДЕ Ссылка = &Ссылка Упорядочить ПО » + ИмяКолонки);
Запрос.УстановитьПараметр(«Ссылка», ДокументСсылка);
Ряд = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку(ИмяКолонки);
Если Ряд.Количество() = 0 Тогда Возврат «»
КонецЕсли;
Ряд.Добавить(0); Ряд.Добавить(0);
Сжато = Строка(Ряд[0]);
Для ё = 1 По Ряд.Количество() 3 Цикл
Если Число(Ряд[ё + 1]) Число(Ряд[ё 1]) <> 2 Тогда
Сжато = Сжато + Слэш + Строка(Ряд[ё])
ИначеЕсли Число(Ряд[ё + 2]) Число(Ряд[ё]) <> 2 Тогда
Сжато = Сжато + Тире
КонецЕсли
КонецЦикла;
Возврат СтрЗаменить(Сжато, Тире + Слэш, Тире)
КонецФункции

Квайн (программа, распечатывающая свой собственный текст)

http://infostart.ru/public/87861/

С=«С=»»;Л=Лев(С,3);П=Сред(С,3);Сообщить(Л+Л+П+П)»;Л=Лев(С,3);П=Сред(С,3);Сообщить(Л+Л+П+П)

Процедура КВН(К)С=«Процедура КВН(К)С=»»;Л=Лев(С,19);П=Сред(С,19);Сообщить(Л+Л+П+П)КонецПроцедуры»;Л=Лев(С,19);П=Сред(С,19);Сообщить(Л+Л+П+П)КонецПроцедуры