SQL หรือแม้แต่ TSQL ทัวริงเสร็จสมบูรณ์หรือไม่


171

สิ่งนี้เกิดขึ้นที่สำนักงานวันนี้ ฉันไม่มีแผนที่จะทำสิ่งนั้น แต่ในทางทฤษฎีคุณสามารถเขียนคอมไพเลอร์ใน SQL ได้ไหม? เมื่อฉันมองแวบแรกมันก็ดูจะสมบูรณ์แม้ว่าจะมีปัญหามากมายสำหรับชั้นเรียน

ถ้ามันไม่ได้ทำให้เสร็จสมบูรณ์มันจะต้องมีอะไรบ้าง?

หมายเหตุ: ฉันไม่มีความปรารถนาที่จะทำอะไรเช่นเขียนคอมไพเลอร์ใน SQL ฉันรู้ว่ามันเป็นเรื่องโง่ที่จะทำดังนั้นถ้าเราสามารถหลีกเลี่ยงการอภิปรายฉันจะขอบคุณมัน

คำตอบ:


219

ปรากฎว่า SQL สามารถทำให้ทัวริงสมบูรณ์แม้ว่าจะไม่มีส่วนขยาย 'การเขียนสคริปต์' ที่แท้จริงเช่น PL / SQL หรือ PSM (ซึ่งได้รับการออกแบบให้เป็นภาษาการเขียนโปรแกรมจริงดังนั้นจึงเป็นการโกง)

ในชุดของสไลด์นี้ Andrew Gierth พิสูจน์ว่าด้วย CTE และ Windowing SQL คือ Turing Complete โดยการสร้างระบบ tag cyclicซึ่งได้รับการพิสูจน์แล้วว่าเป็นทัวริงที่สมบูรณ์ อย่างไรก็ตามคุณลักษณะ CTE เป็นส่วนสำคัญ แต่ช่วยให้คุณสร้างนิพจน์ย่อยที่มีชื่อซึ่งสามารถอ้างถึงตัวเองและดังนั้นจึงแก้ปัญหาซ้ำ ๆ

สิ่งที่น่าสนใจที่จะต้องทราบก็คือ CTE ไม่ได้ถูกเพิ่มเข้ามาเพื่อเปลี่ยน SQL ให้เป็นภาษาการเขียนโปรแกรมเพียงเพื่อเปลี่ยนภาษาการสืบค้นแบบประกาศเป็นภาษาการสืบค้นที่มีประสิทธิภาพยิ่งขึ้น เรียงลำดับเหมือนใน C ++ ซึ่งเทมเพลตกลายเป็นทัวริงสมบูรณ์แม้ว่าพวกเขาไม่ได้ตั้งใจจะสร้างภาษาการเขียนโปรแกรมเมตา

โอ้ชุด Mandelbrot ในตัวอย่างSQLนั้นน่าประทับใจมากเช่นกัน :)


1
Oracle SQL นั้นได้รับการทำให้สมบูรณ์ด้วยเช่นกันแม้ว่าจะค่อนข้างแย่: blog.schauderhaft.de/2009/06/18/ …
Jens Schauder

2
> ปรากฎว่า SQL ไม่ควรพูดว่า: ปรากฎว่า SQL: 1999 เพียงแค่พูดแบบนี้เพราะ CTEs ถูกเพิ่มเข้ามาในเวอร์ชั่น 99 และมีคนจำนวนมากที่เชื่อมโยง sql มาตรฐานกับ Sql 92
Ernesto

1
@JensSchauder ที่สามารถพูดถึง "เทคโนโลยี Oracle $ คือ $ some_good_feature แม้ว่าจะเป็นวิธีที่ค่อนข้างแย่"
Rob Grant

3
เป็นเวลา 9 ปีแล้ว แต่นี่อาจเป็นสิ่งที่น่าสนใจสำหรับbeta.observablehq.com/@pallada-92/sql-3d-engine
Loupax

33

ภาษาการเขียนโปรแกรมที่ระบุไว้ว่าทัวริงเสร็จสมบูรณ์หากสามารถแสดงให้เห็นว่ามันเทียบเท่ากับการคำนวณเครื่องทัวริง

TSQL นั้นสมบูรณ์แบบเพราะเราสามารถสร้างล่ามBrainFuckใน TSQL

ตัวแปล BrainFuck ใน 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 backwards 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

นั่นคือทรานแซคชั่น SQL ซึ่งเป็นทัวริงสมบูรณ์ ANSI SQL ที่ฉันเข้าใจไม่ใช่ TC แต่ความพยายามดี!
alimack

28

https://web.archive.org/web/20110807062050/http://channel9.msdn.com/forums/TechOff/431432-SQL-Turing-Completeness-question

เป็นการสนทนาในหัวข้อนี้ คำพูด:

SQL เป็นเช่นนั้น (เช่นมาตรฐาน SQL92) ไม่ได้ทำให้สมบูรณ์ อย่างไรก็ตามภาษาหลายภาษาที่ได้มาจาก SQL เช่น T / SQL ของ Oracle และ SQL Server ของ T-SQL และภาษาอื่น ๆ กำลังถูกทำให้สมบูรณ์

PL / SQL และ T-SQL มีคุณสมบัติเป็นภาษาการเขียนโปรแกรมอย่างแน่นอนไม่ว่า SQL92 เองจะมีคุณสมบัติเปิดให้มีการอภิปรายหรือไม่ บางคนอ้างว่ารหัสใด ๆ ที่บอกคอมพิวเตอร์ว่าจะต้องมีคุณสมบัติเป็นภาษาโปรแกรมหรือไม่ โดยนิยาม SQL92 นั้นเป็นหนึ่ง แต่เป็นเช่น HTML คำจำกัดความค่อนข้างคลุมเครือและเป็นสิ่งที่ไม่มีเหตุผลที่จะโต้แย้ง


15

ตอนนี้ SQL กำลังพูดอย่างเคร่งครัดอยู่เนื่องจากภาษา SQL มาตรฐานล่าสุดประกอบด้วย "Persistent Stored Modules" (PSMs) กล่าวโดยย่อคือ PSM เป็นเวอร์ชันมาตรฐานของภาษา PL / SQL ใน Oracle (และส่วนขยายขั้นตอนอื่น ๆ ที่คล้ายกันของ DBMS ปัจจุบัน)

ด้วยการรวม PSM เหล่านี้ทำให้ SQL กลายเป็นงานที่สมบูรณ์


13

คำสั่งการเลือก ANSI ตามที่กำหนดไว้เดิมใน SQL-86 ไม่ได้ทำให้เสร็จสมบูรณ์เพราะมันจะยุติ (เสมอยกเว้น CTE ซ้ำและเฉพาะในกรณีที่การดำเนินการสนับสนุนการสอบถามซ้ำลึกโดยพลการ) ดังนั้นจึงเป็นไปไม่ได้ที่จะจำลองเครื่องทัวริงอื่น ๆ ขั้นตอนการจัดเก็บนั้นสมบูรณ์ แต่การโกงนั่นคือ ;-)


1

PLQL ของ Oracle และ TSQL ของ Microsoft ทั้งคู่กำลังทำให้สมบูรณ์ คำแถลงที่เลือกสรรของออราเคิลเองก็กำลังสมบูรณ์เช่นกัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.