UFO ET IT

MySQL 명령 줄 결과의 출력 형식을 CSV로 변경

ufoet 2020. 12. 15. 19:35
반응형

MySQL 명령 줄 결과의 출력 형식을 CSV로 변경


명령 줄에서 MySQL에 대한 쿼리 출력에서 ​​헤더없는 CSV 데이터를 가져오고 싶습니다. 이 쿼리를 MySQL 서버와 다른 컴퓨터에서 실행하고 있으므로 "INTO OUTFILE"에 대한 모든 Google 답변은 좋지 않습니다.

그래서 나는 mysql -e "select people, places from things". 그러면 다음과 같은 결과가 출력됩니다.

+--------+-------------+
| people | places      |
+--------+-------------+
|   Bill | Raleigh, NC |
+--------+-------------+

글쎄, 그것은 좋지 않다. 하지만보세요! 에 난 그냥 파이프를하면 무엇이든 , 그것은 탭으로 구분 된 목록으로 변합니다 :

people  places
Bill    Raleigh, NC

적어도 프로그래밍 방식으로 파싱 할 수 있습니다. 하지만 저는 TSV를 원하지 않고 CSV를 원하며 그 헤더를 원하지 않습니다. 를 사용하여 헤더를 제거 할 수 mysql <stuff> | tail -n +2있지만 MySQL에 생략 할 플래그가있는 경우 피하고 싶은 문제입니다. 모든 탭을 쉼표로 바꿀 수는 없습니다. 쉼표가있는 콘텐츠를 처리하지 않기 때문입니다.

그렇다면 MySQL이 헤더를 생략하고 CSV 형식으로 데이터를 제공하도록하려면 어떻게해야합니까?


부분적인 답변 : mysql -N -B -e "select people, places from things"

-N열 머리글을 인쇄하지 않도록 지시합니다. -B"일괄 모드"이며 탭을 사용하여 필드를 구분합니다.

탭으로 구분 된 값으로 충분하지 않은 경우이 Stackoverflow Q & A를 참조 하세요 .


이 문제를 해결 하기 위해 명령 줄 도구를 직접 작성 했습니다. 그것은 비슷 cut가 Jimothy의 대답 @와 짝을 인용 필드 등이 도구로 무엇을 알고 제외하고, 내가이 명령을 내 로컬 컴퓨터에 내가에는 파일 시스템에 액세스 할 수 없습니다 원격 MySQL 서버에서 헤더가 CSV를 얻을 수 있습니다 :

$ mysql -N -e "select people, places from things" | csvm -i '\t' -o ','
Bill,"Raleigh, NC"

github의 csvmaster


위의 솔루션은 특별한 경우에만 작동합니다. 일반적으로 CSV를 어렵게 만드는 포함 된 쉼표, 포함 된 따옴표 등 모든 종류의 문제에 직면하게됩니다.

자신에게 호의를 베풀고 일반적인 솔루션을 사용하십시오. 올바르게 수행하면 다시 생각할 필요가 없습니다. 매우 강력한 솔루션 중 하나는 csvkitPython을 통해 모든 운영 체제에서 사용할 수 있는 명령 줄 유틸리티입니다. 를 통해 설치하십시오 pip install csvkit. 그러면 올바른 CSV 데이터가 제공됩니다.

    mysql -e "select people, places from things" | csvcut -t

그러면 헤더가 제자리에있는 쉼표로 구분 된 데이터가 생성됩니다. 헤더 행을 삭제하려면 :

    mysql -e "select people, places from things" | csvcut -t | tail -n +2

그것은 OP가 요청한 것을 생성합니다.


추가 비표준 도구없이 클라이언트 측에서 CSV에 결과를 저장하는 방법입니다. 이 예 에서는 mysql 클라이언트 및 awk.

한 줄:

mysql --skip-column-names --batch -e 'select * from dump3't | awk -F '\ t' '{sep = ""; for (i = 1; i <= NF; i ++) {gsub (/ \\ t /, "\ t", $ i); gsub (/ \\ n /, "\ n", $ i); gsub (/ \\\\ /, "\\", $ i); gsub (/ "/,"\ "\" ", $ i); printf sep"\ ""$ i "\" "; sep =", "; if (i == NF) {printf"\ n "} }} '

수행해야 할 작업에 대한 논리적 설명

  1. 먼저 RAW 모드 ( --raw옵션 포함) 에서 데이터가 어떻게 보이는지 살펴 보겠습니다 . 데이터베이스 및 테이블이 각각 있습니다 tdump3

    "new line"(첫 번째 행)에서 시작하는 필드가 값에 새 줄이 배치되어 세 줄로 분할되는 것을 볼 수 있습니다.

mysql --skip-column-names --batch --raw -e 'select * from dump3't

한 줄 2 새 줄
인용 부호 "백 슬래시 \ 두 개의 인용 부호" "두 개의 백 슬래시 \\ 두 개의 탭 새 줄
필드의 끝

다른 줄 1 특수 문자가없는 다른 줄 설명
  1. 일괄 모드의 OUTPUT 데이터 ( --raw옵션 없음)-각 레코드는 \ <tab>같은 문자를 이스케이프하여 한 줄 텍스트로 변경했습니다.new-lines
mysql --skip-column-names --batch -e 'select * from dump3't

한 줄 새 줄 2 개 \ n 따옴표 "백 슬래시 \\ 따옴표 두 개" "백 슬래시 두 개 \\\\ 탭 두 개 \ t \ t 새 줄 \ n 필드 끝
다른 줄 1 특수 문자가없는 다른 줄 설명
  1. 그리고 CSV 형식의 데이터 출력

단서는 이스케이프 문자를 사용하여 CSV 형식으로 데이터를 저장하는 것입니다.

이를 수행하는 방법 mysql --batch은 ( 백쉬 래시와 개행 \t으로 탭 \\으로) 생성 하는 특수 엔티티 \n를 각 값 (필드)에 대해 동등한 바이트로 변환하는 것입니다. 그런 다음 전체 값은로 이스케이프되고 "로 둘러싸여 있습니다 ". Btw-이스케이프 및 둘러싸기에 동일한 문자를 사용하면 두 개의 특수 문자가 없기 때문에 출력 및 처리가 부드럽게 단순화됩니다. 이러한 이유로 csv 형식 관점에서 값을 사용하여해야 할 일은 값을 변경 "하는 것 ""입니다. 일반적인 방법으로 (탈출 각각 둘러싸로 \하고 ") 먼저 변화해야 \하는 \\다음 변경 "으로 \".

그리고 단계별 명령 설명 :

# we produce one-line output as showed in step 2.
mysql --skip-column-names --batch -e 'select * from dump3' t

# set fields separator to  because mysql produces in that way
| awk -F'\t' 

# this start iterating every line/record from the mysql data - standard behaviour of awk
'{ 

# field separator is empty because we don't print a separator before the first output field
sep=""; 

-- iterating by every field and converting the field to csv proper value
for(i = 1; i <= NF; i++) { 
-- note: \\ two shlashes below mean \ for awk because they're escaped

-- changing \t into byte corresponding to <tab> 
    gsub(/\\t/, "\t",$i); 

-- changing \n into byte corresponding to new line
    gsub(/\\n/, "\n",$i); 

-- changing two \\ into one \  
    gsub(/\\\\/,"\\",$i);

-- changing value into CSV proper one literally - change " into ""
    gsub(/"/,   "\"\"",$i); 

-- print output field enclosed by " and adding separator before
    printf sep"\""$i"\"";  

-- separator is set after first field is processed - because earlier we don't need it
    sep=","; 

-- adding new line after the last field processed - so this indicates csv record separator
    if(i==NF) {printf"\n"} 
    }
}'

mysqldump utility can help you, basically with --tab option it's a wrapped for SELECT INTO OUTFILE statement.

Example:

mysqldump -u root -p --tab=/tmp world Country --fields-enclosed-by='"' --fields-terminated-by="," --lines-terminated-by="\n" --no-create-info

This will create csv formatted file /tmp/Country.txt


How about using sed? It comes standard with most (all?) Linux OS.

sed 's/\t/<your_field_delimiter>/g'.

This example uses GNU sed (Linux). For POSIX sed (AIX/Solaris)I believe you would type a literal TAB instead of \t

Example (for CSV output):

#mysql mysql -B -e "select * from user" | while read; do sed 's/\t/,/g'; done

localhost,root,,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,,,,,0,0,0,0,,
localhost,bill,*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,,,,,0,0,0,0,,
127.0.0.1,root,,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,,,,,0,0,0,0,,
::1,root,,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,Y,,,,,0,0,0,0,,
%,jim,*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,,,,,0,0,0,0,,

ReferenceURL : https://stackoverflow.com/questions/15640287/change-output-format-for-mysql-command-line-results-to-csv

반응형