Cập nhật yêu cầu sử dụng bí danh bảng


12

Thực hiện yêu cầu này:

update table t1 set t1.column = 0 where t1.column2 = 1234

Nhận lỗi này:

cột "t1" của quan hệ "bảng" không tồn tại

Yêu cầu này chạy tốt trong MySQL.
Tại sao tôi gặp lỗi này trong PostgreSQL?

Câu trả lời:


9

Tôi không chắc đó có phải là cú pháp mong muốn của bạn hay không. Kiểm tra cú pháp của bạn choUPDATE

Hiện tại, đó là

[ WITH [ RECURSIVE ] with_query [, ...] ]
UPDATE [ ONLY ] table_name [ * ] [ [ AS ] alias ]
    SET { column_name = { expression | DEFAULT } |
          ( column_name [, ...] ) = ( { expression | DEFAULT } [, ...] ) |
          ( column_name [, ...] ) = ( sub-SELECT )
        } [, ...]
    [ FROM from_list ]
    [ WHERE condition | WHERE CURRENT OF cursor_name ]
    [ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ]

Vì vậy, nếu bạn cung cấp table t1, nó sẽ được phân tích cú pháp dưới dạng bảng table. Trên thực tế, để làm điều đó bạn cần phải có nó trong trích dẫn "table" t1mà bạn đang làm hoặc thư viện của bạn đang làm.

  • Như một lưu ý thiết kế, đừng làm điều đó. Trong thực tế, không đặt tên bất kỳ từ khóa SQL nào .
  • Nhưng, nếu bạn muốn vui vẻ và xem những gì đang xảy ra, chúng ta có thể chơi ..

Hãy tạo một số dữ liệu văn bản,

CREATE TABLE "table" AS
SELECT x AS column, x AS column2
FROM generate_series(1,12345) AS t(x);

Bây giờ chúng tôi có thể thử truy vấn ban đầu của bạn và nhận kết quả ban đầu của bạn,

UPDATE "table" t1 SET t1.column=0 WHERE t1.column2=1234;
ERROR:  column "t1" of relation "table" does not exist
LINE 1: UPDATE "table" t1 SET t1.column=0 WHERE t1.column2=1234;

Và đó là vấn đề bạn đang gặp phải. Cũng như bảng, nếu bạn định sử dụng từ khóa SQL, bạn cần trích dẫn nó. Thật thú vị, điều đó không đủ ở đây.

UPDATE "table" t1 SET t1."column"=0 WHERE t1.column2=1234;
ERROR:  column "t1" of relation "table" does not exist
LINE 1: UPDATE "table" t1 SET t1."column"=0 WHERE t1.column2=1234;

Ngoài ra, dường như việc khử răng cưa bảng không được hỗ trợ trong danh sách SET , bất kể cột có được từ khóa dành riêng hay không.

UPDATE "table" t1 SET "column"=0 WHERE t1.column2=1234;

Tại sao nó hiện đang hoạt động như thiết kế

Tại sao bạn không thể sử dụng bí danh, xocolatl từ IRC giúp với điều đó,

<xocolatl> EvanCarroll: lý do bạn không thể sử dụng bí danh ở bên trái của = là vì các loại hỗn hợp

<xocolatl> EvanCarroll: vì vậy, đây không phải là lỗi mà là WAD

Vì vậy, trong mã cho CREATEmột bảng với một kiểu hỗn hợp tùy chỉnh, thực hiện một UPDATEtrên nó.

CREATE TYPE foo AS ( x int, y int );

CREATE TABLE foobar AS
  SELECT v::foo AS mycol
  FROM ( VALUES (1,2), (2,100) ) AS v;

UPDATE foobar SET mycol.x = 9;

Vì vậy, cú pháp cho phép .mycol.type-address, không tablealias.col-name.

Giải bài toán cú pháp mơ hồ

Nếu điều đó không có ý nghĩa, bất kỳ hành vi nào nhưng hành vi này sẽ cung cấp cho bạn một cú pháp mơ hồ,

CREATE TYPE foo AS ( mycol int, x int );

CREATE TABLE mytable AS
  SELECT v::foo AS mycol, 1 AS x
  FROM ( VALUES (1,2), (2,100) ) AS v;

UPDATE mytable AS mycol SET mycol.x = 9;

Điều gì mycol.xđề cập đến ở đó? Vì nó không mơ hồ, tham chiếu bảng và khử răng cưa bảng bị vô hiệu hóa, do đó, nó chắc chắn 100% thời gian của một loại hỗn hợp có tên mycol, trên bảng mytable.


Cảm ơn câu trả lời chi tiết, yêu cầu tôi đã đưa ra chỉ là một ví dụ. tôi đang làm việc tự động (như khi viết một công cụ thực hiện chuyển đổi cho tôi) chuyển đổi các yêu cầu phổ biến cũ, một số trong đó trông giống như ví dụ của tôi. điều này là, truy vấn này là hợp lệ trong MySQL, vậy tại sao không có trong PostgreSQL? Có phải là một lỗi trong trình phân tích cú pháp?
chỉ ra

1
@justesting: Nếu bạn thực sự xem xét kỹ cú pháp ... bạn nên có column_name = expression. Đó là, bạn không có tên bảng cùng với tên cột. Vì vậy, điều này không có gì để làm với một cột được gọi "column"hoặc một bảng được gọi "table". Bạn có thể sử dụng các từ không dành riêng và PostgreSQL vẫn sẽ khiếu nại. Hãy thử: CREATE TABLE normal_table_name AS SELECT x AS c1, x AS c2 FROM generate_series(1, 1000) AS s(x); UPDATE normal_table_name t SET t.c1 = 2 WHERE t.c2 = 123;và bạn sẽ nhận được ERROR: column "t" of relation "normal_table_name" does not exist.
joanolo

Điều này thật đáng buồn -.- bởi vì tôi sẽ cần phải viết thêm một số mã sẽ phân tích các bí danh đó trong trường hợp đó là một yêu cầu cập nhật ... Cảm ơn bạn đã làm cho cuộc sống của tôi khó khăn hơn! Có lẽ tôi sẽ bỏ PostgreSQL và chuyển sang MySQL.
chỉ ra

2
@ xin vui lòng. MySQL có nhiều điều kỳ lạ hơn trong cách mà nó đã tạo ra SQL.
ypercubeᵀᴹ

@justesting được cập nhật ^
Evan Carroll

7

Đó là một sự kỳ lạ của Postgres. Như đã nêu trong tài liệu cho UPDATE, tên bảng không nên được sử dụng cho các cột mục tiêu.

column_name

Tên của một cột trong bảng được đặt tên theo table_name. Tên cột có thể đủ điều kiện với một tên trường con hoặc chỉ mục mảng, nếu cần. Không bao gồm tên của bảng trong đặc tả của cột mục tiêu - ví dụ: UPDATE table_name SET table_name.col = 1không hợp lệ.

Chỉ có một bảng có thể được cập nhật trong một UPDATEmệnh đề, vì vậy không có chỗ cho việc giải thích sai về tuyên bố.


Điều đó đúng, nhưng tôi đang nói về các yêu cầu cũ như sau: bảng cập nhật t1 đặt t1.column = (chọn t2.column2 từ bảng2 t2 trong đó t2.column3 = t1.column3). tôi đau đớn và RẤT NHIỀU nó!
chỉ ra

1
Vâng, tôi hiểu rằng khi bạn đang cố gắng chuyển đổi các truy vấn từ các DBMS khác. Nếu bạn đang thực hiện di chuyển MySQL -> Postgres, bạn cũng sẽ gặp nhiều rắc rối hơn với các CẬP NHẬT khác. Cú pháp của MySQL khác với tiêu chuẩn khi CẬP NHẬT đã tham gia giữa bảng được cập nhật và các bảng khác. Nó (mysql) cũng cho phép CẬP NHẬT cập nhật nhiều hơn 1 bảng. Điều này không được phép trong bất kỳ DBMS nào khác. Postgres có thể sử dụng các CTE sửa đổi để cập nhật nhiều bảng trong 1 câu lệnh nhưng cú pháp khác với MySQL.
ypercubeᵀᴹ

1
MySQL cũng cho phép UPDATE .... ORDER BY some_column;đó là cú pháp không chuẩn. (những người bạn sẽ không gặp khó khăn khi chuyển đổi sang Postgres, bạn sẽ chỉ cần xóa ĐẶT HÀNG B) NG). Nó cũng xử lý hàng CẬP NHẬT theo từng hàng (kiểm tra các ràng buộc UNIITE theo từng hàng) và không ở cuối các câu lệnh, như tất cả các DBMS khác làm.
ypercubeᵀᴹ

1
Chỉ cần không phải lo lắng, tôi là người dùng Top 2 tại thẻ mysql tại trang web. Không có gì sai khi chỉ ra sự khác biệt giữa 2 sản phẩm. Các CTE có thể sửa đổi Postgres cũng là một phần mở rộng không chuẩn.
ypercubeᵀᴹ

1
@justesting Tôi quay lại chỉnh sửa trước đó và chỉnh sửa lại (chủ yếu là định dạng). Bạn cũng có thể tự chỉnh sửa và sửa bất cứ điều gì bạn nghĩ có thể cải thiện câu hỏi.
ypercubeᵀᴹ
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.