Как преобразовать набор данных в массив

#powershell

#powershell

Вопрос:

После извлечения данных из SQL в powershell у меня есть набор данных. Как мне преобразовать это в массив?

$data.tables | gm дает мне TypeName: System.Data.DataSet

Если я запрашиваю информацию из таблицы, которую я извлек, я получаю:

 $data.Tables | fl

ServerName              : Server10
SamAccount              : Admin-Server10
  

но $data доступен только для чтения. Я не планирую выполнять обратную запись в базу данных, но хочу иметь возможность работать с данными и изменять их, находясь в памяти.

Мне нужен строковый массив, содержащий эти значения.

Конечно, я мог бы сделать:

$x = "" | select servername,SamAccount
$x.Servername = $data.tables.servername

но должен быть более простой способ. Извлеченный мной набор данных содержит более 100 столбцов.

Есть ли способ преобразовать это просто в массив строк (или как бы он ни назывался).. Строка, в которой я могу получить доступ к элементам данных внутри нее?

Я хочу иметь возможность использовать:

write-host "$($x.servername)"

и получить Server10

Кстати, в наборе данных всего 1 строка данных.. Просто много столбцов.

Комментарии:

1. Похоже, что для начала это не массив из-за одной строки. Потому что это не так. Если вы помещаете свой набор данных в ‘объект’ Powershell (переменную) и выполняете $data[0], что он возвращает?

Ответ №1:

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

 DataSet -> DataTableCollection -> DataTable -> DataRowCollection -> DataRow
  

Что такое:

 $DataTableCollection = $DataSet.Tables   #Get the Tables
$DataTable = $DataTableCollection[0]     #Only need the first Table
$DataRowCollection = $DataTable.Rows     #Get the Rows
$DataRow = $DataRowCollection[0]         #Only need the first Row
  

Или, для упрощенного однострочного:

 $Row = $DataSet.Tables[0].Rows[0]
  

Затем это позволяет вам получить доступ к свойствам, как вы ожидаете.

 $Row.ServerName = "asdf"
  

Комментарии:

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

2. Это объясняет, как получить доступ к повторным данным, но все равно не позволяет мне манипулировать ими. Если я устал $DataSet.Tables[0].Rows[0].servername = "Test" , он все равно терпит неудачу.

3. Нет. Не используйте $DataSet.Tables[0].Rows[0].servername , потому что да, набор данных доступен только для чтения. Присвойте строку $Row переменной и используйте DataRow, поскольку она не доступна только для чтения.

Ответ №2:

Вы можете создать объект для каждой строки, а затем заполнить их значения на основе столбцов таблицы. Это даст вам PSCustomObject для каждой строки со свойствами, на которые вы можете ссылаться и изменять.

     $MyArray = ForEach($Row in $Data.Tables[0].Rows){
    $Record = New-Object PSObject
    ForEach($Col in $Data.Tables[0].Columns.ColumnName){
        Add-Member -InputObject $Record -NotePropertyName $Col -NotePropertyValue $Row.$Col
    }
    $Record
}
  

Когда это будет сделано $MyArray , появится массив пользовательских объектов, с которыми вы можете работать сколько угодно.

Комментарии:

1. Возможно, я упускаю что-то простое. Используя ваш код точно так, как написано, когда я набираю $myArray, я вижу подтипы. Но если я попытаюсь сделать $MyArray.servername = "dd" это, он не сможет сказать, что свойство не может быть найдено для объекта.

2. Это потому $MyArray , что это массив объектов. Вы можете удалить [array] из первой строки или ссылаться на объект в массиве по индексу $MyArray[0].servername = "dd"

3. Проверил это, без ссылки [array], это именно то, что я пытался сделать. Спасибо.. У вас 26 КБ (на данный момент), поэтому баллы могут мало что значить, но они ваши. Даже значения внутри нового объекта сохраняют там типы. (строка против логического значения). Отлично, спасибо..

Ответ №3:

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

Сначала получите все имена свойств

 [string[]]$Properties = @()
Foreach($col in $DataSet.Tables[0].Columns) {
    $Properties  = $col;
}
  

Затем добавьте все строки как PSCustomObject (с именами столбцов из набора данных) в arraylist:

 $arrayList = New-Object System.Collections.ArrayList
Foreach($row in $DataSet.Tables[0]) {
    $arrayList.Add(($row | Select-Object $Properties)) > $null;
}