#performance #concatenation #qlikview
#Производительность #объединение #qlikview
Вопрос:
я использую qlikview уже несколько лет, и простая проблема, с которой я сталкиваюсь почти ежедневно, заключается в необходимости объединения таблиц с разными полями, когда мне нужны только некоторые из них.
Например, допустим, у меня есть следующие таблицы на отдельных QVDS
таблица1:
таблица2:
мне нужно создать итоговую таблицу ТОЛЬКО с field_1, field_2 и field_3, но если я сделаю
я получаю сообщение об ошибке, что field_2 не существует в table2. я могу указать null() как field_2, когда я имею дело с небольшим количеством таблиц, где я знаю, что поле не существует, но когда я перебираю более 500 QVDS, где у некоторых есть поле, а у некоторых нет, мне нужен способ определить это.
прямо сейчас у меня есть два способа решения этой проблемы:
- сначала я загружаю qvd с помощью * и использую FIELDNUMBER, чтобы проверить, существует ли поле, и помещаю поле в переменную для использования во время загрузки.
пример:
- я создаю пустую стартовую таблицу с полями, для которых установлено значение null, и объединяю ее с помощью load *, чтобы сгенерировать отсутствующие поля (используя преимущество «генерировать отсутствующие поля с null»)
пример:
это довольно плохо с точки зрения производительности, поскольку я загружаю весь файл в память, когда меня интересуют только несколько столбцов, а затем их нужно удалить позже.
есть ли способ выполнить объединение, которое принимает только столбцы, уже присутствующие в первой таблице, завершает отсутствующие столбцы нулем, но автоматически исключает все остальные необязательные поля?
я пытался использовать предыдущую загрузку перед загрузкой с помощью *, но это не удается, когда одного из полей нет в qvd. есть идеи?
PS: я знаю, что описанные мной способы решают проблему, но я ищу лучшее решение с точки зрения производительности и скорости.
Ответ №1:
При объединении двух таблиц в Qlik нет необходимости в совпадении полей. Вы даже можете объединить две таблицы с совершенно разными полями, и Qlik не будет жаловаться. Qlik просто добавит null
для полей, которые отсутствуют.
Смотрим на приведенный ниже скрипт — у нас есть две таблицы Table1
и Table2
.
Table1
поля:field1
,field2
,field3
Table2
поля:field3
,field4
,field5
При загрузке всех полей из Table1
и объединении только field3
из Table2
результат будет:
field1
и field2
заполняются null
для строк, которые получены из Table2
Table1:
Load * Inline [
field1, field2, field3
1 , 2 , 3
4 , 5 , 6
];
Table2:
Load * Inline [
field3, field4, field5
1 , 2 , 3
4 , 5 , 6
];
NoConcatenate
ConcatenatedTable:
Load
field1,
field2,
field3
Resident
Table1
;
Concatenate
Load
field3
Resident
Table2
;
Drop Tables Table1, Table2;
Комментарии:
1. спасибо ответчику, возможно, я неправильно выразился: я знаю, что принудительное объединение генерирует недостающие поля в null (я использую его во втором примере). моя проблема в том, что когда у меня есть 500 qvd с f1, f2, f3, f4 и т.д., И я хочу объединить ТОЛЬКО [f1 f2 f3], но в некоторых таблицах нет f2, и я не могу заранее знать, какие из них есть, я в конечном итоге либо предварительно загружаю каждый qvd, чтобы проверить, существует ли поле, либо принудительно объединяю весь файл в пустую таблицу. оба решения мне не нравятся, потому что я в конечном итоге загружаю в память намного больше данных, чем мне действительно нужно, и теряю производительность.
Ответ №2:
Это другой подход, у меня недостаточно большого набора данных, чтобы проверить его производительность, но, по крайней мере, решает проблему наличия явных имен полей в скрипте, что может быть кошмаром для поддержания.
Начните с загрузки всех файлов с использованием перекрестной таблицы, чтобы деконструировать структуру :
for each file in FileList('<folder><files>*')
RawTable:
CrossTable(Field, Data, 2)
LOAD FileName() as FileName,
RowNo() as RowId,
*
FROM
[$(file)]
(txt, utf8, no labels, embedded labels, delimiter is ',');
next file;
Это создаст таблицу, содержащую 4 поля: исходное имя файла (FileName), номер строки внутри этого файла (RowId), имя столбца (Field) и его значение (Data).
Затем создайте свою конечную таблицу, чтобы она содержала ссылки на каждый файл и каждую известную строку :
DataTable:
LOAD
DISTINCT FileName,
RowId
Resident RawTable;
Затем создайте таблицу поддержки с отличным именем каждого известного поля в ваших файлах :
FieldTable:
LOAD
Distinct Field as KnownField
Resident RawTable;
Наконец, начинается волшебство, когда вы поле за полем слева присоединяете их к DataTable :
LET NumFields = NoOfRows('FieldTable');
FOR i = 0 to $(NumFields) - 1
LET vField = Peek('KnownField', $(i), 'FieldTable');
TRACE $(vField);
Left Join(DataTable)
LOAD
FileName,
RowId,
Data as $(vField)
Resident RawTable
WHERE Field = '$(vField)';
NEXT;
Наконец, просто некоторая очистка :
DROP TABLE RawTable;
DROP TABLE FieldTable;
Если вы хотите сохранить только подмножество полей, вы можете отфильтровать их при создании таблицы полей.
Комментарии:
1. спасибо за ответ, я использую аналогичную логику, когда не знаю имен полей загружаемых наборов данных и хочу сопоставить их со списком возможных имен полей; но поскольку FOR-lines в qlikview невероятно малопроизводительны, я предпочитаю избегать их, когда могу. приведенные мной примеры уже работают, я просто пытаюсь понять, есть ли более эффективный способ сделать это
Ответ №3:
Для более эффективного решения вы можете сначала извлечь метаданные каждого qvd, чтобы получить содержащие их поля, а затем настроить логику итерации qvd на основе этого.
Вот основной скрипт, который выдает вам имена полей файла qvd:
LOAD
"FieldName"
FROM [some.qvd]
(XmlSimple, table is [QvdTableHeader/Fields/QvdFieldHeader]);
Комментарии:
1. я думал об этом, но это то же самое, что загрузить файл и использовать fieldnumber для проверки, что означает, что я в конечном итоге дважды читаю один и тот же файл с диска. я знаю, что пытаюсь повысить производительность на 0,5%, используя странный / оккультный код, но я должен был спросить