Linux

正則表達式 - SQL 操作

  • June 2, 2021
[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,

那是

  • 總是)兩個空格
  • 標識符(即欄位名稱) - 總是

$$ a-z $$- 小寫字母

  • 後跟未知數量的空格
  • 後跟 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'    

所以,

  • ^是字元串的開頭
  • 後跟兩個空格
  • 後跟我的欄位名

$$ a-z $$+

  • 後跟任意編號。空間

$$ $$+

  • 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) &lt;= (\2)\)/g' 
sed: -e expression #1, char 87: invalid reference \2 on `s' command's RHS

獲取無效的反向引用…

理想情況下,我強調理想情況下,如果 NVARCHAR(xy) 後面的字元串是NULL不是 NOT NULL,我不想要任何長度檢查 - 因為取 NULL 的 LENGTH 是沒有意義的……這是有條件的行為 -不確定在正則表達式中是否可能……

ps認為這將是微不足道的。

有這樣的數據:

N'Strada Provinciale 1234', N'Reggio Emilia', NULL, N'10289', N'Italy');

我想將其更改N'為簡單的撇號'(這N'是 SQL Server 的東西),但我不想將其更改NULL為空字元串,或者更糟ULL- 所以我嘗試了:

[pol@fedora data]$ sed 's/N\'\'/g TSQLV5.sql 

但得到

sed: -e expression #1, char 7: unterminated `s' command

我知道我已經使用sed了很多,但我願意接受任何awk可以執行所需任務的命令。

您已經得到了答案,但我想在您自己的方法中添加問題所在,以便您可以從中學習,而不僅僅是複制一些解決方案:

  • 您使用擴展的正則表達式,但忘記-Esed.
  • 您想重用標識符,但未將其包含在()
  • 您似乎將 ERE()組與文字組混合在一起。你大概是說sed -E 's/^ ([a-z]+)[ ]+NVARCHAR\(([0-9]+)\) NOT NULL/TEXT NOT NULL CHECK \(LENGTH\((\1) &lt;= (\2)\)/g'
  • 替換中不顯示空格的第一部分。您還需要對其進行分組並將其用作替換中的參考:sed -E 's/^( ([a-z]+)[ ]+)NVARCHAR\(([0-9]+)\) NOT NULL/\1TEXT NOT NULL CHECK \(LENGTH\((\2) &lt;= (\3)\)/g'
  • [ ]+是一樣的 +。不是錯誤,但會使閱讀更加混亂。
  • g選項是多餘的。使用類似錨^$在模式中的多個替換是不可能的。
  • 您可以通過使NOT選項避免多個表達式:`sed -E ’s/^( ($$ a-z $$+) +)NVARCHAR(($$ 0-9 $$+)) (NOT )?NULL/\1TEXT \4NULL CHECK (LENGTH((\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) &lt;= (\3)\)/
 s/^(  [a-z]+ +)NVARCHAR\(([0-9]+)\) NULL/\1TEXT NULL/
 s/N\'/\'/g'

既然你使用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\) &lt;= \2\),/;q0} ; s/^  ([[:lower:]]+)/\1 TEXT NULL,/'

這模擬了一個假的 if。

if:

a NOT( /NOT/) 在 db 結構中找到,然後執行第一個 sed 命令,然後退出 ( q0) 而不執行第二個語句。

else:

沒有NOT找到關鍵字,執行第二個實例。


對於第二個要求:

sed "s/N'/'/g"

全域搜尋N'並將其替換為 only ''我發現與"for命令行分隔符交換很有用,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\) &lt;= \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命令組合在一起。

qquit命令,它用於使sed退出。如果第一次測試成功,我在這裡使用它來強制sed退出,然後再遇到最後一行。

引用自:https://unix.stackexchange.com/questions/652342