Попробуйте его
WITH Numbers AS
(SELECT TOP(@X.value('count(//ID)','int')) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS Nmbr FROM master..spt_values)
SELECT Nmbr
,@X.value('(//ID[sql:column("Nmbr")])[1]','int') AS ID
,@X.value('(//AppCode[sql:column("Nmbr")])[1]','nvarchar(max)') AS AppCode
,@X.value('(//SomeMore[sql:column("Nmbr")])[1]','nvarchar(max)') AS SomeMore
FROM Numbers;
Идея
Это должно работать со многими столбцами довольно быстро:
DECLARE @X XML = '<ROOT>
<RECORD>
<ID>1</ID>
<AppCode>Code 1</AppCode>
<ID>2</ID>
<AppCode>Code 2</AppCode>
<ID>3</ID>
<AppCode>Code 3</AppCode>
<ID>4</ID>
<AppCode>Code 4</AppCode>
<ID>5</ID>
<AppCode>Code 5</AppCode>
</RECORD>
</ROOT>';
WITH allIDs AS
(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS Pos
,id.value('text()[1]','int') AS ID
FROM @X.nodes('/ROOT/RECORD/ID') A(id)
)
SELECT ai.Pos
,ai.ID
,@X.value('/ROOT[1]/RECORD[1]/AppCode[sql:column("ai.Pos")][1]','nvarchar(max)') AS AppCode
,@X.value('/ROOT[1]/RECORD[1]/SomeMore[sql:column("ai.Pos")][1]','nvarchar(max)') AS SomeMore
FROM allIDs ai
ORDER BY ai.Pos;
Идея:
[ 1130]sql:column()
Это должно быть быстрее:
WITH AllNodes AS
(
SELECT (ROW_NUMBER() OVER(ORDER BY (SELECT NULL))-1) / 3 AS RowGroup
,nd.value('local-name(.)','nvarchar(max)') AS NodeName
,nd.value('text()[1]','nvarchar(max)') AS NodeValue
FROM @X.nodes('/ROOT/RECORD/*') A(nd)
)
SELECT RowGroup
,MAX(CASE WHEN NodeName='ID' THEN NodeValue END) AS ID
,MAX(CASE WHEN NodeName='AppCode' THEN NodeValue END) AS AppCode
,MAX(CASE WHEN NodeName='SomeMore' THEN NodeValue END) AS SomeMore
FROm AllNodes
GROUP BY RowGroup
Идея
(ROW_NUMBER-1)/3
(целочисленное деление!) Вернет групповой индекс, который мы можем использовать в GROUP BY
. Остальное - старомодный PIVOT . Предупреждения для обоих подходов :
ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
сработало для меня во всех случаях, когда я его использовал. Но стоит отметить, что это не гарантирует возвращение правильной позиции. Вы можете выделить несколько дополнительных байтов в свою оболочку и поместить либо идентификатор (если вы хотите связать malloc () и free ()) или просто размер. Просто malloc (), что намного больше памяти, сохраните информацию в начале вашего блока памяти и переместите указатель, который вы возвращаете, на это много байтов вперед.
Это, кстати, также легко можно использовать для указателей / отпечатков пальцев и тому подобное.
Либо вы можете получить доступ к внутренним таблицам, используемым ] malloc
/ free
(см. этот вопрос: Где malloc () / free () хранить выделенные размеры и адреса? для некоторых подсказок), или вам нужно управлять своими собственные таблицы в ваших оболочках.
Вы всегда можете использовать valgrind вместо катания собственной реализации. Если вам не важен объем выделяемой памяти, вы можете использовать еще более простую реализацию: (Я сделал это очень быстро, поэтому могли возникнуть ошибки, и я понимаю, что это не самая эффективная реализация. PAllocedStorage следует дать начальный размер и увеличение на некоторый коэффициент для изменения размера и т. д., но вы поняли идею.)
РЕДАКТИРОВАТЬ: Я пропустил, что это было для ARM, насколько мне известно, valgrind недоступен для ARM, так что это может быть вариант.
static size_t indexAllocedStorage = 0;
static size_t *pAllocedStorage = NULL;
static unsigned int free_calls = 0;
static unsigned long long int total_mem_alloced = 0;
void *
my_malloc(size_t size){
size_t *temp;
void *p = malloc(size);
if(p == NULL){
fprintf(stderr,"my_malloc malloc failed, %s", strerror(errno));
exit(EXIT_FAILURE);
}
total_mem_alloced += size;
temp = (size_t *)realloc(pAllocedStorage, (indexAllocedStorage+1) * sizeof(size_t));
if(temp == NULL){
fprintf(stderr,"my_malloc realloc failed, %s", strerror(errno));
exit(EXIT_FAILURE);
}
pAllocedStorage = temp;
pAllocedStorage[indexAllocedStorage++] = (size_t)p;
return p;
}
void
my_free(void *p){
size_t i;
int found = 0;
for(i = 0; i < indexAllocedStorage; i++){
if(pAllocedStorage[i] == (size_t)p){
pAllocedStorage[i] = (size_t)NULL;
found = 1;
break;
}
}
if(!found){
printf("Free Called on unknown\n");
}
free_calls++;
free(p);
}
void
free_check(void) {
size_t i;
printf("checking freed memeory\n");
for(i = 0; i < indexAllocedStorage; i++){
if(pAllocedStorage[i] != (size_t)NULL){
printf( "Memory leak %X\n", (unsigned int)pAllocedStorage[i]);
free((void *)pAllocedStorage[i]);
}
}
free(pAllocedStorage);
pAllocedStorage = NULL;
}
Я бы использовал rmalloc . Это простая библиотека (на самом деле это всего два файла) для отладки использования памяти, но она также поддерживает статистику. Поскольку вы уже используете функции оболочки, для нее должно быть очень легко использовать rmalloc. Имейте в виду, что вам также необходимо заменить strdup и т. Д.
Вашей программе может также потребоваться перехватить realloc (), calloc (), getcwd () (поскольку в некоторых реализациях она может выделять память, когда буфер равен NULL) и, возможно, strdup () или аналогичный функция, если она поддерживается вашим компилятором
Если вы работаете на x86
, вы можете просто запустить свой двоичный файл под valgrind , и он будет собирать всю эту информацию для вас, используя стандартная реализация malloc
и free
. Простой.