Подключение OLEDB к Excel; как я выбираю зафиксированную ширину, неограниченную высоту?

Вот мое решение:

/**
 * Tests two data structures for equality
 * @param {object} x
 * @param {object} y
 * @returns {boolean}
 */
var equal = function(x, y) {
    if (typeof x !== typeof y) return false;
    if (x instanceof Array && y instanceof Array && x.length !== y.length) return false;
    if (typeof x === 'object') {
        for (var p in x) if (x.hasOwnProperty(p)) {
            if (typeof x[p] === 'function' && typeof y[p] === 'function') continue;
            if (x[p] instanceof Array && y[p] instanceof Array && x[p].length !== y[p].length) return false;
            if (typeof x[p] !== typeof y[p]) return false;
            if (typeof x[p] === 'object' && typeof y[p] === 'object') { if (!equal(x[p], y[p])) return false; } else
            if (x[p] !== y[p]) return false;
        }
    } else return x === y;
    return true;
};

Работает с любой вложенной структурой данных и, очевидно, игнорирует методы объектов. Даже не думайте о расширении Object.prototype этим методом, когда я однажды попробовал это сделать, jQuery сломался;)

Для большинства массивов это все же быстрее, чем у большинства решений для сериализации. Вероятно, это самый быстрый метод сравнения массивов записей объектов.

5
задан Steve Cooper 21 July 2009 в 15:40
поделиться

5 ответов

Предварительное условие: вы можете легко определить в своем коде максимальное количество строк.

Предполагая (1), что на каждый SELECT накладываются большие накладные расходы, поэтому ВЫБОР строки в время медленно (2) ВЫБОР строк размером 64К или 8М (даже если они пустые) выполняется медленно ... поэтому вы хотите увидеть, может ли что-то посередине быть быстрее. Попробуйте следующее:

Выбирайте CHUNKSIZE (например, 100 или 1000) строк за раз (меньше, если в противном случае вы бы перегрузили MAX_ROWS). Просканируйте каждый фрагмент на наличие пустой строки, которая отмечает конец данных.

ОБНОВЛЕНИЕ: Фактически отвечая на явные вопросы:

Q: Кто-нибудь знает способ написать запрос, который говорит либо;

Q1: «выбрать все внизу и справа от B14»?

A1: выбрать * из [Sheet1 $ B12:] не работает. Вам нужно будет сделать ... B12: IV в Excel 2003 и что бы там ни было в Excel 2007. Однако вам это не нужно, потому что вы знаете, какой у вас крайний правый столбец; см. ниже.

Q2: 'выберите все в столбцах B-> D'

A2: выберите * из [Sheet1 $ B: D]

Q3: «выберите B12: D * », где * означает «все, что вы можете»

A3: выберите * из [ Sheet1 $ B12: D]

Протестировано с Python 2.5 с использованием следующего кода:

import win32com.client
import sys
filename, sheetname, range = sys.argv[1:4]
DSN= """
    PROVIDER=Microsoft.Jet.OLEDB.4.0;
    DATA SOURCE=%s;
    Extended Properties='Excel 8.0;READONLY=true;IMEX=1';
    """ % filename
conn = win32com.client.Dispatch("ADODB.Connection")
conn.Open(DSN)
rs = win32com.client.Dispatch("ADODB.Recordset")
sql = (
    "SELECT * FROM [Excel 8.0;HDR=NO;IMEX=1;Database=%s;].[%s$%s]"
    % (filename, sheetname, range)
    )
rs.Open(sql, conn)
nrows = 0
while not rs.EOF:
    nrows += 1
    nf = rs.Fields.Count
    values = [rs.Fields.Item(i).Value for i in xrange(nf)]
    print nrows, values
    if not any(value is not None for value in values):
        print "sentinel found"
        break
    rs.MoveNext()
rs.Close()
conn.Close()
9
ответ дан 13 December 2019 в 22:13
поделиться

Couple possible solutions:

  1. Put your tables on separate worksheets, then simply query the whole worksheet.
  2. Give each table in Excel a name (in Excel 2007, select the table, right-click, and choose Name a range...), then in your query, use this name instead of "Sheet1$B14:D65535".

Hope that helps.

EDIT

Here's a third idea:

I'm not sure what you're using to query your database, but if your query engine supports variables (like Sql Server, for example) you could store the result of...

SELECT COUNT(*) FROM NameOfServer...Sheet1$

...in a variable called @UsedRowCount, that will give you the number of rows actually used in the worksheet. So, @UsedRowCount = LastRowUsed - InitialBlankRows.

You might then be able to use string concatenation to replace "65535" with @UsedRowCount + @InitialBlankRows. You would have to set @InitialBlankRows to a constant (in your example, it would be 3, since the heading row of the first table is located at Row 4).

1
ответ дан 13 December 2019 в 22:13
поделиться

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

0
ответ дан 13 December 2019 в 22:13
поделиться

Я бы выбрал решение от Джона (чтение 1000 строк за раз).

Если у вас установлен Excel, вы также можете использовать автоматизацию OLE.

Я записал простой макрос в Excel, который выбирает последнюю ячейку в текущей таблице.


Sub Macro2()
    Range("B14").Select
    Selection.End(xlDown).Select
    //MsgBox ActiveCell.Address, vbOKOnly
End Sub

Теперь вам просто нужно перевести это на C # и прочитать адрес активной ячейки.

0
ответ дан 13 December 2019 в 22:13
поделиться

Мы читаем всю электронную таблицу (например: SELECT * FROM [Sheet1 $]) и обрабатываем все остальное в коде нашего приложения. Достаточно легко пройти через полученный OleDbDataReader, чтобы добраться до начальной точки ваших данных и начать обработку.

Возможно, это не самый быстрый способ получить данные из Excel, но он надежен.

0
ответ дан 13 December 2019 в 22:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: