[pol@fedora data]$ lsb_release -a
LSB Version: :core-4.1-amd64:core-4.1-noarch
Distributor ID: Fedora
Description: Fedora release 34 (Thirty Four)
Release: 34
Codename: ThirtyFour
MS SQL Server의 샘플 데이터베이스 파일을 PostgreSQL로 변환하려고 합니다.
그래서 제가 해결할 수 없는 두 가지 작은 문제가 있습니다.
shipname NVARCHAR(40) NOT NULL,
그건
(언제나) 공백 두 개
식별자(예: 필드 이름) - 항상 [az] - 소문자
그 뒤에 알 수 없는 수의 공백이 옵니다.
NVARCHAR(xy) NOT NULL이 뒤따릅니다.또는NVARCHAR(xy) NULL이 뒤에 올 수 있습니다.
나는 그것을 바꾸고 싶다
shipname TEXT NOT NULL CHECK (LENGTH(shipname) <= xy),
또는
shipname TEXT NULL,
내가 지금까지 가지고 있는 것:
sed 's/^ [a-z]+[ ]+NVARCHAR([0-9]+) NOT NULL/TEXT NOT NULL CHECK \(LENGTH\((\1) <= (\2)\)/g'
그래서,
^
문자열의 시작 부분입니다그 뒤에 공백 두 개
다음은 내 필드 이름입니다. [az]+
그 뒤에는 임의의 숫자가 옵니다. 공간[ ]+
NVARCHAR([0-9]+)
그리고 대체
TEXT
NOT NULL 다음에 CHECK(LENGTH(xy) - 역참조 1 - <= 역참조 2...
위의 내용을 다양하게 변형하고 조합해 보았지만 아무 것도 나에게 맞는 것 같지 않습니다.
[pol@fedora data]$ sed 's/^ [a-z]+[ ]+NVARCHAR([0-9]+) NOT NULL/TEXT NOT NULL CHECK \(LENGTH\((\1) <= (\2)\)/g'
sed: -e expression #1, char 87: invalid reference \2 on `s' command's RHS
잘못된 역참조를 받는 중...
이상적으로는, 나는 강조한다이상적으로는, NVARCHAR(xy) 다음의 문자열이 다음 NULL
과 같은 경우아니요 NOT NULL
, 길이 검사를 수행하고 싶지 않습니다. NULL 길이를 취하는 것은 의미가 없기 때문입니다... 이는 조건부 동작입니다. 정규식에서 가능한지 확실하지 않습니다...
ps. 이건 사소한 일인 것 같아요.
다음과 같은 데이터가 있습니다.
N'Strada Provinciale 1234', N'Reggio Emilia', NULL, N'10289', N'Italy');
간단한 아포스트로피 ( SQL Server의 경우) N'
로 변경 하고 싶지만 빈 문자열 로 변경 하거나 더 나쁘게 변경하고 싶지 않으므로 다음 과 같이 시도합니다.'
N'
NULL
ULL
[pol@fedora data]$ sed 's/N\'\'/g TSQLV5.sql
하지만 얻을
sed: -e expression #1, char 7: unterminated `s' command
sed
나는 그것을 많이 사용해 왔다는 것을 알고 있지만 awk
필요한 것을 수행하는 모든 명령에 열려 있습니다.
답변1
당신이 사용한 이후 fedora
: GNU sed
이것이 작동해야합니다 :
s=" shipname NVARCHAR(40) NOT NULL,"
echo "$s" | sed -E '/NOT/{s/^ ([[:lower:]]+)\s*NVARCHAR\(([[:digit:]]+)\) NOT NULL,$/\1 TEXT NOT NULL CHECK \(LENGTH\(\1\) <= \2\),/;q0} ; s/^ ([[:lower:]]+)/\1 TEXT NULL,/'
이것은 가짜 if를 시뮬레이션합니다.
if
:
db 구조에서 ()를 찾은 NOT
다음 첫 번째 sed 명령을 실행하고 두 번째 명령문을 실행하지 않고 종료()합니다./NOT/
q0
else
:
키워드를 찾을 수 없으면 NOT
두 번째 인스턴스가 실행됩니다.
두 번째 요구 사항의 경우:
sed "s/N'/'/g"
전역 N'
적으로 검색하여 '
. 많은 이스케이프 작업을 수행하지 않고도 더 깔끔하게 만들 수 있도록 '
명령줄 구분 기호로 "
바꾸는 것이 유용하다고 생각합니다 .sed
첫 번째 것을 sed
파일에 넣으십시오.
#!/bin/sed -Ef
# If a NOT is found execute this:
# capture the column name and the value of this
/NOT/ {
s/^ ([[:lower:]]+)\s*NVARCHAR\(([[:digit:]]+)\) NOT NULL,$/\1 TEXT NOT NULL CHECK \(LENGTH\(\1\) <= \2\),/
# Quit without execute the other statement
q0
}
# Else: If we are here then the database
# structure does not contains a length for the column;
# so it should be NULL
s/^ ([[:lower:]]+)/\1 TEXT NULL,/
이 명령은 더 많은 명령을 그룹화 {
하는 데 사용됩니다 .sed
종료 하라는 명령 입니다 q
. 첫 번째 테스트가 성공하면 마지막 줄을 만나기 전에 강제 종료하기 위해 여기에서 사용하고 있습니다.quit
sed
sed
답변2
이미 답을 얻었지만 문제에 대한 자신만의 접근 방식을 추가하여 일부 솔루션을 복사하는 대신 문제에서 배울 수 있도록 하고 싶었습니다.
- 확장 정규식을 사용하지만
-E
옵션 을 제공하는 것을 잊었습니다sed
. - 식별자를 재사용하고 싶지만 포함하지 마세요.
()
()
ERE 그룹과 텍스트 그룹을 혼합하는 것 같습니다 . 아마 당신 말은sed -E 's/^ ([a-z]+)[ ]+NVARCHAR\(([0-9]+)\) NOT NULL/TEXT NOT NULL CHECK \(LENGTH\((\1) <= (\2)\)/g'
- 교체 시 공간의 첫 번째 부분까지는 표시되지 않습니다. 또한 이를 그룹화하여 교체 시 참조로 사용해야 합니다.
sed -E 's/^( ([a-z]+)[ ]+)NVARCHAR\(([0-9]+)\) NOT NULL/\1TEXT NOT NULL CHECK \(LENGTH\((\2) <= (\3)\)/g'
[ ]+
와 동일합니다+
. 이는 오류는 아니지만 읽기를 더 혼란스럽게 만듭니다.- 이
g
옵션은 중복됩니다.^
또는 같은 앵커 로는$
여러 번 교체할 수 없습니다 . - 선택적 옵션을 설정하여 여러 표현식을 피할 수 있습니다
NOT
: `sed -E 's/^( ([az]+) +)NVARCHAR(([0-9]+)) (NOT )?NULL/\1TEXT \4NULL CHECK ( 길이((\2) <= (\3))/' - 반면에 검사를 생략하려면 별도의 대체 방법으로 수행할 수 있습니다.
s/^( [a-z]+ +)NVARCHAR\(([0-9]+)\) NULL/\1TEXT NULL/
s/N\'\'/g
검색 패턴과 바꾸기 사이의 구분 기호를 놓쳤습니다 .s/N\'/\'/g
그래서 당신은 결국
sed -E 's/^( ([a-z]+) +)NVARCHAR\(([0-9]+)\) NOT NULL/\1TEXT NOT NULL CHECK \(LENGTH\((\2) <= (\3)\)/
s/^( [a-z]+ +)NVARCHAR\(([0-9]+)\) NULL/\1TEXT NULL/
s/N\'/\'/g'
답변3
sed
일부 작업에는 매우 유용하지만 다른 작업 에는 조건문 및 printf 등과 awk
같은 모든 기능을 갖춘 언어가 필요합니다 . perl
정규식과 RPN 계산기의 끔찍한 혼합처럼 읽히지 않는 언어가 바람직합니다 :-).
#!/usr/bin/perl
use strict;
while(<>) {
# print verbatim any lines that don't define an identifier
unless (m/^\s+\S/) { print; next };
# print a blank line before certain identifiers
print "\n" if m/birthdate|address|phone/;
# various regex transformations for IDENTITY and VARCHAR fields
s/\s+NOT NULL IDENTITY/ GENERATED BY DEFAULT AS IDENTITY/;
s/([[:lower:]]+)\s+NVARCHAR\((\d+)\) NOT NULL/$1 TEXT NOT NULL CHECK (LENGTH($1) <= $2)/;
s/\s+NVARCHAR\((\d+)\)\s+NULL/ TEXT NULL/;
# remove length checks from NULL definitions
s/\s+CHECK.*/,/ if /(?<!NOT) NULL/;
# add a comma at the end of the mgrid line if it's not there
s/\s*$/,/ if /mgrid/ && ! /,\s*$/;
# hacky crap to nicely format "TYPE (NOT )?NULL" output.
my @F = split;
my $identifier = shift @F;
my $type = shift @F;
$type .= " " . shift @F if ($F[0] =~ /NOT/);
$type = sprintf "%-8s", $type;
$type .= " " . shift @F if ($F[0] =~ /NULL/);
printf " %-15s %-13s%s\n", $identifier, $type, join(" ",'',@F);
# print the test_field definition after mgrid
if ($identifier eq 'mgrid') {
print " test_field TEXT NULL CHECK (LENGTH(test_field) <= 25)\n";
};
}
이는 입력을 (거의) 원하는 출력으로 변환하는 상당히 무차별적인 방법입니다. 일부 정규식 변환 및 "필드"를 멋지게 정렬하는 일부 코드. 그리고 적절한 경우 빈 줄과 test_field를 추가하는 추가 인쇄 문도 있습니다. 따라서 일반적으로 유용하지는 않지만 필요에 따라 다른 SQL 변환을 수용하도록 조정할 수 있습니다.
스크립트는 "필수 출력"에 표시된 내용이 아닌 질문에 설명된 내용을 구현합니다. 예를 들어 NULL 필드이기 때문에 길이 확인 및 길이 확인이
region
없습니다 .postalcode
산출:
CREATE TABLE employee
(
empid INT GENERATED BY DEFAULT AS IDENTITY,
lastname TEXT NOT NULL CHECK (LENGTH(lastname) <= 20),
firstname TEXT NOT NULL CHECK (LENGTH(firstname) <= 10),
title TEXT NULL,
titleofcourtesy TEXT NULL,
birthdate DATE NOT NULL,
hiredate DATE NOT NULL,
address TEXT NOT NULL CHECK (LENGTH(address) <= 60),
city TEXT NOT NULL CHECK (LENGTH(city) <= 15),
region TEXT NULL,
postalcode TEXT NULL,
country TEXT NOT NULL CHECK (LENGTH(country) <= 15),
phone TEXT NOT NULL CHECK (LENGTH(phone) <= 24),
mgrid INT NULL,
test_field TEXT NULL CHECK (LENGTH(test_field) <= 25)
);
스크립트 출력이 원하는 출력과 어떻게 다른지는 다음과 같습니다(주석 및 일부 불필요한 공백 문자를 제거하기 위해 정리한 후).
- region TEXT NULL CHECK (LENGTH(region) <= 15),
- postalcode TEXT NULL CHECK (LENGTH(postalcode) <= 10),
+ region TEXT NULL,
+ postalcode TEXT NULL,
기타 제안사항:
당신은
PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY
원할 수도 있습니다empid
postgresql에는 TEXT보다 더 적합하고 변환이 더 간단한 VARCHAR(n) 데이터 유형이 있습니다
s/NVARCHAR/VARCHAR/
. VARCHAR의 길이는 고정되어 있으므로 a) 길이 제약 검사가 필요하지 않으며 b) 인덱싱 및 검색이 더 빠릅니다.필드가 NULL이 되도록 허용하는 것이 기본값이므로 명시적으로 정의할 필요가 없습니다.