Вот мое решение:
/**
* 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 сломался;)
Для большинства массивов это все же быстрее, чем у большинства решений для сериализации. Вероятно, это самый быстрый метод сравнения массивов записей объектов.
Предварительное условие: вы можете легко определить в своем коде максимальное количество строк.
Предполагая (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()
Couple possible solutions:
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).
Вы говорите, что на предыдущем шаге пользователи выбрали заголовки. Кто сказал, что ниже интересующей нас области нет нескольких пустых строк, за которыми следует другая несвязанная таблица? Я предлагаю вам заставить их выбрать весь диапазон, который их интересует - это должно решить обе проблемы.
Я бы выбрал решение от Джона (чтение 1000 строк за раз).
Если у вас установлен Excel, вы также можете использовать автоматизацию OLE.
Я записал простой макрос в Excel, который выбирает последнюю ячейку в текущей таблице.
Sub Macro2()
Range("B14").Select
Selection.End(xlDown).Select
//MsgBox ActiveCell.Address, vbOKOnly
End Sub
Теперь вам просто нужно перевести это на C # и прочитать адрес активной ячейки.
Мы читаем всю электронную таблицу (например: SELECT * FROM [Sheet1 $]) и обрабатываем все остальное в коде нашего приложения. Достаточно легко пройти через полученный OleDbDataReader, чтобы добраться до начальной точки ваших данных и начать обработку.
Возможно, это не самый быстрый способ получить данные из Excel, но он надежен.