2009-05-22 50 views
115

今天在辦公室出現了。我沒有計劃做這樣的事情,但理論上你可以在SQL中編寫一個編譯器嗎?初看起來,我認爲這是徹底的,儘管對於很多類別的問題都非常麻煩。是SQL甚至TSQL圖靈完成?

如果它不是完整的,它會變成什麼樣子?

注意:我不想做任何事情,比如在SQL中編寫一個編譯器,我知道這將是一件愚蠢的事情,所以如果我們可以避免這種討論,我將不勝感激。

回答

157

事實證明,即使沒有真正的'腳本'擴展,如PL/SQL或PSM(它們被設計成真正的編程語言,SQL也可以是圖靈完整的這有點欺騙)。

this set of slides Andrew Gierth通過構建一個cyclic tag system證明了CTE和窗口化SQL是Turing Complete,它已被證明是Turing Complete。然而,CTE功能是重要的部分 - 它允許您創建可以引用自己的命名子表達式,從而遞歸地解決問題。

有趣的是,CTE並沒有真正添加到將SQL轉換爲編程語言 - 只是將聲明式查詢語言轉變爲更強大的聲明式查詢語言。有點像C++,儘管它們並不打算創建元編程語言,但其模板竟然是圖靈完備的。

呵呵,Mandelbrot set in SQL例子是非常可觀的,以及:)

+0

的Oracle SQL也圖靈完備,但在一個相當病態的方式:http://blog.schauderhaft.de/2009/06/18/building-a-turing-engine-in -oracle-sql-using-the-model-clause/ – 2014-08-19 05:38:31

+1

>事實證明,SQL 不應該這樣說:事實證明SQL:1999?只是這樣說,因爲CTE是在版本99中添加的,太多人將標準sql與Sql 92關聯起來。 – Ernesto 2014-11-13 14:22:03

27

http://channel9.msdn.com/forums/TechOff/431432-SQL-Turing-Completeness-question/

是這個話題的討論。一個報價:

SQL本身(即SQL92標準)不是完整的。但是,許多從SQL派生的語言,例如Oracle的PL/SQL和SQL Server的T-SQL等等都是完整的。

PL/SQL和T-SQL肯定有資格作爲編程語言,SQL92本身是否具備資格是有爭議的。有些人聲稱任何告訴計算機做什麼的代碼都可以用作編程語言;根據該定義,SQL92是一個,但也是如此HTML。這個定義相當模糊,而且這是一個毫無意義的爭論點。

12

嚴格地說,SQL現在是一種完全圖靈化的語言,因爲最新的SQL標準包含了「持久存儲模塊」(PSMs)。簡而言之,PSM是Oracle中的PL/SQL語言的標準版本(以及當前DBMS的其他類似程序擴展)。

連同這些的PSM的,SQL成爲圖靈完備

11

的ANSI SELECT語句,如最初在SQL-86定義的,不是圖靈完成,因爲它總是終止只有在執行(除遞歸的CTE和支持任意深度遞歸)。因此不可能模擬任何其他圖靈機。存儲過程完成,但那是作弊;-)

18

的TSQL是圖靈Complete.To證明這一點我做了一個BrainFuck解釋。

BrainFuck interpreter in SQL - GitHub

-- Brain Fuck interpreter in SQL 

DECLARE @Code VARCHAR(MAX) = ', [>,] < [.<]' 
DECLARE @Input VARCHAR(MAX) = '!dlroW olleH'; 

-- Creates a "BrainFuck" DataBase. 
-- CREATE DATABASE BrainFuck; 

-- Creates the Source code table 
DECLARE @CodeTable TABLE (
    [Id]  INT IDENTITY(1,1) PRIMARY KEY NOT NULL, 
    [Command] CHAR(1) NOT NULL 
); 

-- Populate the source code into CodeTable 
DECLARE @CodeLen INT = LEN(@Code); 
DECLARE @CodePos INT = 0; 
DECLARE @CodeChar CHAR(1); 

WHILE @CodePos < @CodeLen 
BEGIN 
    SET @CodePos = @CodePos + 1; 
    SET @CodeChar = SUBSTRING(@Code, @CodePos, 1); 
    IF @CodeChar IN ('+', '-', '>', '<', ',', '.', '[', ']') 
     INSERT INTO @CodeTable ([Command]) VALUES (@CodeChar) 
END 

-- Creates the Input table 
DECLARE @InputTable TABLE (
    [Id] INT IDENTITY(1,1) PRIMARY KEY NOT NULL, 
    [Char] CHAR(1) NOT NULL 
); 

-- Populate the input text into InputTable 
DECLARE @InputLen INT = LEN(@Input); 
DECLARE @InputPos INT = 0; 

WHILE @InputPos < @InputLen 
BEGIN 
    SET @InputPos = @InputPos + 1; 
    INSERT INTO @InputTable ([Char]) 
    VALUES (SUBSTRING(@Input, @InputPos, 1)) 
END 

-- Creates the Output table 
DECLARE @OutputTable TABLE (
    [Id] INT IDENTITY(1,1) PRIMARY KEY NOT NULL, 
    [Char] CHAR(1) NOT NULL 
); 

-- Creates the Buffer table 
DECLARE @BufferTable TABLE (
    [Id]  INT IDENTITY(1,1) PRIMARY KEY NOT NULL, 
    [Memory] INT DEFAULT 0 NOT NULL 
); 
INSERT INTO @BufferTable ([Memory]) 
VALUES (0); 

-- Initialization of temporary variables 
DECLARE @CodeLength INT = (SELECT COUNT(*) FROM @CodeTable); 
DECLARE @CodeIndex INT = 0; 
DECLARE @Pointer INT = 1; 
DECLARE @InputIndex INT = 0; 
DECLARE @Command CHAR(1); 
DECLARE @Depth  INT; 

-- Main calculation cycle 
WHILE @CodeIndex < @CodeLength 
BEGIN 
    -- Read the next command. 
    SET @CodeIndex = @CodeIndex + 1; 
    SET @Command = (SELECT [Command] FROM @CodeTable WHERE [Id] = @CodeIndex); 

    -- Increment the pointer. 
    IF @Command = '>' 
    BEGIN 
     SET @Pointer = @Pointer + 1; 
     IF (SELECT [Id] FROM @BufferTable WHERE [Id] = @Pointer) IS NULL 
      INSERT INTO @BufferTable ([Memory]) VALUES (0); 
    END 

    -- Decrement the pointer. 
    ELSE IF @Command = '<' 
     SET @Pointer = @Pointer - 1; 

    -- Increment the byte at the pointer. 
    ELSE IF @Command = '+' 
     UPDATE @BufferTable SET [Memory] = [Memory] + 1 WHERE [Id] = @Pointer; 

    -- Decrement the byte at the pointer. 
    ELSE IF @Command = '-' 
     UPDATE @BufferTable SET [Memory] = [Memory] - 1 WHERE [Id] = @Pointer; 

    -- Output the byte at the pointer. 
    ELSE IF @Command = '.' 
     INSERT INTO @OutputTable ([Char]) (SELECT CHAR([Memory]) FROM @BufferTable WHERE [Id] = @Pointer); 

    -- Input a byte and store it in the byte at the pointer. 
    ELSE IF @Command = ',' 
    BEGIN 
     SET @InputIndex = @InputIndex + 1; 
     UPDATE @BufferTable SET [Memory] = COALESCE((SELECT ASCII([Char]) FROM @InputTable WHERE [Id] = @InputIndex), 0) WHERE [Id] = @Pointer; 
    END 

    -- Jump forward past the matching ] if the byte at the pointer is zero. 
    ELSE IF @Command = '[' AND COALESCE((SELECT [Memory] FROM @BufferTable WHERE [Id] = @Pointer), 0) = 0 
    BEGIN 
     SET @Depth = 1; 
     WHILE @Depth > 0 
     BEGIN 
      SET @CodeIndex = @CodeIndex + 1; 
      SET @Command = (SELECT [Command] FROM @CodeTable WHERE [Id] = @CodeIndex); 
      IF @Command = '[' SET @Depth = @Depth + 1; 
      ELSE IF @Command = ']' SET @Depth = @Depth - 1; 
     END 
    END 

    -- Jump backward to the matching [ unless the byte at the pointer is zero. 
    ELSE IF @Command = ']' AND COALESCE((SELECT [Memory] FROM @BufferTable WHERE [Id] = @Pointer), 0) != 0 
    BEGIN 
     SET @Depth = 1; 
     WHILE @Depth > 0 
     BEGIN 
      SET @CodeIndex = @CodeIndex - 1; 
      SET @Command = (SELECT [Command] FROM @CodeTable WHERE [Id] = @CodeIndex); 
      IF @Command = ']' SET @Depth = @Depth + 1; 
      ELSE IF @Command = '[' SET @Depth = @Depth - 1; 
     END 
    END 
END; 

-- Collects and prints the output 
DECLARE @Output VARCHAR(MAX); 
SELECT @Output = COALESCE(@Output, '') + [Char] 
FROM @OutputTable; 

PRINT @Output; 
Go