#excel #powerquery #m
#excel #powerquery #m
Вопрос:
Мне нужна помощь в организации того, что нужно сделать. У меня есть список биржевых символов, и мне нужно загрузить данные для каждого из них, которые будут отображаться в таблице запросов. Вот как это будет выглядеть, даже если это сокращенная версия :
Я создал URL-адрес для веб-запроса, но поскольку мой тикер меняется для каждого запроса, я не знаю, как заставить запрос просматривать ячейку тикера (C2, G2 и т. Д.) Я могу это сделать, если назову эти ячейки, но должен ли я называть каждую из них? Есть ли способ просмотреть значение ячейки на основе ссылки на ячейку? В приведенном ниже примере это должно быть в Source = Json.Документ (Web.Contents(meurl1 )), где я бы рекламировал meurl1 amp; C2 или что-то в этом роде. Есть идея?
let
meurl1 = Excel.CurrentWorkbook(){[Name="meurl1"]}[Content]{0}[Column1],
Source = Json.Document(Web.Contents(meurl1 )),
#"Converted to Table" = Table.FromList(Source, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"date", "close", "high", "low", "open"}, {"Column1.date", "Column1.close", "Column1.high", "Column1.low", "Column1.open"}),
#"Changed Type" = Table.TransformColumnTypes(#"Expanded Column1",{{"Column1.date", type datetime}}),
#"Renamed Columns" = Table.RenameColumns(#"Changed Type",{{"Column1.date", "Date"}, {"Column1.close", "Close"}, {"Column1.high", "High"}, {"Column1.low", "Low"}, {"Column1.open", "Open"}}),
#"Reordered Columns" = Table.ReorderColumns(#"Renamed Columns",{"Date", "Open", "High", "Low", "Close"}),
#"Sorted Rows" = Table.Sort(#"Reordered Columns",{{"Date", Order.Descending}})
в
Комментарии:
1. Насколько я знаю, при использовании
Excel.CurrentWorkbook
вы можете ссылаться только на именованные диапазоны (включая таблицы). Это означает, что вы не можете использоватьC2
(илиG2
и т.д.) В своем коде запроса, поскольку Power Query не может интерпретировать произвольные ссылки на ячейки / адреса.2. Некоторые варианты: #1 Превратите тикеры в столбце A в именованный диапазон, затем попросите Power Query захватить весь именованный диапазон сразу и перебирать его значения, чтобы получить данные каждого тикера. Однако это будет загружаться как одна таблица, содержащая данные всех тикеров (в отличие от отдельной таблицы для каждого тикера). #2 В качестве альтернативы, включите
C2
(иG2
и т.д.) в именованные диапазоны, а затем создайте запрос для каждого тикера. Это потребует времени / усилий, чтобы сделать вручную (особенно, если вам нужно добавить / удалить тикеры позже), поэтому, возможно, используйте VBA для автоматизации создания / удаления / обновления запроса.3. Спасибо! Я думаю, вы точно понимаете, с чем я сталкиваюсь. Вариант № 1, у меня нет знаний для этого. Будет ли это через VBA. Как вы его зацикливаете? И вариант № 2 — это именно то, чего я пытаюсь избежать. У меня более 100 тикеров. По крайней мере, теперь я знаю, какие есть варианты. Не могли бы вы привести очень простой пример того, что вы предлагаете в вариантах 1?
4. Да, мы предоставили простой пример варианта № 1. В таблице должны быть нужные вам данные, просто не в той структуре / формате, которые задал ваш вопрос.
Ответ №1:
В приведенном ниже примере данные для всех тикеров будут загружены в одну таблицу, а не в отдельную таблицу для каждого тикера.
-
Создайте именованный диапазон, вызываемый
tickers
в вашем файле Excel, который содержит все тикеры (для которых вам нужно получить данные) в одном столбце. -
Скопируйте и вставьте приведенный ниже код в расширенный редактор в Power Query — и затем посмотрите, дает ли он ожидаемый результат.
Я включил три примера ( verticalTable
, horizontalTable
и anotherHorizontalTable
). Посмотрите, какой из трех вариантов лучше всего подходит для вас и ваших данных.
Я не уверен, какое значение meurl1
находится в вашем файле, поэтому я просто скопировал его из вашего вопроса.
let
tickers = Excel.CurrentWorkbook(){[Name="tickers"]}[Content][Column1],
url = Excel.CurrentWorkbook(){[Name="meurl1"]}[Content]{0}[Column1],
getTickerData = (someTicker as text) as table =>
let
response = Web.Contents(url amp; someTicker),
parsed = Json.Document(response),
toTable = Table.FromRecords(parsed, type table [
date = datetime, open = number, high = number, low = number, close = number
])
in toTable,
// This approach should stack your ticker data vertically.
// It's not what you asked for, but it might be a bit quicker than the approaches below.
verticalTable =
let
looped = List.Transform(tickers, each [ticker = _, data = getTickerData(ticker)]),
toTable = Table.FromRecords(looped, type table [ticker = text, data = record]),
expanded = Table.ExpandTableColumn(toTable, "data", {"date", "open", "high", "low", "close"}, {"Date", "Open", "High", "Low", "Close"})
in expanded,
// This approach will stack your ticker data horizontally, but with all tickers sharing a single
// Date column.
horizontalTable =
let
allData = List.Transform(tickers, each [ticker = _, data = getTickerData(ticker)]),
uniqueDates = List.Distinct(List.Combine(List.Transform(allData, each [data][date]))),
looped = List.Accumulate(
allData,
Table.FromColumns({uniqueDates}, type table [Date = datetime]),
(tableState as table, tickerData as record) as table =>
let
columnsToExpand = List.RemoveItems(Table.ColumnNames(tickerData[data]), {"date"}),
joined = Table.NestedJoin(tableState, "Date", tickerData[data], "date", "_toExpand"),
expanded = Table.ExpandTableColumn(joined, "_toExpand", columnsToExpand, List.Transform(columnsToExpand, each tickerData[ticker] amp; " (" amp; Text.Proper(_) amp; ")"))
in expanded
)
in looped,
// This approach will stack your ticker data horizontally, but the difference here is each ticker
// will have its own Date column.
anotherHorizontalTable =
let
looped = List.Accumulate(
tickers,
{},
(tableColumns as list, ticker as text) as list =>
let
tickerTable = getTickerData(ticker),
renamed = Table.TransformColumnNames(tickerTable, each ticker amp; " (" amp; Text.Proper(_) amp; ")"),
columnNames = Table.ColumnNames(renamed),
columns = Table.ToColumns(renamed),
columnsWithMeta = List.Transform(List.Positions(columns), each columns{_} meta [columnName = columnNames{_}]),
combined = tableColumns amp; columnsWithMeta
in combined
),
toTable = Table.FromColumns(looped, List.Transform(looped, each Value.Metadata(_)[columnName]))
in toTable
in
anotherHorizontalTable
Комментарии:
1. Спасибо, Чилин! Мне придется попробовать это и вернуться, если я добьюсь успеха