Хотя вопрос предполагает опрос мнений, который противоречит политике вопроса stackexchange
, я постараюсь привести некоторые причины, которые, конечно, предвзяты.
И, наконец, ответ на последний вопрос, который вы выделили жирным шрифтом.
Не рекомендуется. Каждая вещь обслуживает чьи-то потребности с определенным качеством за определенные деньги. Баланс качества и стоимости имеет значение.
Использование csvkit
,
$ csvsql -H --query 'SELECT a,min(b),max(c),d FROM file GROUP BY a' file.csv
a,min(b),max(c),d
164318,1449,1457,1922
841422,1221,1228,1860
842179,2115,2118,1485
846354,1512,1513,1590
Это загрузит данные CSV во временную базу данных (SQLite по умолчанию, я полагаю ), а затем применит к ней заданный SQL-запрос. По умолчанию таблица будет иметь то же имя, что и входной файл (без суффикса ), и, поскольку в данных отсутствуют заголовки столбцов, имена полей по умолчанию будут в алфавитном порядке.
Опции -H
сообщают csvsql
, что данные не имеют заголовков столбцов.
Чтобы удалить сгенерированный заголовок в выводе, передайте результат через что-то вроде sed '1d'
.
Для получения нуля -заполненных целых чисел:
$ csvsql -H --query 'SELECT printf("%07d,%06d,%06d,%06d",a,min(b),max(c),d) FROM file GROUP BY a' file.csv
"printf(""%07d,%06d,%06d,%06d"",a,min(b),max(c),d)"
"0164318,001449,001457,001922"
"0841422,001221,001228,001860"
"0842179,002115,002118,001485"
"0846354,001512,001513,001590"
Здесь строки заключены в кавычки, так как на самом деле мы запрашиваем только одно поле вывода для каждой записи результата (и оно содержит запятые ). Другой способ сделать это, который включает в себя немного больше ввода, но не создает дополнительных двойных кавычек:
$ csvsql -H --query 'SELECT printf("%07d",a),printf("%06d",min(b)),printf("%06d",max(c)),printf("%06d",d) FROM file GROUP BY a' file.csv
"printf(""%07d"",a)","printf(""%06d"",min(b))","printf(""%06d"",max(c))","printf(""%06d"",d)"
0164318,001449,001457,001922
0841422,001221,001228,001860
0842179,002115,002118,001485
0846354,001512,001513,001590
Опять же, выходной заголовок можно удалить, передав результат через sed '1d'
.
С Миллером (http://johnkerl.org/miller/doc), используя
mlr --ocsv --quote-all --inidx --ifs, cat inputFile | \
mlr --ocsv --quote-none --icsvlite stats1 -g '"1"' -a min,max,min -f '"2","3","4"' \
then cut -f '"1","2"_min,"3"_max,"4"_min' \
then label id,col2,col3,col4 | sed 's/"//g'
у вас есть
id,col2,col3,col4
0164318,001449,001457,001922
0842179,002115,002118,001485
0846354,001512,001513,001590
0841422,001221,001228,001860
Вы можете разбить свой SQL на базовые процедурные операции и воспроизвести их в сценарии оболочки.
Это, конечно, не очень хорошая идея, поскольку одно из преимуществ декларативных языков (, таких как SQL ), заключается в том, что они скрывают от разработчиков многословие и сложность процедурной реализации, позволяя им сконцентрироваться на данных. (Оптимизация — второе большое преимущество декларативных языков, которое теряется, если вы копируете их с помощью процедурной программы ).
Кроме того, этот подход проблематичен, потому что обработка текста в циклах оболочки обычно считается плохой практикой .
Тем не менее, вот пример сценария оболочки, который использует стандартные утилиты, которые вы найдете предварительно -установленными на многих системах (, за исключением конструкции массива — не указанной в POSIX, но широко доступной,и, безусловно, доступен для вас, поскольку вы спрашиваете оbash
):
#!/bin/bash
# The input file will be passed as the first argument
file="$1"
# For each input line:
# We take only the values of the first field, sort them, remove duplicates
for i in $(cut -d ',' -f 1 "$file" | sort -n -u); do
# Resetting the array is not really needed; we do it for safety
out=()
# The first field of the output row is the key of the loop
out[0]="$i"
# We only consider the rows whose first field is equal
# to the current key (grep) and...
#... we sort the values of the second field
# in ascending order and take only the first one
out[1]="$(grep "^${out[0]}" "$file" | cut -d ',' -f 2 | sort -n | head -n 1)"
#... we sort the values of the third field in
# ascending order and take only the last one
out[2]="$(grep "^${out[0]}" "$file" | cut -d ',' -f 3 | sort -n | tail -n 1)"
#... we sort the values of the fourth field in
# ascending order and take only the first one
out[3]="$(grep "^${out[0]}" "$file" | cut -d ',' -f 4 | sort -n | head -n 1)"
# Finally we print out the output, separating fields with ','
printf '%s,%s,%s,%s\n' "${out[@]}"
done
Он должен вызываться как
./script file
Этот скрипт эквивалентен
SELECT col1, MIN(col2), MAX(col3), MIN(col4)
FROM text
GROUP BY col1
ORDER BY col1