Выбрать дату в календареВыбрать дату в календаре

Страницы: 1
Вычислить формулу из цифр и букв, Преобразовать цифры и буквы в формулу и вычислить результат
 
Код
Option Explicit

Sub CalculateProductFromFormattedString()

    ' --- Константы ---
    ' Имя листа, на котором находится столбец с данными
    Const TargetSheetName As String = "Лист1" ' <--- ИЗМЕНИТЕ НА ИМЯ ВАШЕГО ЛИСТА (например, "Данные")

    ' Диапазон ячеек с исходными данными (столбец, например, "A1:A10" или "B2:B100")
    Const DataRangeAddress As String = "A1:A10" ' <--- ИЗМЕНИТЕ НА НУЖНЫЙ ДИАПАЗОН С ВАШИМИ ДАННЫМИ

    ' Диапазон ячеек для записи результатов (произведения).
    ' Может быть тот же столбец, если вы хотите заменить исходные данные результатом,
    ' или другой столбец (например, "B1:B10"), куда будут записаны результаты.
    ' Убедитесь, что размер и количество ячеек в диапазоне результатов соответствует диапазону данных.
    Const ResultRangeAddress As String = "B1:B10" ' <--- ИЗМЕНИТЕ НА ДИАПАЗОН ДЛЯ ЗАПИСИ РЕЗУЛЬТАТОВ

    ' --- Переменные ---
    Dim ws As Worksheet          ' Объект листа Excel
    Dim dataRng As Range         ' Объект диапазона с исходными данными
    Dim resultRng As Range       ' Объект диапазона для записи результатов
    Dim dataCell As Range        ' Объект для перебора каждой ячейки в диапазоне данных
    Dim resultCell As Range      ' Объект для записи результата в соответствующую ячейку
    Dim cellValue As Variant     ' Значение, прочитанное из ячейки (может быть пустым)
    Dim cellText As String       ' Значение ячейки как строка для обработки
    Dim cleanedText As String    ' Строка после удаления лишних символов (" д")
    Dim numbersArray() As String ' Массив строк с числами после разделения
    Dim product As Double        ' Переменная для хранения произведения чисел
    Dim numStr As Variant        ' Переменная для перебора элементов массива чисел (как строк)
    Dim numValue As Double       ' Переменная для хранения числового значения после преобразования
    Dim i As Long                ' Счетчик для синхронизации ячеек в диапазонах данных и результатов

    ' --- Настройка ---
    ' Включаем обработку ошибок. Если произойдет ошибка, выполнение перейдет к метке ErrorHandler.
    On Error GoTo ErrorHandler
    ' Отключаем обновление экрана для ускорения работы макроса на больших диапазонах.
    Application.ScreenUpdating = False
    ' Возможно, потребуется отключить автоматический пересчет, если у вас много формул.
    ' Application.Calculation = xlCalculationManual

    ' --- Получение объектов листа и диапазонов ---
    ' Временно отключаем обработку ошибок, чтобы проверить существование листа и диапазонов
    On Error Resume Next
    Set ws = ThisWorkbook.Sheets(TargetSheetName)
    Set dataRng = ws.Range(DataRangeAddress)
    Set resultRng = ws.Range(ResultRangeAddress) ' Получаем диапазон для результатов

    ' Восстанавливаем стандартную обработку ошибок
    On Error GoTo ErrorHandler

    ' Проверяем, найдены ли лист и диапазоны
    If ws Is Nothing Then
        MsgBox "Ошибка: Лист с именем """ & TargetSheetName & """ не найден.", vbCritical
        GoTo ExitMacro
    End If

    If dataRng Is Nothing Then
        MsgBox "Ошибка: Некорректный адрес диапазона данных """ & DataRangeAddress & """ на листе """ & TargetSheetName & """.", vbCritical
        GoTo ExitMacro
    End If

    If resultRng Is Nothing Then
        MsgBox "Ошибка: Некорректный адрес диапазона результатов """ & ResultRangeAddress & """ на листе """ & TargetSheetName & """.", vbCritical
        GoTo ExitMacro
    End If

    ' Проверяем, что количество ячеек в диапазонах данных и результатов совпадает
    If dataRng.Cells.Count <> resultRng.Cells.Count Then
         MsgBox "Ошибка: Количество ячеек в диапазоне данных (" & dataRng.Address(False, False) & ") " & _
                "и диапазоне результатов (" & resultRng.Address(False, False) & ") не совпадает." & vbCrLf & _
                "Эти диапазоны должны иметь одинаковый размер (например, A1:A10 и B1:B10, или A1:A10 и A1:A10).", vbCritical
         GoTo ExitMacro
    End If


    ' --- Обработка каждой ячейки в диапазоне данных ---
    i = 1 ' Инициализируем счетчик для доступа к соответствующей ячейке в диапазоне результатов

    For Each dataCell In dataRng.Cells
        ' Определяем соответствующую ячейку в диапазоне результатов
        Set resultCell = resultRng.Cells(i)

        ' Читаем значение из текущей ячейки данных
        cellValue = dataCell.Value

        ' Проверяем, пуста ли ячейка или содержит ошибку
        If IsEmpty(cellValue) Or IsError(cellValue) Then
            resultCell.Value = cellValue ' Копируем пустоту или ошибку в ячейку результата
            i = i + 1
            GoTo NextCell ' Переходим к следующей ячейке данных
        End If

        ' Преобразуем значение в текст и убираем лишние пробелы по краям
        cellText = Trim(CStr(cellValue))

        ' Проверяем, не стала ли строка пустой после Trim
        If cellText = "" Then
            resultCell.Value = "" ' Если пустая строка, оставляем ячейку результата пустой
            i = i + 1
            GoTo NextCell
        End If

        ' --- Очистка строки от лишних символов ---
        ' Удаляем " д" (пробел + "д"). Важно удалить пробел перед "д".
        cleanedText = Replace(cellText, " д", "")
        ' Также удаляем просто "д", если вдруг нет пробела перед ней
        cleanedText = Replace(cleanedText, "д", "")
         ' Удаляем возможные лишние пробелы в начале или конце после удаления "д"
        cleanedText = Trim(cleanedText)

        ' --- Разделение строки на отдельные числа ---
        ' Разделяем очищенную строку на массив строк, используя " x " как разделитель.
        ' Split("1 x 2 x 3", " x ") вернет массив: {"1", "2", "3"}
        ' Split("4", " x ") вернет массив: {"4"}
        numbersArray = Split(cleanedText, " x ")

        ' --- Вычисление произведения ---
        product = 1 ' Инициализируем произведение единицей (чтобы первое число умножилось на 1)
        Dim conversionError As Boolean ' Флаг для отслеживания ошибок преобразования

        ' Перебираем каждую строку-число в полученном массиве
        For Each numStr In numbersArray
            ' Убираем лишние пробелы из текущей строки-числа
            numStr = Trim(CStr(numStr)) ' Убедимся, что это строка перед Trim

            ' Проверяем, не пустая ли строка после Trim (может быть при двойном разделителе " x x ")
            If numStr <> "" Then
                ' Пытаемся преобразовать строку в число (Double для поддержки десятичных)
                On Error Resume Next ' Временно игнорируем ошибку при преобразовании в число
                numValue = CDbl(numStr)
                On Error GoTo ErrorHandler ' Восстанавливаем стандартную обработку ошибок

                ' Проверяем, была ли ошибка преобразования (например, если в строке не число)
                If Err.Number <> 0 Then
                    ' Если произошла ошибка при преобразовании, помечаем флаг и выходим из внутреннего цикла
                    conversionError = True
                    Exit For
                End If

                ' Умножаем текущее число на текущее произведение
                product = product * numValue
            End If
        Next numStr ' Переходим к следующему элементу в массиве чисел

        ' --- Запись результата ---
        ' Проверяем, не было ли ошибок при преобразовании чисел
        If conversionError Then
            ' Если была ошибка преобразования, записываем сообщение об ошибке в ячейку результата
            resultCell.Value = "Ошибка данных: " & cleanedText
        Else
             ' Если ошибок не было, записываем вычисленное произведение
            resultCell.Value = product
        End If


NextCell: ' Метка для перехода к следующей ячейке данных в цикле For Each
        i = i + 1 ' Увеличиваем счетчик ячеек
    Next dataCell ' Переходим к следующей ячейке в диапазоне данных

    ' --- Сообщение об успешном завершении ---
    MsgBox "Расчеты завершены.", vbInformation

ExitMacro:
    ' --- Секция завершения макроса (выполняется всегда при выходе, включая ошибки) ---
    ' Включаем обратно обновление экрана
    Application.ScreenUpdating = True

    ' Если отключали автоматический пересчет, включаем его обратно
    ' If Application.Calculation = xlCalculationManual Then Application.Calculation = xlCalculationAutomatic

    ' Очищаем используемые объекты
    Set ws = Nothing
    Set dataRng = Nothing
    Set resultRng = Nothing
    Set dataCell = Nothing
    Set resultCell = Nothing

    Exit Sub ' Завершаем выполнение макроса

ErrorHandler:
    ' --- Обработчик ошибок ---
    ' Если произошла непредвиденная ошибка
    MsgBox "Произошла ошибка № " & Err.Number & ": " & Err.Description & vbCrLf & _
           "Макрос будет завершен." & vbCrLf & _
           "При обработке ячейки: " & dataCell.Address(False, False) & vbCrLf & _
           "Исходное значение: """ & cellValue & """", vbCritical
    Resume ExitMacro ' Переходим к секции завершения для корректного выхода
End Sub
One tap - one kill
Автообновление Динамического источника данных (Яндекс API) Power BI
 
Цитата
написал:
Expression.Error: Не удается преобразовать значение типа Binary в тип Text.
Сведения:
   Value=[Binary]
   Type=[Type]
Ошибка возникает потому, что функция Json.FromValue() уже возвращает значение типа Binary, но происходит попытка преобразовать его в Binary снова с помощью Text.ToBinary(). Это вызывает конфликт типов данных.

Нужно использовать только Json.FromValue() без Text.ToBinary():
Код
Content = Json.FromValue([
    date1 = "2025-02-10",
    date2 = "2025-02-15",
    fields = {"ym:s:clientID", "ym:s:counterUserIDHash", "ym:s:eventsProductEventTime", "ym:s:eventsProductType"},
    source = "visits"
])
Либо, если нужно использовать Text.ToBinary(), сначала преобразуйте JSON в текст:
Код
Content = Text.ToBinary(Text.FromBinary(Json.FromValue([
    date1 = "2025-02-10",
    date2 = "2025-02-15",
    fields = {"ym:s:clientID", "ym:s:counterUserIDHash", "ym:s:eventsProductEventTime", "ym:s:eventsProductType"},
    source = "visits"
])))

Что касается вопроса о том, где можно найти информацию о работе с API в Power BI, то, безусловно, рекомендую соответствующее сообщество на Reddit, потом можете чекнуть Chris Webb, ну и документацию Microsoft по работе с Web.Contents(), там вроде и динамические источники данных описываются, если память не изменяет :)
One tap - one kill
Создание меры для выведения в таблицу TOP N в разрезе подразделений PQ или PBI, Прошу помощи с написанием меры TOPN или любой другой меры для вывода ТОП 3 по продажам продукции в подразделении за определенный период
 

Цитата
написал:
К сожалению нужно формулой ((

Код
ТОП N Продажи = 
VAR N = 3
VAR ТекущееПодразделение = SELECTEDVALUE(Подразделение[Подразделение])
VAR ТопТоваровТаблица = 
    TOPN(
        N,
        SUMMARIZE(
            FILTER(Продажи, Продажи[Подразделение] = ТекущееПодразделение),
            Продукция[Товар],
            "СуммаПродаж", SUM(Продажи[Сумма])
        ),
        [СуммаПродаж], DESC
    )
RETURN
    CALCULATE(
        SUM(Продажи[Сумма]),
        KEEPFILTERS(ТопТоваровТаблица)
    )

Эта мера работает следующим образом:

  1. Определяет количество товаров в топе (N = 3)

  2. Получает текущее выбранное подразделение

  3. Создает таблицу с топ N товарами для этого подразделения, сортируя их по сумме продаж

  4. Возвращает сумму продаж только для этих топ N товаров

Если также нужно отображать категорию "Остальные" для товаров, не попавших в топ, можно использовать следующую меру:
Код
ТОП N с Остальными = 
VAR N = 3 // Количество товаров в топе
VAR ТекущееПодразделение = SELECTEDVALUE(Подразделение[Подразделение])
VAR ТопТоваровТаблица = 
    TOPN(
        N,
        SUMMARIZE(
            FILTER(Продажи, Продажи[Подразделение] = ТекущееПодразделение),
            Продукция[Товар],
            "СуммаПродаж", SUM(Продажи[Сумма])
        ),
        [СуммаПродаж], DESC
    )
VAR ТопПродажи = 
    CALCULATE(
        SUM(Продажи[Сумма]),
        KEEPFILTERS(ТопТоваровТаблица)
    )
VAR ОбщиеПродажи = 
    CALCULATE(
        SUM(Продажи[Сумма]),
        FILTER(Продажи, Продажи[Подразделение] = ТекущееПодразделение)
    )
VAR ОстальныеПродажи = ОбщиеПродажи - ТопПродажи
VAR ТекущийТовар = SELECTEDVALUE(Продукция[Товар])
RETURN
    IF(
        CONTAINS(ТопТоваровТаблица, Продукция[Товар], ТекущийТовар),
        ТопПродажи,
        IF(ТекущийТовар = "Остальные", ОстальныеПродажи, BLANK())
    )

Чтобы добавить фильтр по дате, можно модифицировать меру, добавив условие по дате в FILTER:
Код
ТОП N Продажи по Периоду = 
VAR N = 3
VAR НачалоПериода = DATE(2025, 1, 1) // Начало периода
VAR КонецПериода = DATE(2025, 1, 31) // Конец периода
VAR ТекущееПодразделение = SELECTEDVALUE(Подразделение[Подразделение])
VAR ТопТоваровТаблица = 
    TOPN(
        N,
        SUMMARIZE(
            FILTER(
                Продажи, 
                Продажи[Подразделение] = ТекущееПодразделение && 
                Продажи[Дата] >= НачалоПериода && 
                Продажи[Дата] <= КонецПериода
            ),
            Продукция[Товар],
            "СуммаПродаж", SUM(Продажи[Сумма])
        ),
        [СуммаПродаж], DESC
    )
RETURN
    CALCULATE(
        SUM(Продажи[Сумма]),
        KEEPFILTERS(ТопТоваровТаблица),
        Продажи[Дата] >= НачалоПериода && Продажи[Дата] <= КонецПериода
    )

One tap - one kill
Как правильно делить время пополам, разные варианты деления дают разный результат
 
Цитата
написал:
Я не понимаю, почеру эксель в разных случаях округляет по разному.
Вполне вероятно, что это проблема при отображении результата в зависимости от применённого форматирования. И что самое забавное, он сохраняет точность внутренне, но может округлять по-разному, в итоге. Теперь я тоже обратил на это внимание.

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

Для точных расчётов времени без проблем с округлением используйте функцию TIME:
Код
=TIME(HOUR(A1/2),MINUTE(A1/2),SECOND(A1/2))
Если нужно конкретно контролировать округление, можно использовать функцию MROUND для значений времени:
Код
=MROUND(A1/2,"0:00:01")
Для точного контроля на уровне секунд можно преобразовать в секунды, выполнить операцию и преобразовать обратно:
Код
=TEXT(((HOUR(A1)*3600+MINUTE(A1)*60+SECOND(A1))/2)/86400,"h:mm:ss")

Думаю, должно сработать.
One tap - one kill
Сломалась обработка Power Query
 
- При расчетах в Power Query, если одно из значений в формуле является null, весь результат становится null, это логично
- И в вашем макросе есть несколько операций объединения таблиц (Table.NestedJoin) и расчетов, где могут возникать null-значения, из чего следует проблема, как я понял.
- Пустые строки (null) из БД корректно подтягиваются, но теряются при дальнейшей обработке?

Если так, то попробуйте в Power Query Editor заменить null-значения через вкладку Transform/Home ----> в поле "Value to find" введите null, а в "Replace with" введите подходящее значение (например, 0 для числовых полей).

Есть ещё варианты с введением оператора коалесценции + проверка, что включённые в код условные выражения правильно обрабатывают null, но замена значений через редактор по идее должна оказаться проще.
One tap - one kill
Автообновление Динамического источника данных (Яндекс API) Power BI
 
Цитата
написал:
как url изменить, чтобы не статус получить, а сформировать и скачать этот отчет.
Вместо /evaluate, который только проверяет возможность создания отчета, нужно:
  1. Сначала создать запрос на формирование отчета.

  2. Проверить статус готовности отчета.

  3. Скачать готовый отчет.

Модификация запроса:
Код
let
    // 1. Создание запроса на формирование отчета
    CreateRequest = 
        Json.Document(Web.Contents("https://api-metrika.yandex.net/management/v1/counter/{мой счётчик}/logrequests", 
        [
            Headers=
                [Authorization="OAuth {мой ключ}", 
                #"Content-Type"="application/x-yametrika+json"], 
            Content = Text.ToBinary(Json.FromValue(
                [
                    date1 = "2025-02-10", 
                    date2 = "2025-02-15", 
                    fields = {"ym:s:clientID", "ym:s:counterUserIDHash", "ym:s:eventsProductEventTime", "ym:s:eventsProductType"}, 
                    source = "visits"
                ])),
            ManualStatusHandling = {400, 401, 403, 404, 429, 500, 502, 503, 504}
        ])),
    
    // Получаем ID запроса
    RequestId = CreateRequest[log_request][request_id],
    
    // 2. Проверка статуса запроса (в цикле, пока не будет готов)
    CheckStatus = Function.InvokeAfter(
        () => Json.Document(Web.Contents("https://api-metrika.yandex.net/management/v1/counter/{мой счётчик}/logrequest/" & RequestId,
        [
            Headers=[Authorization="OAuth {мой ключ}"],
            ManualStatusHandling = {400, 401, 403, 404, 429, 500, 502, 503, 504}
        ])),
        #duration(0, 0, 0, 5)
    ),
    
    // 3. Скачивание отчета
    DownloadReport = 
        if CheckStatus[log_request][status] = "processed" then
            Csv.Document(Web.Contents("https://api-metrika.yandex.net/management/v1/counter/{мой счётчик}/logrequest/" & RequestId & "/part/0/download",
            [
                Headers=[Authorization="OAuth {мой ключ}"],
                ManualStatusHandling = {400, 401, 403, 404, 429, 500, 502, 503, 504}
            ]))
        else
            "Отчет еще не готов"
in
    DownloadReport

Так же присутствуют важные моменты:
- Используется POST-запрос к /logrequests (без /evaluate)
- Параметры запроса передаются в теле самого запроса через Content
- После создания получаем request_id для дальнейшего отслеживания
- Проверяем статус запроса, ожидая значение "processed"
- Когда отчет готов, скачиваем его, указывая номер части (part/0)

Вот. И для работы с большими отчётами придётся модифицировать код, чтобы он чекал каждую часть датабазы.
One tap - one kill
Связь столбцов одного листа/книги со столбцами другого листа/книги.
 
Можно попробовать в SQL через mapping-таблицу.
Код
CREATE TABLE mapping_table (
    source_column VARCHAR(255),
    target_column VARCHAR(255)
);

INSERT INTO mapping_table (source_column, target_column)
VALUES
    ('column1_source', 'column1_target'),
    ('column2_source', 'column2_target'),
    -- Добавьте все необходимые соответствия
    ('columnN_source', 'columnN_target');
Теперь мы можем использовать эту mapping-таблицу для копирования данных из source_table в target_table. Юзаем динамический SQL, чтобы построить запрос на основе mapping-таблицы.
Код
-- Получаем все соответствия из mapping таблицы
SELECT source_column, target_column
FROM mapping_table;

-- Пример динамического SQL (в реальности это будет цикл или процедура)
DECLARE @sql NVARCHAR(MAX) = '';

SELECT @sql += 'INSERT INTO target_table (' + target_column + ') SELECT ' + source_column + ' FROM source_table; '
FROM mapping_table;

-- Выполняем запрос
EXEC sp_executesql @sql;
Используя SQLite и Питон, автоматизируем процесс:
Код
import sqlite3

# Подключаемся к базе данных
conn = sqlite3.connect('your_database.db')
cursor = conn.cursor()

# Получаем все соответствия из mapping таблицы
cursor.execute("SELECT source_column, target_column FROM mapping_table")
mappings = cursor.fetchall()

# Генерируем и выполняем запросы
for source, target in mappings:
    query = f"INSERT INTO target_table ({target}) SELECT {source} FROM source_table"
    cursor.execute(query)

# Сохраняем изменения
conn.commit()

# Закрываем соединение
conn.close()

Не забываем про установку библиотек pandas для чтения данных и sqlite3 для работы с базой данных.
One tap - one kill
Связная таблица образец, Таблица образец при изменении которой менялось бы оформление в других таблицах.
 
Эх, муторно это, но в целом можно попробовать несколько вариантов:

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

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

3. Наиболее эффективный - макрос через VBA, чтобы он отслеживал изменения в бланке и применял их к копиям, но с ним нужно поработать. Используйте событие Worksheet_Change:
Код
Private Sub Worksheet_Change(ByVal Target As Range)
    ' Укажите диапазон, который вы хотите отслеживать
    Dim sourceRange As Range
    Set sourceRange = Me.Range("A1:E10") ' Измените на нужный диапазон
    
    ' Проверка, произошли ли изменения в указанном диапазоне
    If Not Application.Intersect(sourceRange, Target) Is Nothing Then
        ' Применение изменений к копиям
        ApplyChangesToCopies Target
    End If
End Sub

Sub ApplyChangesToCopies(Target As Range)
    ' Укажите пути к копиям или имена листов в текущей книге
    Dim copyPaths() As Variant
    copyPaths = Array("C:\Path\To\Copy1.xlsx", "C:\Path\To\Copy2.xlsx")
    
    ' Или если копии находятся в той же книге
    ' Dim copySheets() As Variant
    ' copySheets = Array("Sheet2", "Sheet3")
    
    ' Применение изменений к каждой копии
    Dim i As Integer
    For i = LBound(copyPaths) To UBound(copyPaths)
        ' Открытие книги копии (если она не открыта)
        Dim copyWorkbook As Workbook
        Set copyWorkbook = Workbooks.Open(copyPaths(i))
        
        ' Применение изменений
        ApplyChangeToCopy copyWorkbook, Target
        
        ' Сохранение и закрытие книги копии
        copyWorkbook.Save
        copyWorkbook.Close
    Next i
End Sub

Sub ApplyChangeToCopy(copyWorkbook As Workbook, Target As Range)
    ' Укажите лист в копии, где нужно применить изменения
    Dim copySheet As Worksheet
    Set copySheet = copyWorkbook.Sheets(1) ' Измените на нужный лист
    
    ' Применение изменений (например, обновление формул и форматирования)
    copySheet.Range(Target.Address).Value = Target.Value
    copySheet.Range(Target.Address).Font.Bold = Target.Font.Bold
    copySheet.Range(Target.Address).Interior.ColorIndex = Target.Interior.ColorIndex
End Sub
Код будет запускаться каждый раз, когда в исходной таблице меняются данные, и применять эти изменения к копиям.

Нужно будет настроить пути к копиям (copyPaths) или имена листов (copySheets), а также диапазон (sourceRange), который хотите отслеживать. Так же мой код может обрабатывать несколько копий, указанных в массиве copyPaths и чекать изменения в sourceRange.

И не забудьте, что он должен быть размещен в модуле листа исходной таблицы, чтобы событие Worksheet_Change срабатывало при изменении данных в этом листе.
Изменено: Bug Hunter - 13.03.2025 01:33:28
One tap - one kill
Регулярные выражения в PQ
 
Код
let fx = (txt as text, regex as text, delim as text) =>
    Web.Page(
        "<script>
            var x = '" & txt & "';
            var delim = '" & delim & "';
            var pattern = new RegExp('" & regex & "', 'gm');
            var results = Array.from(x.matchAll(pattern));
            
            // Сортировка по группам
            results.sort((a, b) => {
                if (a[1] === b[1]) return 0;
                if (a[1] < b[1]) return -1;
                return 1;
            });
            
            // Вывод отсортированных результатов
            var sortedResult = results.map(match => match[1]).join(delim);
            document.write(sortedResult);
        </script>")[Data]{0}[Children]{0}[Children]{1}[Text]{0}

В этом примере предполагается, что группа, по которой вы хотите сортировать, является первой группой (a[1]). Если у вас несколько групп или они имеют другие индексы, то скорректируйте код сортировки соответственно.

Можно ещё попробовать поиграться с именованными группами - так будет несколько легче:
Код
let fx = (txt as text, regex as text, delim as text) =>
    Web.Page(
        "<script>
            var x = '" & txt & "';
            var delim = '" & delim & "';
            // Используем именованную группу в регулярном выражении
            var pattern = new RegExp('(?<fruit>" & regex & ")', 'gm');
            
            var results = Array.from(x.matchAll(pattern));
            
            // Сортировка по именованной группе
            results.sort((a, b) => {
                if (a.groups.fruit === b.groups.fruit) return 0;
                if (a.groups.fruit < b.groups.fruit) return -1;
                return 1;
            });
            
            // Вывод отсортированных результатов
            var sortedResult = results.map(match => match.groups.fruit).join(delim);
            document.write(sortedResult);
        </script>")[Data]{0}[Children]{0}[Children]{1}[Text]{0}
One tap - one kill
Автообновление Динамического источника данных (Яндекс API) Power BI
 
Также, ещё вспомнил насчёт Power BI.

В Power Query можно использовать функцию Web.Contents() с параметрами RelativePath и Query, чтобы динамически изменять URL запроса. Тогда получится обновлять данные, если используется базовый URL и динамические части URL передаются через эти параметры.
Вот сниппет:
Код
let
    Source = Web.Contents("https://api.example.com/baseurl",
        [RelativePath = "/path/to/resource",
         Query = "param1=value1¶m2=value2"])
in
    Source

Можно использовать REST API Power BI для обновления наборов данных. Тогда выйдет обновлять данные асинхронно (полезно для сложных моделей и больших данных).
Команда для Powershell:
Код
# Установите модуль Power BI
Install-Module -Name MicrosoftPowerBIMgmt

# Войдите в Power BI
Login-PowerBI

# Обновите набор данных
Invoke-PowerBIRestMethod -Url "https://api.powerbi.com/v1.0/myorg/groups/{groupId}/datasets/{datasetId}/refreshes&quot; -Method Post
One tap - one kill
Фильтр по датам в PQ из данных в Excel, Фильтр по датам в PQ из данных в Excel
 
Из начала и конца отчёта извлеките даты:
Код
let
    // Извлечение даты начала отчёта
    Источник1 = Excel.CurrentWorkbook(){[Name="Дата_начала_отчета"]}[Content],
    #"Измененный тип1" = Table.TransformColumnTypes(Источник1,{{"Дата начала отчета", type date}}),
    Дата_начала_отчета = Record.Field(#"Измененный тип1"{0},"Дата начала отчета"),

    // Извлечение даты конца отчёта (если она есть)
    Источник2 = Excel.CurrentWorkbook(){[Name="Дата_конца_отчета"]}[Content],
    #"Измененный тип2" = Table.TransformColumnTypes(Источник2,{{"Дата конца отчета", type date}}),
    Дата_конца_отчета = Record.Field(#"Измененный тип2"{0},"Дата конца отчета"),

Затем примените фильтр:    
Код
Источник = Excel.CurrentWorkbook(){[Name="Погашение"]}[Content],
    #"Измененный тип" = Table.TransformColumnTypes(Источник,{{"Дата погашения", type date}}),
    #"Строки с примененным фильтром" = Table.SelectRows(#"Измененный тип", each 
        ([Наименование организации] = "ПАО") and 
        [Дата погашения] >= Дата_начала_отчета and 
        [Дата погашения] <= Дата_конца_отчета)
in
    #"Строки с примененным фильтром"

И объедините всё в одно:
Код
let
    // Извлечение даты начала отчёта
    Источник1 = Excel.CurrentWorkbook(){[Name="Дата_начала_отчета"]}[Content],
    #"Измененный тип1" = Table.TransformColumnTypes(Источник1,{{"Дата начала отчета", type date}}),
    Дата_начала_отчета = Record.Field(#"Измененный тип1"{0},"Дата начала отчета"),

    // Извлечение даты конца отчёта (если она есть)
    Источник2 = Excel.CurrentWorkbook(){[Name="Дата_конца_отчета"]}[Content],
    #"Измененный тип2" = Table.TransformColumnTypes(Источник2,{{"Дата конца отчета", type date}}),
    Дата_конца_отчета = Record.Field(#"Измененный тип2"{0},"Дата конца отчета"),

    Источник = Excel.CurrentWorkbook(){[Name="Погашение"]}[Content],
    #"Измененный тип" = Table.TransformColumnTypes(Источник,{{"Дата погашения", type date}}),
    #"Строки с примененным фильтром" = Table.SelectRows(#"Измененный тип", each 
        ([Наименование организации] = "ПАО") and 
        [Дата погашения] >= Дата_начала_отчета and 
        [Дата погашения] <= Дата_конца_отчета)
in
    #"Строки с примененным фильтром"

Если у вас нет даты конца отчёта, просто удалите соответствующие строки кода и измените условие фильтрации на [Дата погашения] >= Дата_начала_отчета
One tap - one kill
Автообновление Динамического источника данных (Яндекс API) Power BI
 
Попробуйте создать скрипт через Cron, который запрашивает данные из Яндекс API по расписанию.

Или вообще нечто похожее на Python с помощью requests и schedule оформите:
Код
import requests
import schedule
import time

def update_report():
    # Настройки API
    API_URL = 'https://api.example.com/data&#39;
    API_token = 'your_token'

    # Параметры запроса
    params = {
        'date1': '6daysAgo',
        'date2': 'today',
        # Другие параметры
    }

    # Заголовки для авторизации
    headers = {'Authorization': API_token}

    # Отправка запроса
    response = requests.get(API_URL, params=params, headers=headers)

    # Обработка ответа
    if response.status_code == 200:
        # Обновление данных в отчете
        print("Данные обновлены успешно")
    else:
        print("Ошибка обновления данных")

# Настройка расписания
schedule.every(1).day.at("08:00").do(update_report)  # Обновлять каждый день в 8:00

while True:
    schedule.run_pending()
    time.sleep(1)
One tap - one kill
Как составить график в Excel?, Создание графика в Excel
 
Код
Sub UpdateDeliveryAndPayment()
    Dim ws As Worksheet
    Set ws = ThisWorkbook.Sheets("Лист1")
        Dim lastRow As Long
    lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
    
    Dim i As Long
    For i = 2 To lastRow
        ' Наименование
        Dim name As String
        name = ws.Cells(i, 2).Value
        
        ' Сумма аванса
        Dim advanceAmount As Double
        advanceAmount = 0
        For j = 4 To 15
            If ws.Cells(i, j).Value <> "" Then
                advanceAmount = ws.Cells(i, j).Value
                Exit For
            End If
        Next j
        
        ' Срок поставки
        Dim deliveryTerm As Integer
        deliveryTerm = ws.Cells(i, 16).Value
        
        ' Рассчитываем месяц поставки
        Dim deliveryMonth As Integer
        For j = 4 To 15
            If ws.Cells(i, j).Value = advanceAmount Then
                deliveryMonth = j + deliveryTerm
                If deliveryMonth > 15 Then
                    deliveryMonth = deliveryMonth - 12
                End If
                Exit For
            End If
        Next j
        
        ' Обновление поставки
        ws.Cells(i, deliveryMonth + 3).Value = advanceAmount
        
        ' Рассчитываем месяц оплаты остатка
        Dim paymentMonth As Integer
        paymentMonth = deliveryMonth + 1
        If paymentMonth > 15 Then
            paymentMonth = paymentMonth - 12
        End If
        
        ' Обновление оплаты остатка
        ' Предположим, что оплата остатка равна авансу (на самом деле это должно быть разница между авансом и поставкой)
        ws.Cells(i, paymentMonth + 3 + 12).Value = advanceAmount
    Next i
End Sub
Пускайте макрос через VBA и адаптируйте под вашу таблицу, указав правильные столбцы и строки.

Также, маленький бонус:
  • Для каждого месяца (например, Январь, Февраль, ...) используйте формулу, которая проверяет, соответствует ли текущий месяц месяцу поставки. Например, для января:

    Код
    =IF(MONTH(DATE(YEAR(TODAY());MONTH(B2)+C2;DAY(B2)))=1;B2;"")

  • Для каждого месяца используйте формулу, которая проверяет, соответствует ли текущий месяц месяцу оплаты остатка. Так же, для января:

    Код
    =IF(MONTH(DATE(YEAR(TODAY());MONTH(DATE(YEAR(TODAY());MONTH(B2)+C2;DAY(B2)))+1;DAY(B2)))=1;B2;"")

One tap - one kill
Как правильно делить время пополам, разные варианты деления дают разный результат
 
Когда вы работаете с временем в Excel, оно интерпретируется как дробная часть дня. Например, время 01:24:31 соответствует дробной части дня, равной 0.05869212962962963. Когда вы делите время пополам, результатом является дробное число, которое можно интерпретировать как время или как числовое значение. Однако, когда преобразуете это дробное число обратно в формат времени, Excel округляет его до ближайшей секунды, что может привести к расхождениям.

Если точность важна, лучше работать с числовыми значениями времени. Это позволит избежать проблем с округлением при преобразовании в формат времени.
One tap - one kill
Форматы для чисел с символами из соседней ячейки, Помогите пожалуйста с макросом.
 
Код
Sub ApplyFormatBasedOnAdjacentCell()
    Dim ws As Worksheet
    Set ws = ThisWorkbook.Sheets("ВашЛист") ' Укажите имя вашего листа
    
    Dim lastRow As Long
    lastRow = ws.Cells(ws.Rows.Count, "B").End(xlUp).Row ' Предполагается, что данные в столбце B
    
    Dim i As Long
    For i = 1 To lastRow
        Dim formatString As String
        formatString = ws.Cells(i, "B").Value ' Символы для формата
        
        Select Case formatString
            Case "TTRT"
                ws.Cells(i, "C").NumberFormat = "0.00" ' Пример формата для TTRT
            Case "RRT"
                ws.Cells(i, "C").NumberFormat = "0" ' Пример формата для RRT
            Case "RRR"
                ws.Cells(i, "C").NumberFormat = "#,##0" ' Пример формата для RRR
            Case Else
                ' Действие по умолчанию, если формат не найден
                ws.Cells(i, "C").NumberFormat = "General"
        End Select
    Next i
End Sub
Пускаете через редактор VBA. Этот код проверяет символы в столбце B и применяет соответствующий числовой формат к ячейкам в столбце C. Больше условий можете добавить в Select Case
One tap - one kill
Уникальность значений с одного столбца по сравнению с другим, Уникальность значений с одного столбца по сравнению с другим
 
Используйте формулу с массивным расчетом для проверки уникальных отделов:
Код
=COUNT(UNIQUE(FILTER(Отдел, Департамент = "Имя_Департамента")))

Для проверки всех департаментов можно использовать формулу:
Вместо A2 укажите ячейку, содержащую название департамента. Затем эту формулу можно скопировать вниз по столбцу для всех департаментов.
Код
=COUNT(UNIQUE(FILTER(Отдел, Департамент = A2)))
One tap - one kill
Страницы: 1
Наверх